runtime: check for heap allocations inside interrupts

This is unsafe and should never be done.
Этот коммит содержится в:
Ayke van Laethem 2020-10-25 14:58:56 +01:00 коммит произвёл Ron Evans
родитель e066e67baf
коммит f41b6a3b96
9 изменённых файлов: 77 добавлений и 0 удалений

Просмотреть файл

@ -277,6 +277,10 @@ func alloc(size uintptr, layout unsafe.Pointer) unsafe.Pointer {
size += align(unsafe.Sizeof(layout)) size += align(unsafe.Sizeof(layout))
} }
if interrupt.In() {
runtimePanic("alloc in interrupt")
}
gcTotalAlloc += uint64(size) gcTotalAlloc += uint64(size)
gcMallocs++ gcMallocs++

Просмотреть файл

@ -34,3 +34,12 @@ func Restore(state State) {
"state": state, "state": state,
}) })
} }
// In returns whether the system is currently in an interrupt.
//
// Warning: this always returns false on AVR, as there does not appear to be a
// reliable way to determine whether we're currently running inside an interrupt
// handler.
func In() bool {
return false
}

Просмотреть файл

@ -50,3 +50,13 @@ func Disable() (state State) {
func Restore(state State) { func Restore(state State) {
arm.EnableInterrupts(uintptr(state)) arm.EnableInterrupts(uintptr(state))
} }
// In returns whether the system is currently in an interrupt.
func In() bool {
// The VECTACTIVE field gives the instruction vector that is currently
// active (in handler mode), or 0 if not in an interrupt.
// Documentation:
// https://developer.arm.com/documentation/dui0497/a/cortex-m0-peripherals/system-control-block/interrupt-control-and-state-register
vectactive := uint8(arm.SCB.ICSR.Get())
return vectactive != 0
}

Просмотреть файл

@ -2,6 +2,8 @@
package interrupt package interrupt
// This is good documentation of the GBA: https://www.akkit.org/info/gbatek.htm
import ( import (
"runtime/volatile" "runtime/volatile"
"unsafe" "unsafe"
@ -36,8 +38,11 @@ func (irq Interrupt) Enable() {
regInterruptEnable.SetBits(1 << uint(irq.num)) regInterruptEnable.SetBits(1 << uint(irq.num))
} }
var inInterrupt bool
//export handleInterrupt //export handleInterrupt
func handleInterrupt() { func handleInterrupt() {
inInterrupt = true
flags := regInterruptRequestFlags.Get() flags := regInterruptRequestFlags.Get()
for i := 0; i < 14; i++ { for i := 0; i < 14; i++ {
if flags&(1<<uint(i)) != 0 { if flags&(1<<uint(i)) != 0 {
@ -45,6 +50,7 @@ func handleInterrupt() {
callInterruptHandler(i) callInterruptHandler(i)
} }
} }
inInterrupt = false
} }
// Pseudo function call that is replaced by the compiler with the actual // Pseudo function call that is replaced by the compiler with the actual
@ -115,3 +121,8 @@ func Restore(state State) {
// Restore interrupts to the previous state. // Restore interrupts to the previous state.
regGlobalInterruptEnable.Set(uint16(state)) regGlobalInterruptEnable.Set(uint16(state))
} }
// In returns whether the system is currently in an interrupt.
func In() bool {
return inInterrupt
}

Просмотреть файл

@ -23,3 +23,9 @@ func Disable() (state State) {
// calling Disable, this will not re-enable interrupts, allowing for nested // calling Disable, this will not re-enable interrupts, allowing for nested
// cricital sections. // cricital sections.
func Restore(state State) {} func Restore(state State) {}
// In returns whether the system is currently in an interrupt.
func In() bool {
// There are no interrupts, so it can't be in one.
return false
}

Просмотреть файл

@ -27,3 +27,12 @@ func Disable() (state State) {
func Restore(state State) { func Restore(state State) {
riscv.EnableInterrupts(uintptr(state)) riscv.EnableInterrupts(uintptr(state))
} }
// In returns whether the system is currently in an interrupt.
func In() bool {
// There is one exception that has the value 0 (instruction address
// misaligned), but it's not very likely and even if it happens, it's not
// really something that can be recovered from. Therefore I think it's safe
// to ignore it. It's handled specially (in handleException).
return riscv.MCAUSE.Get() != 0
}

Просмотреть файл

@ -29,3 +29,11 @@ func Restore(state State) {
"state": state, "state": state,
}) })
} }
// In returns whether the system is currently in an interrupt.
//
// Warning: interrupts have not been implemented for Xtensa yet so this always
// returns false.
func In() bool {
return false
}

Просмотреть файл

@ -25,6 +25,12 @@ func main() {
// Zero the threshold value to allow all priorities of interrupts. // Zero the threshold value to allow all priorities of interrupts.
sifive.PLIC.THRESHOLD.Set(0) sifive.PLIC.THRESHOLD.Set(0)
// Zero MCAUSE, which is set to the reset reason on reset. It must be zeroed
// to make interrupt.In() work.
// This would also be a good time to save the reset reason, but that hasn't
// been implemented yet.
riscv.MCAUSE.Set(0)
// Set the interrupt address. // Set the interrupt address.
// Note that this address must be aligned specially, otherwise the MODE bits // Note that this address must be aligned specially, otherwise the MODE bits
// of MTVEC won't be zero. // of MTVEC won't be zero.
@ -73,6 +79,10 @@ func handleInterrupt() {
// misaligned loads). However, for now we'll just print a fatal error. // misaligned loads). However, for now we'll just print a fatal error.
handleException(code) handleException(code)
} }
// Zero MCAUSE so that it can later be used to see whether we're in an
// interrupt or not.
riscv.MCAUSE.Set(0)
} }
// initPeripherals configures periperhals the way the runtime expects them. // initPeripherals configures periperhals the way the runtime expects them.

Просмотреть файл

@ -31,6 +31,12 @@ func main() {
kendryte.PLIC.PRIORITY[i].Set(0) kendryte.PLIC.PRIORITY[i].Set(0)
} }
// Zero MCAUSE, which is set to the reset reason on reset. It must be zeroed
// to make interrupt.In() work.
// This would also be a good time to save the reset reason, but that hasn't
// been implemented yet.
riscv.MCAUSE.Set(0)
// Set the interrupt address. // Set the interrupt address.
// Note that this address must be aligned specially, otherwise the MODE bits // Note that this address must be aligned specially, otherwise the MODE bits
// of MTVEC won't be zero. // of MTVEC won't be zero.
@ -93,6 +99,10 @@ func handleInterrupt() {
// misaligned loads). However, for now we'll just print a fatal error. // misaligned loads). However, for now we'll just print a fatal error.
handleException(code) handleException(code)
} }
// Zero MCAUSE so that it can later be used to see whether we're in an
// interrupt or not.
riscv.MCAUSE.Set(0)
} }
// initPeripherals configures periperhals the way the runtime expects them. // initPeripherals configures periperhals the way the runtime expects them.