Skip to content

Commit 8a19965

Browse files
committed
Increase core0 stack to 8K and paint/measure stack usage.
1 parent 1ed790a commit 8a19965

File tree

5 files changed

+93
-12
lines changed

5 files changed

+93
-12
lines changed

.cargo/config.toml

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,7 @@
22
# This will make a UF2 and copy it to the RP2040's Mass Storage Device bootloader
33
# runner = "elf2uf2-rs -d"
44
# This will flash over SWD with any compatible probe it finds. You need 0.3.1 or higher for RP2040 support.
5-
runner = "probe-run --chip RP2040 --measure-stack"
6-
5+
runner = "probe-run --chip RP2040"
76
rustflags = [
87
# This is needed if your flash or ram addresses are not aligned to 0x10000 in memory.x
98
# See https://github.com/rust-embedded/cortex-m-quickstart/pull/95
@@ -17,4 +16,4 @@ rustflags = [
1716
]
1817

1918
[build]
20-
target = "thumbv6m-none-eabi" # Cortex-M0 and Cortex-M0+
19+
target = "thumbv6m-none-eabi" # Cortex-M0 and Cortex-M0+

Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,3 +77,6 @@ lto = true
7777
# good choice for performance on the RP2040, where code executes from external
7878
# SPI Flash and has to be buffered in a small on-chip cache memory.
7979
opt-level = "s"
80+
81+
[features]
82+
check-stack = []

memory.x

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -25,30 +25,33 @@ MEMORY {
2525
/*
2626
* This is the bottom of the four striped banks of SRAM in the RP2040.
2727
*/
28-
RAM_OS : ORIGIN = 0x20000000, LENGTH = 0x3A000
28+
RAM_OS : ORIGIN = 0x20000000, LENGTH = 0x39000
2929
/*
3030
* This is the top of the four striped banks of SRAM in the RP2040.
3131
*
32-
* We give ourselves six 4K pages [0x3A_000, 0x40_000]
32+
* We give ourselves size 4K pages [0x39_000..0x3E_FFF]
3333
*/
34-
RAM : ORIGIN = 0x2003A000, LENGTH = 24K
34+
RAM : ORIGIN = 0x20039000, LENGTH = 24K
3535
/*
36-
* This is the fifth bank, a 4KB block. We use this for Core 0 Stack.
36+
* This 4K from the top of striped RAM, plus the fifth bank - another a 4KB
37+
* block. We use this for Core 0 Stack. We tried 4K but it wasn't enough.
3738
*/
38-
RAM_CORE0_STACK : ORIGIN = 0x20040000, LENGTH = 4K
39+
RAM_CORE0_STACK : ORIGIN = 0x2003F000, LENGTH = 8K
3940
/*
4041
* This is the sixth bank, a 4KB block. We use this for Core 1 Stack.
42+
* As of 0.5.1 Pico BIOS uses about 316 bytes of this but we give it the
43+
* full 4K so it can have uncontended access to this SRAM bank.
4144
*/
4245
RAM_CORE1_STACK : ORIGIN = 0x20041000, LENGTH = 4K
4346
}
4447

4548
/*
4649
* This is where the call stack for Core 0 will be located. The stack is of
47-
* the full descending type. You may want to use this variable to locate the
48-
* call stack and static variables in different memory regions. Below is
49-
* shown the default value
50+
* the full descending type.
5051
*/
5152
_stack_start = ORIGIN(RAM_CORE0_STACK) + LENGTH(RAM_CORE0_STACK);
53+
_stack_bottom = ORIGIN(RAM_CORE0_STACK);
54+
_stack_len = LENGTH(RAM_CORE0_STACK);
5255

5356
/*
5457
* This is where the call stack for Core 1 will be located.

src/main.rs

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -311,6 +311,12 @@ extern "C" {
311311
static mut _ram_os_len: u32;
312312
}
313313

314+
/// What we paint Core 0's stack with
315+
const CORE0_STACK_PAINT_WORD: usize = 0xBBBB_BBBB;
316+
317+
/// What we paint Core 1's stack with
318+
const CORE1_STACK_PAINT_WORD: usize = 0xCCCC_CCCC;
319+
314320
// -----------------------------------------------------------------------------
315321
// Functions
316322
// -----------------------------------------------------------------------------
@@ -333,6 +339,27 @@ fn main() -> ! {
333339
// Reset the spinlocks.
334340
pp.SIO.spinlock[31].reset();
335341

342+
{
343+
// Paint the stack
344+
extern "C" {
345+
static mut _stack_bottom: usize;
346+
static mut _stack_len: usize;
347+
}
348+
// But not the top 64 words, because we're using the stack right now!
349+
let stack = unsafe {
350+
core::slice::from_raw_parts_mut(
351+
&mut _stack_bottom as *mut usize,
352+
(&mut _stack_len as *const _ as usize / core::mem::size_of::<usize>()) - 256,
353+
)
354+
};
355+
info!("Painting {:?}", stack.as_ptr_range());
356+
for b in stack.iter_mut() {
357+
*b = CORE0_STACK_PAINT_WORD;
358+
}
359+
}
360+
361+
check_stacks();
362+
336363
// Needed by the clock setup
337364
let mut watchdog = hal::watchdog::Watchdog::new(pp.WATCHDOG);
338365

@@ -1897,6 +1924,7 @@ extern "C" fn bus_interrupt_status() -> u32 {
18971924
/// media is indicated with a boolean field in the
18981925
/// `block_dev::DeviceInfo` structure.
18991926
pub extern "C" fn block_dev_get_info(device: u8) -> common::Option<common::block_dev::DeviceInfo> {
1927+
check_stacks();
19001928
match device {
19011929
0 => {
19021930
let mut lock = HARDWARE.lock();
@@ -1970,6 +1998,7 @@ pub extern "C" fn block_read(
19701998
data: common::ApiBuffer,
19711999
) -> common::Result<()> {
19722000
use embedded_sdmmc::BlockDevice;
2001+
check_stacks();
19732002
if data.data_len != usize::from(num_blocks) * 512 {
19742003
return common::Result::Err(common::Error::UnsupportedConfiguration(0));
19752004
}
@@ -2087,6 +2116,49 @@ fn IO_IRQ_BANK0() {
20872116
cortex_m::asm::sev();
20882117
}
20892118

2119+
/// Measure how much stack space remains unused.
2120+
#[cfg(feature = "check-stack")]
2121+
fn check_stacks() {
2122+
extern "C" {
2123+
static _stack_bottom: usize;
2124+
static _stack_len: usize;
2125+
static _core1_stack_bottom: usize;
2126+
static _core1_stack_len: usize;
2127+
}
2128+
let p = unsafe { &_stack_bottom as *const usize };
2129+
let total_bytes = unsafe { &_stack_len as *const usize as usize };
2130+
check_stack(p, total_bytes, CORE0_STACK_PAINT_WORD);
2131+
let p = unsafe { &_core1_stack_bottom as *const usize };
2132+
let total_bytes = unsafe { &_core1_stack_len as *const usize as usize };
2133+
check_stack(p, total_bytes, CORE1_STACK_PAINT_WORD);
2134+
}
2135+
2136+
/// Dummy stack checker that does nothing
2137+
#[cfg(not(feature = "check-stack"))]
2138+
fn check_stacks() {}
2139+
2140+
/// Check an individual stack to see how much has been used
2141+
#[cfg(feature = "check-stack")]
2142+
fn check_stack(start: *const usize, stack_len_bytes: usize, check_word: usize) {
2143+
let mut p: *const usize = start;
2144+
let mut free_bytes = 0;
2145+
loop {
2146+
let value = unsafe { p.read_volatile() };
2147+
if value != check_word {
2148+
break;
2149+
}
2150+
// Safety: We must hit a used stack value somewhere!
2151+
p = unsafe { p.offset(1) };
2152+
free_bytes += core::mem::size_of::<usize>();
2153+
}
2154+
defmt::debug!(
2155+
"Stack free at 0x{:08x}: {} bytes used of {} bytes",
2156+
start,
2157+
stack_len_bytes - free_bytes,
2158+
stack_len_bytes
2159+
);
2160+
}
2161+
20902162
/// Called when the CPU Hard Faults.
20912163
///
20922164
/// This probably means something panicked, and the Rust code was compiled to

src/vga/mod.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1034,10 +1034,14 @@ pub fn init(
10341034
}
10351035
core::slice::from_raw_parts_mut(
10361036
&mut _core1_stack_bottom as *mut _,
1037-
&mut _core1_stack_len as *const _ as usize / 4,
1037+
&mut _core1_stack_len as *const _ as usize / core::mem::size_of::<usize>(),
10381038
)
10391039
};
10401040

1041+
for b in core1_stack.iter_mut() {
1042+
*b = super::CORE1_STACK_PAINT_WORD;
1043+
}
1044+
10411045
debug!(
10421046
"Core 1 stack: {:08x}, {} bytes",
10431047
core1_stack.as_ptr(),

0 commit comments

Comments
 (0)