1 /* $NetBSD: fault.c,v 1.29 2026/05/21 10:07:02 skrll Exp $ */ 2 3 /* 4 * Copyright (c) 2017 Ryo Shimizu 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 20 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 24 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 25 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 #include <sys/cdefs.h> 30 __KERNEL_RCSID(0, "$NetBSD: fault.c,v 1.29 2026/05/21 10:07:02 skrll Exp $"); 31 32 #include "opt_compat_netbsd32.h" 33 #include "opt_cpuoptions.h" 34 #include "opt_ddb.h" 35 #include "opt_uvmhist.h" 36 37 #include <sys/param.h> 38 #include <sys/kauth.h> 39 #include <sys/proc.h> 40 #include <sys/siginfo.h> 41 42 #include <uvm/uvm.h> 43 44 #include <aarch64/frame.h> 45 #include <aarch64/machdep.h> 46 #include <aarch64/armreg.h> 47 #include <aarch64/db_machdep.h> 48 #if defined(PMAP_DEBUG) 49 #include <aarch64/pmap.h> 50 #endif 51 52 #include <arm/cpufunc.h> 53 54 UVMHIST_DECL(pmaphist); 55 56 const char * const fault_status_code[] = { 57 [ESR_ISS_FSC_ADDRESS_SIZE_FAULT_0] = "Address Size Fault L0", 58 [ESR_ISS_FSC_ADDRESS_SIZE_FAULT_1] = "Address Size Fault L1", 59 [ESR_ISS_FSC_ADDRESS_SIZE_FAULT_2] = "Address Size Fault L2", 60 [ESR_ISS_FSC_ADDRESS_SIZE_FAULT_3] = "Address Size Fault L3", 61 [ESR_ISS_FSC_TRANSLATION_FAULT_0] = "Translation Fault L0", 62 [ESR_ISS_FSC_TRANSLATION_FAULT_1] = "Translation Fault L1", 63 [ESR_ISS_FSC_TRANSLATION_FAULT_2] = "Translation Fault L2", 64 [ESR_ISS_FSC_TRANSLATION_FAULT_3] = "Translation Fault L3", 65 [ESR_ISS_FSC_ACCESS_FAULT_0] = "Access Flag Fault L0", 66 [ESR_ISS_FSC_ACCESS_FAULT_1] = "Access Flag Fault L1", 67 [ESR_ISS_FSC_ACCESS_FAULT_2] = "Access Flag Fault L2", 68 [ESR_ISS_FSC_ACCESS_FAULT_3] = "Access Flag Fault L3", 69 [ESR_ISS_FSC_PERM_FAULT_0] = "Permission Fault L0", 70 [ESR_ISS_FSC_PERM_FAULT_1] = "Permission Fault L1", 71 [ESR_ISS_FSC_PERM_FAULT_2] = "Permission Fault L2", 72 [ESR_ISS_FSC_PERM_FAULT_3] = "Permission Fault L3", 73 [ESR_ISS_FSC_SYNC_EXTERNAL_ABORT] = 74 "Synchronous External Abort", 75 [ESR_ISS_FSC_SYNC_EXTERNAL_ABORT_TTWALK_0] = 76 "Synchronous External Abort on translation table walk L0", 77 [ESR_ISS_FSC_SYNC_EXTERNAL_ABORT_TTWALK_1] = 78 "Synchronous External Abort on translation table walk L1", 79 [ESR_ISS_FSC_SYNC_EXTERNAL_ABORT_TTWALK_2] = 80 "Synchronous External Abort on translation table walk L2", 81 [ESR_ISS_FSC_SYNC_EXTERNAL_ABORT_TTWALK_3] = 82 "Synchronous External Abort on translation table walk L3", 83 [ESR_ISS_FSC_SYNC_PARITY_ERROR] = 84 "Synchronous Parity error", 85 [ESR_ISS_FSC_SYNC_PARITY_ERROR_ON_TTWALK_0] = 86 "Synchronous Parity error on translation table walk L0", 87 [ESR_ISS_FSC_SYNC_PARITY_ERROR_ON_TTWALK_1] = 88 "Synchronous Parity error on translation table walk L1", 89 [ESR_ISS_FSC_SYNC_PARITY_ERROR_ON_TTWALK_2] = 90 "Synchronous Parity error on translation table walk L2", 91 [ESR_ISS_FSC_SYNC_PARITY_ERROR_ON_TTWALK_3] = 92 "Synchronous Parity error on translation table walk L3", 93 [ESR_ISS_FSC_ALIGNMENT_FAULT] = "Alignment Fault", 94 [ESR_ISS_FSC_TLB_CONFLICT_FAULT] = "TLB Conflict Fault", 95 [ESR_ISS_FSC_LOCKDOWN_ABORT] = "Lockdown Abort", 96 [ESR_ISS_FSC_UNSUPPORTED_EXCLUSIVE] = "Unsupported exclusive", 97 [ESR_ISS_FSC_FIRST_LEVEL_DOMAIN_FAULT] = 98 "First Level Domain Fault", 99 [ESR_ISS_FSC_SECOND_LEVEL_DOMAIN_FAULT] = 100 "Second Level Domain Fault" 101 }; 102 103 static bool 104 is_fatal_abort(uint32_t esr) 105 { 106 uint32_t fsc; 107 108 fsc = __SHIFTOUT(esr, ESR_ISS_DATAABORT_DFSC); 109 110 switch (fsc) { 111 case ESR_ISS_FSC_TRANSLATION_FAULT_0: 112 case ESR_ISS_FSC_TRANSLATION_FAULT_1: 113 case ESR_ISS_FSC_TRANSLATION_FAULT_2: 114 case ESR_ISS_FSC_TRANSLATION_FAULT_3: 115 case ESR_ISS_FSC_ACCESS_FAULT_0: 116 case ESR_ISS_FSC_ACCESS_FAULT_1: 117 case ESR_ISS_FSC_ACCESS_FAULT_2: 118 case ESR_ISS_FSC_ACCESS_FAULT_3: 119 case ESR_ISS_FSC_PERM_FAULT_0: 120 case ESR_ISS_FSC_PERM_FAULT_1: 121 case ESR_ISS_FSC_PERM_FAULT_2: 122 case ESR_ISS_FSC_PERM_FAULT_3: 123 return false; 124 } 125 return true; 126 } 127 128 /* SPSR_M is SPSR_M_EL0T or SPSR_M_USR32 ? */ 129 #define IS_SPSR_USER(spsr) \ 130 (((spsr) & (SPSR_M & ~SPSR_A32)) == 0) 131 132 void 133 data_abort_handler(struct trapframe *tf, uint32_t eclass) 134 { 135 struct proc *p; 136 struct lwp *l; 137 struct vm_map *map; 138 struct faultbuf *fb; 139 vaddr_t va; 140 uint32_t esr, fsc, rw; 141 vm_prot_t ftype; 142 int error = EFAULT, len; 143 const bool user = IS_SPSR_USER(tf->tf_spsr) ? true : false; 144 bool is_pan_trap = false; 145 146 bool fatalabort; 147 const char *faultstr; 148 static char panicinfo[256]; 149 150 UVMHIST_FUNC(__func__); 151 UVMHIST_CALLED(pmaphist); 152 153 __asm __volatile ("clrex"); 154 155 l = curlwp; 156 157 esr = tf->tf_esr; 158 rw = __SHIFTOUT(esr, ESR_ISS_DATAABORT_WnR); /* 0 if IFSC */ 159 160 fatalabort = is_fatal_abort(esr); 161 if (fatalabort) 162 goto do_fault; 163 164 p = l->l_proc; 165 va = trunc_page((vaddr_t)tf->tf_far); 166 167 /* eliminate address tag if ECR_EL1.TBI[01] is enabled */ 168 va = aarch64_untag_address(va); 169 170 if (VM_MIN_KERNEL_ADDRESS <= va && va < VM_MAX_KERNEL_ADDRESS) { 171 map = kernel_map; 172 UVMHIST_LOG(pmaphist, "use kernel_map %p", map, 0, 0, 0); 173 } else if (VM_MIN_ADDRESS <= va && va <= VM_MAX_ADDRESS) { 174 map = &p->p_vmspace->vm_map; 175 UVMHIST_LOG(pmaphist, "use user vm_map %p (kernel_map=%p)", 176 map, kernel_map, 0, 0); 177 } else 178 goto do_fault; 179 180 if (eclass == ESR_EC_INSN_ABT_EL0 || eclass == ESR_EC_INSN_ABT_EL1) 181 ftype = VM_PROT_EXECUTE; 182 else if (__SHIFTOUT(esr, ESR_ISS_DATAABORT_CM)) 183 ftype = VM_PROT_READ; 184 else 185 ftype = (rw == 0) ? VM_PROT_READ : VM_PROT_WRITE; 186 187 if (ftype & VM_PROT_EXECUTE) { 188 UVMHIST_LOG(pmaphist, "pagefault %016jx %016jx user=%jd EXEC", 189 tf->tf_far, va, user, 0); 190 } else { 191 UVMHIST_LOG(pmaphist, "pagefault %016lx %016lx user=%jd " 192 "write=%jd", tf->tf_far, va, user, rw); 193 } 194 195 if (__predict_false(!user && map != kernel_map && 196 (tf->tf_spsr & SPSR_PAN))) { 197 /* 198 * We were in kernel mode, faulted on a user address, 199 * and had PAN enabled. This is a fatal fault. 200 */ 201 is_pan_trap = true; 202 goto handle_fault; 203 } 204 205 /* reference/modified emulation */ 206 #ifdef ARMV81_HAFDBS 207 if (aarch64_hafdbs_enabled == ID_AA64MMFR1_EL1_HAFDBS_NONE || 208 (aarch64_hafdbs_enabled == ID_AA64MMFR1_EL1_HAFDBS_A && 209 ftype == VM_PROT_WRITE)) 210 #endif 211 { 212 if (pmap_fault_fixup(map->pmap, va, ftype, user)) { 213 UVMHIST_LOG(pmaphist, "fixed: va=%016llx", tf->tf_far, 0, 0, 0); 214 return; 215 } 216 } 217 218 fb = cpu_disable_onfault(); 219 error = uvm_fault(map, va, ftype); 220 cpu_enable_onfault(fb); 221 if (__predict_true(error == 0)) { 222 if (user) 223 uvm_grow(p, va); 224 225 UVMHIST_LOG(pmaphist, "uvm_fault success: far=%016lx, va=%016llx", 226 tf->tf_far, va, 0, 0); 227 return; 228 } 229 230 do_fault: 231 /* faultbail path? */ 232 kpreempt_disable(); 233 const bool intrdepthzero = (curcpu()->ci_intr_depth == 0); 234 kpreempt_enable(); 235 if (intrdepthzero) { 236 fb = cpu_disable_onfault(); 237 if (fb != NULL) { 238 cpu_jump_onfault(tf, fb, error); 239 return; 240 } 241 } 242 243 handle_fault: 244 fsc = __SHIFTOUT(esr, ESR_ISS_DATAABORT_DFSC); /* also IFSC */ 245 if (user) { 246 if (!fatalabort) { 247 switch (error) { 248 case ENOMEM: 249 printf("UVM: pid %d (%s), uid %d killed: " 250 "out of swap\n", 251 l->l_proc->p_pid, l->l_proc->p_comm, 252 l->l_cred ? 253 kauth_cred_geteuid(l->l_cred) : -1); 254 do_trapsignal(l, SIGKILL, 0, 255 (void *)tf->tf_far, esr); 256 break; 257 case EACCES: 258 do_trapsignal(l, SIGSEGV, SEGV_ACCERR, 259 (void *)tf->tf_far, esr); 260 break; 261 case EINVAL: 262 do_trapsignal(l, SIGBUS, BUS_ADRERR, 263 (void *)tf->tf_far, esr); 264 break; 265 default: 266 do_trapsignal(l, SIGSEGV, SEGV_MAPERR, 267 (void *)tf->tf_far, esr); 268 break; 269 } 270 } else { 271 /* 272 * fatal abort in usermode 273 */ 274 switch (fsc) { 275 case ESR_ISS_FSC_TLB_CONFLICT_FAULT: 276 case ESR_ISS_FSC_LOCKDOWN_ABORT: 277 case ESR_ISS_FSC_UNSUPPORTED_EXCLUSIVE: 278 case ESR_ISS_FSC_FIRST_LEVEL_DOMAIN_FAULT: 279 case ESR_ISS_FSC_SECOND_LEVEL_DOMAIN_FAULT: 280 default: 281 do_trapsignal(l, SIGSEGV, SEGV_MAPERR, 282 (void *)tf->tf_far, esr); 283 break; 284 case ESR_ISS_FSC_ADDRESS_SIZE_FAULT_0: 285 case ESR_ISS_FSC_ADDRESS_SIZE_FAULT_1: 286 case ESR_ISS_FSC_ADDRESS_SIZE_FAULT_2: 287 case ESR_ISS_FSC_ADDRESS_SIZE_FAULT_3: 288 do_trapsignal(l, SIGBUS, BUS_ADRERR, 289 (void *)tf->tf_far, esr); 290 break; 291 case ESR_ISS_FSC_SYNC_EXTERNAL_ABORT: 292 case ESR_ISS_FSC_SYNC_EXTERNAL_ABORT_TTWALK_0: 293 case ESR_ISS_FSC_SYNC_EXTERNAL_ABORT_TTWALK_1: 294 case ESR_ISS_FSC_SYNC_EXTERNAL_ABORT_TTWALK_2: 295 case ESR_ISS_FSC_SYNC_EXTERNAL_ABORT_TTWALK_3: 296 case ESR_ISS_FSC_SYNC_PARITY_ERROR: 297 case ESR_ISS_FSC_SYNC_PARITY_ERROR_ON_TTWALK_0: 298 case ESR_ISS_FSC_SYNC_PARITY_ERROR_ON_TTWALK_1: 299 case ESR_ISS_FSC_SYNC_PARITY_ERROR_ON_TTWALK_2: 300 case ESR_ISS_FSC_SYNC_PARITY_ERROR_ON_TTWALK_3: 301 do_trapsignal(l, SIGBUS, BUS_OBJERR, 302 (void *)tf->tf_far, esr); 303 break; 304 case ESR_ISS_FSC_ALIGNMENT_FAULT: 305 do_trapsignal(l, SIGBUS, BUS_ADRALN, 306 (void *)tf->tf_far, esr); 307 break; 308 } 309 } 310 311 #undef DEBUG_DUMP_ON_USERFAULT /* DEBUG */ 312 #undef DEBUG_DDB_ON_USERFAULT /* DEBUG */ 313 314 #if defined(DEBUG_DUMP_ON_USERFAULT) || \ 315 (defined(DDB) && defined(DEBUG_DDB_ON_USERFAULT)) 316 __nothing; 317 #else 318 return; 319 #endif 320 } 321 322 /* 323 * fatal abort. analyze fault status code to show by panic() 324 */ 325 len = snprintf(panicinfo, sizeof(panicinfo), "Trap: %s:", 326 eclass_trapname(eclass)); 327 328 if (fsc >= __arraycount(fault_status_code) || 329 (faultstr = fault_status_code[fsc]) == NULL) 330 len += snprintf(panicinfo + len, sizeof(panicinfo) - len, 331 " unknown fault status 0x%x ", fsc); 332 else 333 len += snprintf(panicinfo + len, sizeof(panicinfo) - len, 334 " %s", faultstr); 335 336 if (__SHIFTOUT(esr, ESR_EC) == ESR_EC_DATA_ABT_EL1 || 337 __SHIFTOUT(esr, ESR_EC) == ESR_EC_DATA_ABT_EL0) 338 len += snprintf(panicinfo + len, sizeof(panicinfo) - len, 339 " with %s access", (rw == 0) ? "read" : "write"); 340 341 len += snprintf(panicinfo + len, sizeof(panicinfo) - len, 342 " for %016"PRIxREGISTER, tf->tf_far); 343 344 if (__SHIFTOUT(esr, ESR_ISS_DATAABORT_EA) != 0) 345 len += snprintf(panicinfo + len, sizeof(panicinfo) - len, 346 ", External abort"); 347 348 if (__SHIFTOUT(esr, ESR_ISS_DATAABORT_S1PTW) != 0) 349 len += snprintf(panicinfo + len, sizeof(panicinfo) - len, 350 ", State 2 Fault"); 351 352 if (is_pan_trap) 353 len += snprintf(panicinfo + len, sizeof(panicinfo) - len, 354 ", PAN Set"); 355 356 len += snprintf(panicinfo + len, sizeof(panicinfo) - len, 357 ": pc %016"PRIxREGISTER, tf->tf_pc); 358 359 if (tf->tf_pc == tf->tf_far) { /* XXX? */ 360 /* fault address is pc. the causal instruction cannot be read */ 361 len += snprintf(panicinfo + len, sizeof(panicinfo) - len, 362 ": opcode unknown"); 363 } 364 #ifdef DDB 365 else { 366 /* ...and disassemble the instruction */ 367 len += snprintf(panicinfo + len, sizeof(panicinfo) - len, 368 ": %s", strdisasm(tf->tf_pc, tf->tf_spsr)); 369 } 370 #endif 371 372 if (user) { 373 #if defined(DEBUG_DDB_ON_USERFAULT) && defined(DDB) 374 printf("%s\n", panicinfo); 375 Debugger(); 376 #elif defined(DEBUG_DUMP_ON_USERFAULT) 377 printf("%s\n", panicinfo); 378 dump_trapframe(tf, printf); 379 #endif 380 } 381 382 if (!user) 383 panic("%s\n", panicinfo); 384 } 385