github.com/usbarmory/tamago@v0.0.0-20240508072735-8612bbe1e454/arm/exception.go (about) 1 // ARM processor support 2 // https://github.com/usbarmory/tamago 3 // 4 // Copyright (c) WithSecure Corporation 5 // https://foundry.withsecure.com 6 // 7 // Use of this source code is governed by the license 8 // that can be found in the LICENSE file. 9 10 package arm 11 12 import ( 13 "unsafe" 14 15 "github.com/usbarmory/tamago/internal/reg" 16 ) 17 18 // ARM exception vector offsets 19 // (Table 11-1, ARM® Cortex™ -A Series Programmer’s Guide). 20 const ( 21 RESET = 0x00 22 UNDEFINED = 0x04 23 SUPERVISOR = 0x08 24 PREFETCH_ABORT = 0x0c 25 DATA_ABORT = 0x10 26 IRQ = 0x18 27 FIQ = 0x1c 28 ) 29 30 // set by application or, if not previously defined, by cpu.Init() 31 var vecTableStart uint32 32 33 const ( 34 vecTableJump = 0xe59ff018 // ldr pc, [pc, #24] 35 vecTableSize = 0x4000 // 16 kB 36 excStackOffset = 0x8000 // 32 kB 37 excStackSize = 0x4000 // 16 kB 38 ) 39 40 // defined in exception.s 41 func set_exc_stack(addr uint32) 42 func set_vbar(addr uint32) 43 func set_mvbar(addr uint32) 44 func resetHandler() 45 func undefinedHandler() 46 func supervisorHandler() 47 func prefetchAbortHandler() 48 func dataAbortHandler() 49 func irqHandler() 50 func fiqHandler() 51 func nullHandler() 52 53 type ExceptionHandler func() 54 55 func vector(fn ExceptionHandler) uint32 { 56 return **((**uint32)(unsafe.Pointer(&fn))) 57 } 58 59 type VectorTable struct { 60 Reset ExceptionHandler 61 Undefined ExceptionHandler 62 Supervisor ExceptionHandler 63 PrefetchAbort ExceptionHandler 64 DataAbort ExceptionHandler 65 IRQ ExceptionHandler 66 FIQ ExceptionHandler 67 } 68 69 // DefaultExceptionHandler handles an exception by printing its vector and 70 // processor mode before panicking. 71 func DefaultExceptionHandler(off int) { 72 print("exception: vector ", off, " mode ", int(read_cpsr()&0x1f), "\n") 73 panic("unhandled exception") 74 } 75 76 // SystemExceptionHandler allows to override the default exception handler 77 // executed at any exception by the table returned by SystemVectorTable(), 78 // which is used by default when initializing the CPU instance (e.g. 79 // CPU.Init()). 80 var SystemExceptionHandler = DefaultExceptionHandler 81 82 func systemException(off int) { 83 SystemExceptionHandler(off) 84 } 85 86 // SystemVectorTable returns a vector table that, for all exceptions, switches 87 // to system mode and calls the SystemExceptionHandler on the Go runtime stack 88 // within goroutine g0. 89 func SystemVectorTable() VectorTable { 90 return VectorTable{ 91 Reset: resetHandler, 92 Undefined: undefinedHandler, 93 Supervisor: supervisorHandler, 94 PrefetchAbort: prefetchAbortHandler, 95 DataAbort: dataAbortHandler, 96 IRQ: irqHandler, 97 FIQ: fiqHandler, 98 } 99 } 100 101 // VectorName returns the exception vector offset name. 102 func VectorName(off int) string { 103 switch off { 104 case RESET: 105 return "RESET" 106 case UNDEFINED: 107 return "UNDEFINED" 108 case SUPERVISOR: 109 return "SUPERVISOR" 110 case PREFETCH_ABORT: 111 return "PREFETCH_ABORT" 112 case DATA_ABORT: 113 return "DATA_ABORT" 114 case IRQ: 115 return "IRQ" 116 case FIQ: 117 return "FIQ" 118 } 119 120 return "Unknown" 121 } 122 123 // SetVectorTable updates the CPU exception handling vector table with the 124 // addresses of the functions defined in the passed structure. 125 func (cpu *CPU) SetVectorTable(t VectorTable) { 126 vecTable := cpu.vbar + 8*4 127 128 // set handler pointers 129 // Table 11-1 ARM® Cortex™ -A Series Programmer’s Guide 130 131 reg.Write(vecTable+RESET, vector(t.Reset)) 132 reg.Write(vecTable+UNDEFINED, vector(t.Undefined)) 133 reg.Write(vecTable+SUPERVISOR, vector(t.Supervisor)) 134 reg.Write(vecTable+PREFETCH_ABORT, vector(t.PrefetchAbort)) 135 reg.Write(vecTable+DATA_ABORT, vector(t.DataAbort)) 136 reg.Write(vecTable+IRQ, vector(t.IRQ)) 137 reg.Write(vecTable+FIQ, vector(t.FIQ)) 138 } 139 140 //go:nosplit 141 func (cpu *CPU) initVectorTable(vbar uint32) { 142 cpu.vbar = vbar 143 144 // initialize jump table 145 // Table 11-1 ARM® Cortex™ -A Series Programmer’s Guide 146 for i := uint32(0); i < 8; i++ { 147 reg.Write(cpu.vbar+4*i, vecTableJump) 148 } 149 150 // set exception handlers 151 cpu.SetVectorTable(SystemVectorTable()) 152 153 // set vector base address register 154 set_vbar(cpu.vbar) 155 156 if cpu.Secure() { 157 // set monitor vector base address register 158 set_mvbar(cpu.vbar) 159 } 160 161 // Set the stack pointer for exception modes to provide a stack when 162 // summoned by exception vectors. 163 excStackStart := cpu.vbar + excStackOffset 164 set_exc_stack(excStackStart + excStackSize) 165 }