github.com/tinygo-org/tinygo@v0.31.3-0.20240404173401-90b0bf646c27/src/runtime/runtime_cortexm_hardfault_debug.go (about) 1 //go:build cortexm && !atsamd21 && !nrf51 2 3 package runtime 4 5 import ( 6 "device/arm" 7 "unsafe" 8 ) 9 10 const ( 11 SCB_CFSR_KnownFault = arm.SCB_CFSR_IACCVIOL | arm.SCB_CFSR_DACCVIOL | 12 arm.SCB_CFSR_MUNSTKERR | arm.SCB_CFSR_MSTKERR | arm.SCB_CFSR_MLSPERR | 13 arm.SCB_CFSR_IBUSERR | arm.SCB_CFSR_PRECISERR | arm.SCB_CFSR_IMPRECISERR | 14 arm.SCB_CFSR_UNSTKERR | arm.SCB_CFSR_STKERR | arm.SCB_CFSR_LSPERR | 15 arm.SCB_CFSR_UNDEFINSTR | arm.SCB_CFSR_INVSTATE | arm.SCB_CFSR_INVPC | 16 arm.SCB_CFSR_NOCP | arm.SCB_CFSR_UNALIGNED | arm.SCB_CFSR_DIVBYZERO 17 ) 18 19 // See runtime_cortexm_hardfault.go 20 // 21 //go:export handleHardFault 22 func handleHardFault(sp *interruptStack) { 23 fault := GetFaultStatus() 24 spValid := !fault.Bus().ImpreciseDataBusError() 25 26 print("fatal error: ") 27 if spValid && uintptr(unsafe.Pointer(sp)) < 0x20000000 { 28 print("stack overflow? ") 29 } 30 if fault.Mem().InstructionAccessViolation() { 31 print("instruction access violation") 32 } 33 if fault.Mem().DataAccessViolation() { 34 print("data access violation") 35 } 36 if fault.Mem().WhileUnstackingException() { 37 print(" while unstacking exception") 38 } 39 if fault.Mem().WileStackingException() { 40 print(" while stacking exception") 41 } 42 if fault.Mem().DuringFPLazyStatePres() { 43 print(" during floating-point lazy state preservation") 44 } 45 46 if fault.Bus().InstructionBusError() { 47 print("instruction bus error") 48 } 49 if fault.Bus().PreciseDataBusError() { 50 print("data bus error (precise)") 51 } 52 if fault.Bus().ImpreciseDataBusError() { 53 print("data bus error (imprecise)") 54 } 55 if fault.Bus().WhileUnstackingException() { 56 print(" while unstacking exception") 57 } 58 if fault.Bus().WhileStackingException() { 59 print(" while stacking exception") 60 } 61 if fault.Bus().DuringFPLazyStatePres() { 62 print(" during floating-point lazy state preservation") 63 } 64 65 if fault.Usage().UndefinedInstruction() { 66 print("undefined instruction") 67 } 68 if fault.Usage().IllegalUseOfEPSR() { 69 print("illegal use of the EPSR") 70 } 71 if fault.Usage().IllegalExceptionReturn() { 72 print("illegal load of EXC_RETURN to the PC") 73 } 74 if fault.Usage().AttemptedToAccessCoprocessor() { 75 print("coprocessor access violation") 76 } 77 if fault.Usage().UnalignedMemoryAccess() { 78 print("unaligned memory access") 79 } 80 if fault.Usage().DivideByZero() { 81 print("divide by zero") 82 } 83 84 if fault.Unknown() { 85 print("unknown hard fault") 86 } 87 88 if addr, ok := fault.Mem().Address(); ok { 89 print(" with fault address ", addr) 90 } 91 92 if addr, ok := fault.Bus().Address(); ok { 93 print(" with bus fault address ", addr) 94 } 95 if spValid { 96 print(" with sp=", sp) 97 if uintptr(unsafe.Pointer(&sp.PC)) >= 0x20000000 { 98 // Only print the PC if it points into memory. 99 // It may not point into memory during a stack overflow, so check that 100 // first before accessing the stack. 101 print(" pc=", sp.PC) 102 } 103 } 104 println() 105 abort() 106 } 107 108 // Descriptions are sourced from the K66 SVD and 109 // http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0552a/Cihcfefj.html 110 111 // GetFaultStatus reads the System Control Block Configurable Fault Status 112 // Register and returns it as a FaultStatus. 113 func GetFaultStatus() FaultStatus { 114 return FaultStatus(arm.SCB.CFSR.Get()) 115 } 116 117 type FaultStatus uint32 118 type MemFaultStatus uint32 119 type BusFaultStatus uint32 120 type UsageFaultStatus uint32 121 122 func (fs FaultStatus) Mem() MemFaultStatus { return MemFaultStatus(fs) } 123 func (fs FaultStatus) Bus() BusFaultStatus { return BusFaultStatus(fs) } 124 func (fs FaultStatus) Usage() UsageFaultStatus { return UsageFaultStatus(fs) } 125 126 // Unknown returns true if the cause of the fault is not know 127 func (fs FaultStatus) Unknown() bool { 128 return fs&SCB_CFSR_KnownFault == 0 129 } 130 131 // InstructionAccessViolation: the processor attempted an instruction fetch from 132 // a location that does not permit execution 133 // 134 // "This fault occurs on any access to an XN region, even when the MPU is 135 // disabled or not present. 136 // 137 // When this bit is 1, the PC value stacked for the exception return points to 138 // the faulting instruction. The processor has not written a fault address to 139 // the MMAR." 140 func (fs MemFaultStatus) InstructionAccessViolation() bool { 141 return fs&arm.SCB_CFSR_IACCVIOL != 0 142 } 143 144 // DataAccessViolation: the processor attempted a load or store at a location 145 // that does not permit the operation 146 // 147 // "When this bit is 1, the PC value stacked for the exception return points to 148 // the faulting instruction. The processor has loaded the MMAR with the address 149 // of the attempted access." 150 func (fs MemFaultStatus) DataAccessViolation() bool { 151 return fs&arm.SCB_CFSR_DACCVIOL != 0 152 } 153 154 // WhileUnstackingException: unstack for an exception return has caused one or 155 // more access violations 156 // 157 // "This fault is chained to the handler. This means that when this bit is 1, 158 // the original return stack is still present. The processor has not adjusted 159 // the SP from the failing return, and has not performed a new save. The 160 // processor has not written a fault address to the MMAR." 161 func (fs MemFaultStatus) WhileUnstackingException() bool { 162 return fs&arm.SCB_CFSR_MUNSTKERR != 0 163 } 164 165 // WileStackingException: stacking for an exception entry has caused one or more 166 // access violations 167 // 168 // "When this bit is 1, the SP is still adjusted but the values in the context 169 // area on the stack might be incorrect. The processor has not written a fault 170 // address to the MMAR." 171 func (fs MemFaultStatus) WileStackingException() bool { 172 return fs&arm.SCB_CFSR_MSTKERR != 0 173 } 174 175 // DuringFPLazyStatePres: A MemManage fault occurred during floating-point lazy 176 // state preservation 177 func (fs MemFaultStatus) DuringFPLazyStatePres() bool { 178 return fs&arm.SCB_CFSR_MLSPERR != 0 179 } 180 181 // InstructionBusError: instruction bus error 182 // 183 // "The processor detects the instruction bus error on prefetching an 184 // instruction, but it sets the IBUSERR flag to 1 only if it attempts to issue 185 // the faulting instruction. 186 // 187 // When the processor sets this bit is 1, it does not write a fault address to 188 // the BFAR." 189 func (fs BusFaultStatus) InstructionBusError() bool { 190 return fs&arm.SCB_CFSR_IBUSERR != 0 191 } 192 193 // PreciseDataBusError: a data bus error has occurred, and the PC value stacked 194 // for the exception return points to the instruction that caused the fault 195 func (fs BusFaultStatus) PreciseDataBusError() bool { 196 return fs&arm.SCB_CFSR_PRECISERR != 0 197 } 198 199 // ImpreciseDataBusError: a data bus error has occurred, but the return address 200 // in the stack frame is not related to the instruction that caused the error 201 // 202 // "When the processor sets this bit to 1, it does not write a fault address to 203 // the BFAR. 204 // 205 // This is an asynchronous fault. Therefore, if it is detected when the priority 206 // of the current process is higher than the BusFault priority, the BusFault 207 // becomes pending and becomes active only when the processor returns from all 208 // higher priority processes. If a precise fault occurs before the processor 209 // enters the handler for the imprecise BusFault, the handler detects both 210 // IMPRECISERR set to 1 and one of the precise fault status bits set to 1." 211 func (fs BusFaultStatus) ImpreciseDataBusError() bool { 212 return fs&arm.SCB_CFSR_IMPRECISERR != 0 213 } 214 215 // WhileUnstackingException: unstack for an exception return has caused one or 216 // more BusFaults 217 // 218 // "This fault is chained to the handler. This means that when the processor 219 // sets this bit to 1, the original return stack is still present. The processor 220 // does not adjust the SP from the failing return, does not performed a new 221 // save, and does not write a fault address to the BFAR." 222 func (fs BusFaultStatus) WhileUnstackingException() bool { 223 return fs&arm.SCB_CFSR_UNSTKERR != 0 224 } 225 226 // WhileStackingException: stacking for an exception entry has caused one or 227 // more BusFaults 228 // 229 // "When the processor sets this bit to 1, the SP is still adjusted but the 230 // values in the context area on the stack might be incorrect. The processor 231 // does not write a fault address to the BFAR." 232 func (fs BusFaultStatus) WhileStackingException() bool { 233 return fs&arm.SCB_CFSR_STKERR != 0 234 } 235 236 // DuringFPLazyStatePres: A bus fault occurred during floating-point lazy state 237 // preservation 238 func (fs BusFaultStatus) DuringFPLazyStatePres() bool { 239 return fs&arm.SCB_CFSR_LSPERR != 0 240 } 241 242 // UndefinedInstruction: the processor has attempted to execute an undefined 243 // instruction 244 // 245 // "When this bit is set to 1, the PC value stacked for the exception return 246 // points to the undefined instruction. 247 // 248 // An undefined instruction is an instruction that the processor cannot decode." 249 func (fs UsageFaultStatus) UndefinedInstruction() bool { 250 return fs&arm.SCB_CFSR_UNDEFINSTR != 0 251 } 252 253 // IllegalUseOfEPSR: the processor has attempted to execute an instruction that 254 // makes illegal use of the EPSR 255 // 256 // "When this bit is set to 1, the PC value stacked for the exception return 257 // points to the instruction that attempted the illegal use of the EPSR. 258 // 259 // This bit is not set to 1 if an undefined instruction uses the EPSR." 260 func (fs UsageFaultStatus) IllegalUseOfEPSR() bool { 261 return fs&arm.SCB_CFSR_INVSTATE != 0 262 } 263 264 // IllegalExceptionReturn: the processor has attempted an illegal load of 265 // EXC_RETURN to the PC 266 // 267 // "When this bit is set to 1, the PC value stacked for the exception return 268 // points to the instruction that tried to perform the illegal load of the PC." 269 func (fs UsageFaultStatus) IllegalExceptionReturn() bool { 270 return fs&arm.SCB_CFSR_INVPC != 0 271 } 272 273 // AttemptedToAccessCoprocessor: the processor has attempted to access a 274 // coprocessor 275 func (fs UsageFaultStatus) AttemptedToAccessCoprocessor() bool { 276 return fs&arm.SCB_CFSR_NOCP != 0 277 } 278 279 // UnalignedMemoryAccess: the processor has made an unaligned memory access 280 // 281 // "Enable trapping of unaligned accesses by setting the UNALIGN_TRP bit in the 282 // CCR to 1. 283 // 284 // Unaligned LDM, STM, LDRD, and STRD instructions always fault irrespective of 285 // the setting of UNALIGN_TRP." 286 func (fs UsageFaultStatus) UnalignedMemoryAccess() bool { 287 return fs&arm.SCB_CFSR_UNALIGNED != 0 288 } 289 290 // DivideByZero: the processor has executed an SDIV or UDIV instruction with a 291 // divisor of 0 292 // 293 // "When the processor sets this bit to 1, the PC value stacked for the 294 // exception return points to the instruction that performed the divide by zero. 295 // 296 // Enable trapping of divide by zero by setting the DIV_0_TRP bit in the CCR to 297 // 1." 298 func (fs UsageFaultStatus) DivideByZero() bool { 299 return fs&arm.SCB_CFSR_DIVBYZERO != 0 300 } 301 302 // Address returns the MemManage Fault Address Register if the fault status 303 // indicates the address is valid. 304 // 305 // "If a MemManage fault occurs and is escalated to a HardFault because of 306 // priority, the HardFault handler must set this bit to 0. This prevents 307 // problems on return to a stacked active MemManage fault handler whose MMAR 308 // value has been overwritten." 309 func (fs MemFaultStatus) Address() (uintptr, bool) { 310 if fs&arm.SCB_CFSR_MMARVALID == 0 { 311 return 0, false 312 } else { 313 return uintptr(arm.SCB.MMFAR.Get()), true 314 } 315 } 316 317 // Address returns the BusFault Address Register if the fault status 318 // indicates the address is valid. 319 // 320 // "The processor sets this bit to 1 after a BusFault where the address is 321 // known. Other faults can set this bit to 0, such as a MemManage fault 322 // occurring later. 323 // 324 // If a BusFault occurs and is escalated to a hard fault because of priority, 325 // the hard fault handler must set this bit to 0. This prevents problems if 326 // returning to a stacked active BusFault handler whose BFAR value has been 327 // overwritten."" 328 func (fs BusFaultStatus) Address() (uintptr, bool) { 329 if fs&arm.SCB_CFSR_BFARVALID == 0 { 330 return 0, false 331 } else { 332 return uintptr(arm.SCB.BFAR.Get()), true 333 } 334 }