github.com/f-secure-foundry/tamago@v0.0.0-20220307101044-d73fcdd7f11b/arm/exception.go (about)

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