
This is the kind that is used in Go (actually CGo) for exporting functions. I think it's best to use //export instead of our custom //go:export pragma, for consistency (they are equivalent in TinyGo). Therefore I've updated all instances to the standard format (except for two that are updated in https://github.com/tinygo-org/tinygo/pull/1024). No smoke tests changed (when comparing the output hash), except for some wasm tests that include DWARF debug info and tend to be flaky anyway.
97 строки
2,4 КиБ
Go
97 строки
2,4 КиБ
Go
// +build cortexm
|
|
|
|
package runtime
|
|
|
|
import (
|
|
"device/arm"
|
|
"unsafe"
|
|
)
|
|
|
|
//go:extern _sbss
|
|
var _sbss [0]byte
|
|
|
|
//go:extern _ebss
|
|
var _ebss [0]byte
|
|
|
|
//go:extern _sdata
|
|
var _sdata [0]byte
|
|
|
|
//go:extern _sidata
|
|
var _sidata [0]byte
|
|
|
|
//go:extern _edata
|
|
var _edata [0]byte
|
|
|
|
func preinit() {
|
|
// Initialize .bss: zero-initialized global variables.
|
|
ptr := unsafe.Pointer(&_sbss)
|
|
for ptr != unsafe.Pointer(&_ebss) {
|
|
*(*uint32)(ptr) = 0
|
|
ptr = unsafe.Pointer(uintptr(ptr) + 4)
|
|
}
|
|
|
|
// Initialize .data: global variables initialized from flash.
|
|
src := unsafe.Pointer(&_sidata)
|
|
dst := unsafe.Pointer(&_sdata)
|
|
for dst != unsafe.Pointer(&_edata) {
|
|
*(*uint32)(dst) = *(*uint32)(src)
|
|
dst = unsafe.Pointer(uintptr(dst) + 4)
|
|
src = unsafe.Pointer(uintptr(src) + 4)
|
|
}
|
|
}
|
|
|
|
func abort() {
|
|
// disable all interrupts
|
|
arm.DisableInterrupts()
|
|
|
|
// lock up forever
|
|
for {
|
|
arm.Asm("wfi")
|
|
}
|
|
}
|
|
|
|
// The stack layout at the moment an interrupt occurs.
|
|
// Registers can be accessed if the stack pointer is cast to a pointer to this
|
|
// struct.
|
|
type interruptStack struct {
|
|
R0 uintptr
|
|
R1 uintptr
|
|
R2 uintptr
|
|
R3 uintptr
|
|
R12 uintptr
|
|
LR uintptr
|
|
PC uintptr
|
|
PSR uintptr
|
|
}
|
|
|
|
// This function is called at HardFault.
|
|
// Before this function is called, the stack pointer is reset to the initial
|
|
// stack pointer (loaded from addres 0x0) and the previous stack pointer is
|
|
// passed as an argument to this function. This allows for easy inspection of
|
|
// the stack the moment a HardFault occurs, but it means that the stack will be
|
|
// corrupted by this function and thus this handler must not attempt to recover.
|
|
//
|
|
// For details, see:
|
|
// https://community.arm.com/developer/ip-products/system/f/embedded-forum/3257/debugging-a-cortex-m0-hard-fault
|
|
// https://blog.feabhas.com/2013/02/developing-a-generic-hard-fault-handler-for-arm-cortex-m3cortex-m4/
|
|
//export handleHardFault
|
|
func handleHardFault(sp *interruptStack) {
|
|
print("fatal error: ")
|
|
if uintptr(unsafe.Pointer(sp)) < 0x20000000 {
|
|
print("stack overflow")
|
|
} else {
|
|
// TODO: try to find the cause of the hard fault. Especially on
|
|
// Cortex-M3 and higher it is possible to find more detailed information
|
|
// in special status registers.
|
|
print("HardFault")
|
|
}
|
|
print(" with sp=", sp)
|
|
if uintptr(unsafe.Pointer(&sp.PC)) >= 0x20000000 {
|
|
// Only print the PC if it points into memory.
|
|
// It may not point into memory during a stack overflow, so check that
|
|
// first before accessing the stack.
|
|
print(" pc=", sp.PC)
|
|
}
|
|
println()
|
|
abort()
|
|
}
|