1 /*- 2 * Copyright (c) 2014 Andrew Turner 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26 27 #ifdef __arm__ 28 #include <arm/asm.h> 29 #else /* !__arm__ */ 30 31 #ifndef _MACHINE_ASM_H_ 32 #define _MACHINE_ASM_H_ 33 34 #undef __FBSDID 35 #if !defined(lint) && !defined(STRIP_FBSDID) 36 #define __FBSDID(s) .ident s 37 #else 38 #define __FBSDID(s) /* nothing */ 39 #endif 40 41 #define _C_LABEL(x) x 42 43 #ifdef KDTRACE_HOOKS 44 #define DTRACE_NOP nop 45 #else 46 #define DTRACE_NOP 47 #endif 48 49 #define LENTRY(sym) \ 50 .text; .align 2; .type sym,#function; sym: \ 51 .cfi_startproc; BTI_C; DTRACE_NOP 52 #define ENTRY(sym) \ 53 .globl sym; LENTRY(sym) 54 #define EENTRY(sym) \ 55 .globl sym; .text; .align 2; .type sym,#function; sym: 56 #define LEND(sym) .ltorg; .cfi_endproc; .size sym, . - sym 57 #define END(sym) LEND(sym) 58 #define EEND(sym) 59 60 #define WEAK_REFERENCE(sym, alias) \ 61 .weak alias; \ 62 .set alias,sym 63 64 #define UINT64_C(x) (x) 65 66 #if defined(PIC) 67 #define PIC_SYM(x,y) x ## @ ## y 68 #else 69 #define PIC_SYM(x,y) x 70 #endif 71 72 /* Alias for link register x30 */ 73 #define lr x30 74 75 /* 76 * Check whether a given cpu feature is present, in the case it is not we jump 77 * to the given label. The tmp register should be a register able to hold the 78 * temporary data. 79 */ 80 #define CHECK_CPU_FEAT(tmp, feat_reg, feat, label) \ 81 mrs tmp, ##feat_reg##_el1; \ 82 ubfx tmp, tmp, ##feat_reg##_##feat##_SHIFT, ##feat_reg##_##feat##_WIDTH; \ 83 cbz tmp, label 84 85 /* 86 * Sets the trap fault handler. The exception handler will return to the 87 * address in the handler register on a data abort or the xzr register to 88 * clear the handler. The tmp parameter should be a register able to hold 89 * the temporary data. 90 */ 91 #define SET_FAULT_HANDLER(handler, tmp) \ 92 ldr tmp, [x18, #PC_CURTHREAD]; /* Load curthread */ \ 93 ldr tmp, [tmp, #TD_PCB]; /* Load the pcb */ \ 94 str handler, [tmp, #PCB_ONFAULT] /* Set the handler */ 95 96 #define ENTER_USER_ACCESS(reg, tmp) \ 97 ldr tmp, =has_pan; /* Get the addr of has_pan */ \ 98 ldr reg, [tmp]; /* Read it */ \ 99 cbz reg, 997f; /* If no PAN skip */ \ 100 .arch_extension pan; \ 101 msr pan, #0; /* Disable PAN checks */ \ 102 .arch_extension nopan; \ 103 997: 104 105 #define EXIT_USER_ACCESS(reg) \ 106 cbz reg, 998f; /* If no PAN skip */ \ 107 .arch_extension pan; \ 108 msr pan, #1; /* Enable PAN checks */ \ 109 .arch_extension nopan; \ 110 998: 111 112 #define EXIT_USER_ACCESS_CHECK(reg, tmp) \ 113 ldr tmp, =has_pan; /* Get the addr of has_pan */ \ 114 ldr reg, [tmp]; /* Read it */ \ 115 cbz reg, 999f; /* If no PAN skip */ \ 116 .arch_extension pan; \ 117 msr pan, #1; /* Enable PAN checks */ \ 118 .arch_extension nopan; \ 119 999: 120 121 /* 122 * Some AArch64 CPUs speculate past an eret instruction. As the user may 123 * control the registers at this point add a speculation barrier usable on 124 * all AArch64 CPUs after the eret instruction. 125 * TODO: ARMv8.5 adds a specific instruction for this, we could use that 126 * if we know we are running on something that supports it. 127 */ 128 #define ERET \ 129 eret; \ 130 dsb sy; \ 131 isb 132 133 /* 134 * When a CPU that implements FEAT_BTI uses a BR/BLR instruction (or the 135 * pointer authentication variants, e.g. BLRAA) and the target location 136 * has the GP attribute in its page table, then the target of the BR/BLR 137 * needs to be a valid BTI landing pad. 138 * 139 * BTI_C should be used at the start of a function and is used in the 140 * ENTRY macro. It can be replaced by PACIASP or PACIBSP, however these 141 * also need an appropriate authenticate instruction before returning. 142 * 143 * BTI_J should be used as the target instruction when branching with a 144 * BR instruction within a function. 145 * 146 * When using a BR to branch to a new function, e.g. a tail call, then 147 * the target register should be x16 or x17 so it is compatible with 148 * the BRI_C instruction. 149 * 150 * As these instructions are in the hint space they are a NOP when 151 * the CPU doesn't implement FEAT_BTI so are safe to use. 152 */ 153 #ifdef __ARM_FEATURE_BTI_DEFAULT 154 #define BTI_C hint #34 155 #define BTI_J hint #36 156 #else 157 #define BTI_C 158 #define BTI_J 159 #endif 160 161 /* 162 * To help protect against ROP attacks we can use Pointer Authentication 163 * to sign the return address before pushing it to the stack. 164 * 165 * PAC_LR_SIGN can be used at the start of a function to sign the link 166 * register with the stack pointer as the modifier. As this is in the hint 167 * space it is safe to use on CPUs that don't implement pointer 168 * authentication. It can be used in place of the BTI_C instruction above as 169 * a valid BTI landing pad instruction. 170 * 171 * PAC_LR_AUTH is used to authenticate the link register using the stack 172 * pointer as the modifier. It should be used in any function that uses 173 * PAC_LR_SIGN. The stack pointer must be identical in each case. 174 */ 175 #ifdef __ARM_FEATURE_PAC_DEFAULT 176 #define PAC_LR_SIGN hint #25 /* paciasp */ 177 #define PAC_LR_AUTH hint #29 /* autiasp */ 178 #else 179 #define PAC_LR_SIGN 180 #define PAC_LR_AUTH 181 #endif 182 183 /* 184 * GNU_PROPERTY_AARCH64_FEATURE_1_NOTE can be used to insert a note that 185 * the current assembly file is built with Pointer Authentication (PAC) or 186 * Branch Target Identification support (BTI). As the linker requires all 187 * object files in an executable or library to have the GNU property 188 * note to emit it in the created elf file we need to add a note to all 189 * assembly files that support BTI so the kernel and dynamic linker can 190 * mark memory used by the file as guarded. 191 * 192 * The GNU_PROPERTY_AARCH64_FEATURE_1_VAL macro encodes the combination 193 * of PAC and BTI that have been enabled. It can be used as follows: 194 * GNU_PROPERTY_AARCH64_FEATURE_1_NOTE(GNU_PROPERTY_AARCH64_FEATURE_1_VAL); 195 * 196 * To use this you need to include <sys/elf_common.h> for 197 * GNU_PROPERTY_AARCH64_FEATURE_1_* 198 */ 199 #if defined(__ARM_FEATURE_BTI_DEFAULT) 200 #if defined(__ARM_FEATURE_PAC_DEFAULT) 201 /* BTI, PAC */ 202 #define GNU_PROPERTY_AARCH64_FEATURE_1_VAL \ 203 (GNU_PROPERTY_AARCH64_FEATURE_1_BTI | GNU_PROPERTY_AARCH64_FEATURE_1_PAC) 204 #else 205 /* BTI, no PAC */ 206 #define GNU_PROPERTY_AARCH64_FEATURE_1_VAL \ 207 (GNU_PROPERTY_AARCH64_FEATURE_1_BTI) 208 #endif 209 #elif defined(__ARM_FEATURE_PAC_DEFAULT) 210 /* No BTI, PAC */ 211 #define GNU_PROPERTY_AARCH64_FEATURE_1_VAL \ 212 (GNU_PROPERTY_AARCH64_FEATURE_1_PAC) 213 #else 214 /* No BTI, no PAC */ 215 #define GNU_PROPERTY_AARCH64_FEATURE_1_VAL 0 216 #endif 217 218 #if defined(__ARM_FEATURE_BTI_DEFAULT) || defined(__ARM_FEATURE_PAC_DEFAULT) 219 #define GNU_PROPERTY_AARCH64_FEATURE_1_NOTE(x) \ 220 .section .note.gnu.property, "a"; \ 221 .balign 8; \ 222 .4byte 0x4; /* sizeof(vendor) */ \ 223 .4byte 0x10; /* sizeof(note data) */ \ 224 .4byte (NT_GNU_PROPERTY_TYPE_0); \ 225 .asciz "GNU"; /* vendor */ \ 226 /* note data: */ \ 227 .4byte (GNU_PROPERTY_AARCH64_FEATURE_1_AND); \ 228 .4byte 0x4; /* sizeof(property) */ \ 229 .4byte (x); /* property */ \ 230 .4byte 0 231 #else 232 #define GNU_PROPERTY_AARCH64_FEATURE_1_NOTE(x) 233 #endif 234 235 #endif /* _MACHINE_ASM_H_ */ 236 237 #endif /* !__arm__ */ 238