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  }