You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The exhubris tools are turning out to be a pretty good kernel torture test. 😄
During the reinitialize operation that starts (and restarts) a task, the kernel (on ARM M-profile at least) needs to deposit an initial stack frame in the task's stack memory, from which the hardware will load the task's initial register values. Before we do that, we "zap" the stack, overwriting it with a predictable pattern to help monitor a task's stack usage high-watermark.
let zap = task.try_write(&mut uslice).unwrap_lite();
for word in zap.iter_mut(){
*word = 0xbaddcafe;
}
}
That code assumes that the memory region containing the topmost word in the stack (initial_stack_ptr.saturating_sub(4)) also contains the the entire stack, because the kernel uses region.base to define the place to start zapping.
If the initial stack frame (104 bytes on Cortex-M4, thanks largely to the FPU) does not fit in the region that contains the topmost word of the stack, you instead get an invalid USlice constructed using region.base and a large negative number. (If you're building with overflow checks enabled, you get a subtraction with overflow panic. I disabled overflow checks to help find the real problem.) USlice rightfully rejects this as nonsense, which the code here really wasn't expecting, since it calls unwrap_lite on the result. Panic.
This code dates to the early days of Hubris when a task would always have a single contiguous RAM region containing the stack. In mainline "Oxide Hubris" that's still true in practice: we mostly apply the region-splitting allocator to flash.
The exhubris tools split both RAM and flash, deciding which to split next based on the potential cost of fragmentation given their sizes. This means I wound up with a task with a 256 byte stack split over no fewer than five regions (sizes: 32, 64, 64, 64, 32). In that case, it takes the last three regions to cover the 104-byte initial stack frame, and hilarity ensues. Where by "hilarity" I mean "the application refusing to start."
Interestingly, the actual code for writing the frame (just below) works fine if I disable the stack zap code, because it doesn't try to be clever with regions. So, the zap code itself needs to be improved to handle more elaborate RAM region splits.
I may land an initial fix that just makes the zap code optional, since the stack zapping method is inexact anyway (#1872).
The text was updated successfully, but these errors were encountered:
The
exhubris
tools are turning out to be a pretty good kernel torture test. 😄During the
reinitialize
operation that starts (and restarts) a task, the kernel (on ARM M-profile at least) needs to deposit an initial stack frame in the task's stack memory, from which the hardware will load the task's initial register values. Before we do that, we "zap" the stack, overwriting it with a predictable pattern to help monitor a task's stack usage high-watermark.The code in question is here:
hubris/sys/kern/src/arch/arm_m.rs
Lines 298 to 322 in 8437fbd
That code assumes that the memory region containing the topmost word in the stack (
initial_stack_ptr.saturating_sub(4)
) also contains the the entire stack, because the kernel usesregion.base
to define the place to start zapping.If the initial stack frame (104 bytes on Cortex-M4, thanks largely to the FPU) does not fit in the region that contains the topmost word of the stack, you instead get an invalid
USlice
constructed usingregion.base
and a large negative number. (If you're building with overflow checks enabled, you get a subtraction with overflow panic. I disabled overflow checks to help find the real problem.)USlice
rightfully rejects this as nonsense, which the code here really wasn't expecting, since it callsunwrap_lite
on the result. Panic.This code dates to the early days of Hubris when a task would always have a single contiguous RAM region containing the stack. In mainline "Oxide Hubris" that's still true in practice: we mostly apply the region-splitting allocator to flash.
The exhubris tools split both RAM and flash, deciding which to split next based on the potential cost of fragmentation given their sizes. This means I wound up with a task with a 256 byte stack split over no fewer than five regions (sizes: 32, 64, 64, 64, 32). In that case, it takes the last three regions to cover the 104-byte initial stack frame, and hilarity ensues. Where by "hilarity" I mean "the application refusing to start."
Interestingly, the actual code for writing the frame (just below) works fine if I disable the stack zap code, because it doesn't try to be clever with regions. So, the zap code itself needs to be improved to handle more elaborate RAM region splits.
I may land an initial fix that just makes the zap code optional, since the stack zapping method is inexact anyway (#1872).
The text was updated successfully, but these errors were encountered: