1 /* 2 * Copyright (c) 2019 Apple Inc. All rights reserved. 3 * 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. The rights granted to you under the License 10 * may not be used to create, or enable the creation or redistribution of, 11 * unlawful or unlicensed copies of an Apple operating system, or to 12 * circumvent, violate, or enable the circumvention or violation of, any 13 * terms of an Apple operating system software license agreement. 14 * 15 * Please obtain a copy of the License at 16 * http://www.opensource.apple.com/apsl/ and read it before using this file. 17 * 18 * The Original Code and all software distributed under the License are 19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 23 * Please see the License for the specific language governing rights and 24 * limitations under the License. 25 * 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ 27 */ 28 29 #ifndef _ARM64_PAC_ASM_H_ 30 #define _ARM64_PAC_ASM_H_ 31 32 #ifndef __ASSEMBLER__ 33 #error "This header should only be used in .s files" 34 #endif 35 36 #include <pexpert/arm64/board_config.h> 37 #include <arm64/proc_reg.h> 38 #if HAS_PARAVIRTUALIZED_PAC 39 #include "smccc_asm.h" 40 #endif 41 #include "assym.s" 42 43 #if defined(HAS_APPLE_PAC) 44 45 46 /* BEGIN IGNORE CODESTYLE */ 47 48 /** 49 * REPROGRAM_JOP_KEYS 50 * 51 * Loads a userspace process's JOP key (task->jop_pid) into the CPU, and 52 * updates current_cpu_datap()->jop_key accordingly. This reprogramming process 53 * is skipped whenever the "new" JOP key has already been loaded into the CPU. 54 * 55 * skip_label - branch to this label if new_jop_key is already loaded into CPU 56 * new_jop_key - process's jop_pid 57 * cpudatap - current cpu_data_t * 58 * tmp - scratch register 59 */ 60 .macro REPROGRAM_JOP_KEYS skip_label, new_jop_key, cpudatap, tmp 61 ldr \tmp, [\cpudatap, CPU_JOP_KEY] 62 cmp \new_jop_key, \tmp 63 b.eq \skip_label 64 SET_JOP_KEY_REGISTERS \new_jop_key, \tmp 65 str \new_jop_key, [\cpudatap, CPU_JOP_KEY] 66 .endmacro 67 68 /** 69 * REPROGRAM_ROP_KEYS 70 * 71 * Loads a userspace process's ROP key (task->rop_pid) into the CPU, and 72 * updates current_cpu_datap()->rop_key accordingly. This reprogramming process 73 * is skipped whenever the "new" ROP key has already been loaded into the CPU. 74 * 75 * skip_label - branch to this label if new_rop_key is already loaded into CPU 76 * new_rop_key - process's rop_pid 77 * cpudatap - current cpu_data_t * 78 * tmp - scratch register 79 */ 80 .macro REPROGRAM_ROP_KEYS skip_label, new_rop_key, cpudatap, tmp 81 ldr \tmp, [\cpudatap, CPU_ROP_KEY] 82 cmp \new_rop_key, \tmp 83 b.eq \skip_label 84 SET_ROP_KEY_REGISTERS \new_rop_key, \tmp 85 str \new_rop_key, [\cpudatap, CPU_ROP_KEY] 86 .endmacro 87 88 /** 89 * SET_JOP_KEY_REGISTERS 90 * 91 * Unconditionally loads a userspace process's JOP key (task->jop_pid) into the 92 * CPU. The caller is responsible for updating current_cpu_datap()->jop_key as 93 * needed. 94 * 95 * new_jop_key - process's jop_pid 96 * tmp - scratch register 97 */ 98 .macro SET_JOP_KEY_REGISTERS new_jop_key, tmp 99 #if HAS_PARAVIRTUALIZED_PAC 100 SAVE_SMCCC_CLOBBERED_REGISTERS 101 /* 102 * We're deliberately calling PAC_SET_EL0_DIVERSIFIER here, even though the 103 * EL0 diversifier affects both A (JOP) and B (ROP) keys. We don't want 104 * SET_JOP_KEY_REGISTERS to have an impact on the EL1 A key state, since 105 * these are the keys the kernel uses to sign pointers on the heap. 106 * 107 * Using new_jop_key as the EL0 diversifer has the same net effect of giving 108 * userspace its own set of JOP keys, but doesn't affect EL1 A key state. 109 */ 110 MOV64 x0, VMAPPLE_PAC_SET_EL0_DIVERSIFIER 111 mov x1, \new_jop_key 112 hvc #0 113 LOAD_SMCCC_CLOBBERED_REGISTERS 114 #endif /* HAS_PARAVIRTUALIZED_PAC */ 115 .endmacro 116 117 /** 118 * SET_ROP_KEY_REGISTERS 119 * 120 * Unconditionally loads a userspace process's ROP key (task->rop_pid) into the 121 * CPU. The caller is responsible for updating current_cpu_datap()->rop_key as 122 * needed. 123 * 124 * new_rop_key - process's rop_pid 125 * tmp - scratch register 126 */ 127 .macro SET_ROP_KEY_REGISTERS new_rop_key, tmp 128 #if HAS_PARAVIRTUALIZED_PAC 129 SAVE_SMCCC_CLOBBERED_REGISTERS 130 MOV64 x0, VMAPPLE_PAC_SET_B_KEYS 131 mov x1, \new_rop_key 132 hvc #0 133 LOAD_SMCCC_CLOBBERED_REGISTERS 134 #endif /* HAS_PARAVIRTUALIZED_PAC */ 135 .endmacro 136 137 /** 138 * PAC_INIT_KEY_STATE 139 * 140 * Sets the initial PAC key state, but does not enable the keys. 141 * 142 * tmp - scratch register 143 * tmp2 - scratch register 144 */ 145 .macro PAC_INIT_KEY_STATE tmp, tmp2 146 #if HAS_PARAVIRTUALIZED_PAC 147 #if HIBERNATION 148 #error PAC_INIT_KEY_STATE is not implemented for HAS_PARAVIRTUALIZED_PAC && HIBERNATION 149 #endif 150 /* 151 * This call clobbers x0-x3. However we only initialize PAC at a point in 152 * common_start where x0-x3 are safe to clobber, and where we don't yet have 153 * a working stack to stash the existing values anyway. 154 */ 155 mov x0, #VMAPPLE_PAC_SET_INITIAL_STATE 156 hvc #0 157 #endif /* HAS_PARAVIRTUALIZED_PAC */ 158 .endmacro 159 160 /* END IGNORE CODESTYLE */ 161 162 #endif /* defined(HAS_APPLE_PAC) */ 163 164 #endif /* _ARM64_PAC_ASM_H_ */ 165 166 /* vim: set ts=4 ft=asm: */ 167