runtime: check for heap allocations inside interrupts
This is unsafe and should never be done.
Этот коммит содержится в:
родитель
e066e67baf
коммит
f41b6a3b96
9 изменённых файлов: 77 добавлений и 0 удалений
|
@ -277,6 +277,10 @@ func alloc(size uintptr, layout unsafe.Pointer) unsafe.Pointer {
|
|||
size += align(unsafe.Sizeof(layout))
|
||||
}
|
||||
|
||||
if interrupt.In() {
|
||||
runtimePanic("alloc in interrupt")
|
||||
}
|
||||
|
||||
gcTotalAlloc += uint64(size)
|
||||
gcMallocs++
|
||||
|
||||
|
|
|
@ -34,3 +34,12 @@ func Restore(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) {
|
||||
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
|
||||
|
||||
// This is good documentation of the GBA: https://www.akkit.org/info/gbatek.htm
|
||||
|
||||
import (
|
||||
"runtime/volatile"
|
||||
"unsafe"
|
||||
|
@ -36,8 +38,11 @@ func (irq Interrupt) Enable() {
|
|||
regInterruptEnable.SetBits(1 << uint(irq.num))
|
||||
}
|
||||
|
||||
var inInterrupt bool
|
||||
|
||||
//export handleInterrupt
|
||||
func handleInterrupt() {
|
||||
inInterrupt = true
|
||||
flags := regInterruptRequestFlags.Get()
|
||||
for i := 0; i < 14; i++ {
|
||||
if flags&(1<<uint(i)) != 0 {
|
||||
|
@ -45,6 +50,7 @@ func handleInterrupt() {
|
|||
callInterruptHandler(i)
|
||||
}
|
||||
}
|
||||
inInterrupt = false
|
||||
}
|
||||
|
||||
// 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.
|
||||
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
|
||||
// cricital sections.
|
||||
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) {
|
||||
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,
|
||||
})
|
||||
}
|
||||
|
||||
// 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.
|
||||
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.
|
||||
// Note that this address must be aligned specially, otherwise the MODE bits
|
||||
// of MTVEC won't be zero.
|
||||
|
@ -73,6 +79,10 @@ func handleInterrupt() {
|
|||
// misaligned loads). However, for now we'll just print a fatal error.
|
||||
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.
|
||||
|
|
|
@ -31,6 +31,12 @@ func main() {
|
|||
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.
|
||||
// Note that this address must be aligned specially, otherwise the MODE bits
|
||||
// of MTVEC won't be zero.
|
||||
|
@ -93,6 +99,10 @@ func handleInterrupt() {
|
|||
// misaligned loads). However, for now we'll just print a fatal error.
|
||||
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.
|
||||
|
|
Загрузка…
Создание таблицы
Сослаться в новой задаче