github.com/usbarmory/GoTEE@v0.0.0-20240405084336-c52770d9fcdb/monitor/exec_arm.go (about) 1 // Copyright (c) WithSecure Corporation 2 // https://foundry.withsecure.com 3 // 4 // Use of this source code is governed by the license 5 // that can be found in the LICENSE file. 6 7 // Package monitor provides supervisor support for TamaGo unikernels to allow 8 // scheduling of Secure user mode or NonSecure system mode executables. 9 // 10 // This package is only meant to be used with `GOOS=tamago GOARCH=arm` as 11 // supported by the TamaGo framework for bare metal Go on ARM SoCs, see 12 // https://github.com/usbarmory/tamago. 13 package monitor 14 15 import ( 16 "errors" 17 "log" 18 "net/rpc" 19 "runtime" 20 "sync" 21 22 "github.com/usbarmory/tamago/arm" 23 "github.com/usbarmory/tamago/arm/tzc380" 24 "github.com/usbarmory/tamago/dma" 25 "github.com/usbarmory/tamago/soc/nxp/imx6ul" 26 ) 27 28 var ( 29 systemVectorTable = arm.SystemVectorTable() 30 31 monitorVectorTable = arm.VectorTable{ 32 Reset: resetMonitor, 33 Undefined: undefinedMonitor, 34 Supervisor: supervisorMonitor, 35 PrefetchAbort: prefetchAbortMonitor, 36 DataAbort: dataAbortMonitor, 37 IRQ: irqMonitor, 38 FIQ: fiqMonitor, 39 } 40 ) 41 42 var mux sync.Mutex 43 44 // defined in exec_arm.s 45 func resetMonitor() 46 func undefinedMonitor() 47 func supervisorMonitor() 48 func prefetchAbortMonitor() 49 func dataAbortMonitor() 50 func irqMonitor() 51 func fiqMonitor() 52 53 func init() { 54 imx6ul.CSU.Init() 55 imx6ul.TZASC.Init() 56 57 if !imx6ul.Native { 58 return 59 } 60 61 tzcAttr := (1 << tzc380.SP_SW_RD) | (1 << tzc380.SP_SW_WR) 62 63 // redundant enforcement of Region 0 (entire memory space) defaults 64 if err := imx6ul.TZASC.EnableRegion(0, 0, 0, tzcAttr); err != nil { 65 panic("could not set TZASC defaults") 66 } 67 } 68 69 // Exec allows execution of an executable in Secure user mode or NonSecure 70 // system mode. The execution is isolated from the invoking Go runtime, 71 // yielding back to it is supported through exceptions (e.g. syscalls through 72 // SVC). 73 // 74 // The execution context pointer allows task initialization and it is updated 75 // with the program state at return, it can therefore be passed again to resume 76 // the task. 77 func Exec(ctx *ExecCtx) 78 79 // ExecCtx represents a executable initialization or returning state. 80 type ExecCtx struct { 81 R0 uint32 82 R1 uint32 83 R2 uint32 84 R3 uint32 85 R4 uint32 86 R5 uint32 87 R6 uint32 88 R7 uint32 89 R8 uint32 90 R9 uint32 91 R10 uint32 92 R11 uint32 93 R12 uint32 94 R13 uint32 // SP 95 R14 uint32 // LR 96 R15 uint32 // PC 97 98 // CPSR is the Current Program Status Register of the handler which 99 // caught the exception raised by the execution context. 100 CPSR uint32 101 102 // SPSR (Saved Program Status Register) is the CPSR of the execution 103 // context as it raised the exception. 104 SPSR uint32 105 106 ExceptionVector int 107 108 VFP []uint64 // d0-d31 109 FPSCR uint32 110 FPEXC uint32 111 112 // Memory is the executable allocated RAM 113 Memory *dma.Region 114 // Domain represents the domain ID (0-15) assigned to the executable 115 // Memory. The value must be overridden with distinct values if memory 116 // isolation is required for parallel execution of different 117 // user/secure execution contexts. 118 Domain uint32 119 120 // Handler, if not nil, handles user syscalls 121 Handler func(ctx *ExecCtx) error 122 123 // Server, if not nil, serves RPC calls over syscalls 124 Server *rpc.Server 125 126 // Debug controls activation of debug logs 127 Debug bool 128 129 // execution state 130 run bool 131 // stopped will be closed once the context has stopped running. 132 stopped chan struct{} 133 // TrustZone configuration 134 ns bool 135 // executing g stack pointer 136 g_sp uint32 137 138 // Read() buffer 139 in []byte 140 // Write() buffer 141 out []byte 142 } 143 144 // Print logs the execution context registers. 145 func (ctx *ExecCtx) Print() { 146 cpsr, spsr := ctx.Mode() 147 148 log.Printf(" r0:%.8x r1:%.8x r2:%.8x r3:%.8x", ctx.R0, ctx.R1, ctx.R2, ctx.R3) 149 log.Printf(" r4:%.8x r5:%.8x r6:%.8x r7:%.8x", ctx.R4, ctx.R5, ctx.R6, ctx.R7) 150 log.Printf(" r8:%.8x r9:%.8x r10:%.8x r11:%.8x cpsr:%.8x (%s)", ctx.R8, ctx.R9, ctx.R10, ctx.R11, ctx.CPSR, arm.ModeName(cpsr)) 151 log.Printf(" r12:%.8x sp:%.8x lr:%.8x pc:%.8x spsr:%.8x (%s)", ctx.R12, ctx.R13, ctx.R14, ctx.R15, ctx.SPSR, arm.ModeName(spsr)) 152 } 153 154 // NonSecure returns whether the execution context is loaded as non-secure. 155 func (ctx *ExecCtx) NonSecure() bool { 156 return ctx.ns 157 } 158 159 // Mode returns the processor mode. 160 func (ctx *ExecCtx) Mode() (current int, saved int) { 161 current = int(ctx.CPSR & 0x1f) 162 saved = int(ctx.SPSR & 0x1f) 163 return 164 } 165 166 func (ctx *ExecCtx) schedule() (err error) { 167 mux.Lock() 168 defer mux.Unlock() 169 170 // set monitor handlers 171 arm.SetVectorTable(monitorVectorTable) 172 173 // execute context 174 Exec(ctx) 175 176 // restore default handlers 177 arm.SetVectorTable(systemVectorTable) 178 179 mode, _ := ctx.Mode() 180 181 switch mode { 182 case arm.IRQ_MODE, arm.FIQ_MODE, arm.SVC_MODE, arm.MON_MODE: 183 return 184 default: 185 if ctx.Debug { 186 ctx.Print() 187 } 188 189 return errors.New(arm.ModeName(mode)) 190 } 191 192 return 193 } 194 195 // Run starts the execution context and handles system or monitor calls. The 196 // execution yields back to the invoking Go runtime only when exceptions are 197 // caught. 198 // 199 // The function invokes the context Handler() and returns when an unhandled 200 // exception, or any other error, is raised. 201 func (ctx *ExecCtx) Run() (err error) { 202 ctx.run = true 203 ctx.stopped = make(chan struct{}) 204 defer close(ctx.stopped) 205 206 ap := arm.TTE_AP_001 207 208 if !ctx.ns { 209 ap = arm.TTE_AP_011 210 } 211 212 // Set privilege level and domain access 213 imx6ul.ARM.SetAccessPermissions( 214 uint32(ctx.Memory.Start()), uint32(ctx.Memory.End()), 215 ap, ctx.Domain, 216 ) 217 218 for ctx.run { 219 if err = ctx.schedule(); err != nil { 220 break 221 } 222 223 if ctx.Handler != nil { 224 if err = ctx.Handler(ctx); err != nil { 225 break 226 } 227 } 228 229 // Return to next instruction when handling interrupts 230 // (Table 11-3, ARM® Cortex™ -A Series Programmer’s Guide). 231 switch ctx.ExceptionVector { 232 case arm.IRQ, arm.FIQ: 233 ctx.R15 -= 4 234 } 235 236 runtime.Gosched() 237 } 238 239 return 240 } 241 242 // Stop stops the execution context. 243 func (ctx *ExecCtx) Stop() { 244 mux.Lock() 245 defer mux.Unlock() 246 247 ctx.run = false 248 } 249 250 // Done returns a channel which will be closed once execution context has stopped. 251 func (ctx *ExecCtx) Done() chan struct{} { 252 return ctx.stopped 253 } 254 255 // Load returns an execution context initialized for the argument entry point 256 // and memory region, the secure flag controls whether the context belongs to a 257 // secure partition (e.g. TrustZone Secure World) or a non-secure one (e.g. 258 // TrustZone Normal World). 259 // 260 // In case of a non-secure execution context, the memory is configured as 261 // NonSecure by means of MMU NS bit and memory controller region configuration. 262 // 263 // The caller is responsible for any other required MMU configuration (see 264 // arm.ConfigureMMU()) or additional peripheral restrictions (e.g. TrustZone). 265 func Load(entry uint, mem *dma.Region, secure bool) (ctx *ExecCtx, err error) { 266 ctx = &ExecCtx{ 267 R15: uint32(entry), 268 VFP: make([]uint64, 32), 269 Memory: mem, 270 Server: rpc.NewServer(), 271 ns: !secure, 272 } 273 274 if secure { 275 // enable VFP 276 ctx.FPEXC = 1 << arm.FPEXC_EN 277 } 278 279 if secure { 280 ctx.Handler = SecureHandler 281 } else { 282 ctx.Handler = NonSecureHandler 283 } 284 285 tzcAttr := (1 << tzc380.SP_NW_RD) | (1 << tzc380.SP_NW_WR) 286 287 if ctx.ns && imx6ul.Native { 288 // allow NonSecure World R/W access to its own memory 289 if err = imx6ul.TZASC.EnableRegion(1, uint32(mem.Start()), uint32(mem.Size()), tzcAttr); err != nil { 290 return 291 } 292 } 293 294 // set all mask bits 295 ctx.SPSR = (0b111 << 6) 296 flags := arm.MemoryRegion 297 298 if ctx.ns { 299 // The NS bit is required to ensure that cache lines are kept 300 // separate. 301 ctx.SPSR |= arm.SYS_MODE 302 flags |= arm.TTE_NS 303 } else { 304 ctx.SPSR |= arm.USR_MODE 305 } 306 307 imx6ul.ARM.SetAttributes(uint32(mem.Start()), uint32(mem.End()), flags) 308 309 return 310 }