Skip to content

Instantly share code, notes, and snippets.

@folkertdev
Created April 25, 2025 09:25
Show Gist options
  • Save folkertdev/6a5ebe1272b38472310cec3964b6ae44 to your computer and use it in GitHub Desktop.
Save folkertdev/6a5ebe1272b38472310cec3964b6ae44 to your computer and use it in GitHub Desktop.
cfg macro example
#[unsafe(naked)]
extern "C" fn Reset() {
core::arch::naked_asm!(
// debug info
".cfi_sections .debug_frame",
".cfi_startproc",
// If enabled, initialise the SP. This is normally initialised by the CPU itself or by a
// bootloader, but some debuggers fail to set it when resetting the target, leading to
// stack corruptions.
#[cfg(feature = "set-sp")]
concat!("ldr r0, =_stack_start", "msr msp, r0",),
// If enabled, initialise VTOR to the start of the vector table. This is normally initialised
// by a bootloader when the non-reset value is required, but some bootloaders do not set it,
// leading to frustrating issues where everything seems to work but interrupts are never
// handled. The VTOR register is optional on ARMv6-M, but when not present is RAZ,WI and
// therefore safe to write to.
#[cfg(feature = "set-vtor")]
concat!(
"ldr r0, =0xe000ed08",
"ldr r1, =__vector_table",
"str r1, [r0]",
),
// If enabled, set the Main Stack Pointer Limit (MSPLIM) to the end of the stack.
// This feature is only available on ARMv8-M Mainline, where it helps enforce stack limits
// by defining the lowest valid stack address.
#[cfg(all(armv8m_main, feature = "set-msplim"))]
concat!("ldr r0, =_stack_end", "msr MSPLIM, r0",),
// Run user pre-init code which must be executed immediately after startup, before the
// potentially time-consuming memory initialisation takes place.
// Example use cases include disabling default watchdogs or enabling RAM.
"bl __pre_init",
// If enabled, initialize RAM with zeros. This is not usually required, but might be necessary
// to properly initialize checksum-based memory integrity measures on safety-critical hardware.
//
// Otherwise, initialise .bss memory. `__sbss` and `__ebss` come from the linker script.
cfg_match! {
feature = "zero-init-ram" => {
concat!(
"ldr r0, =_ram_start",
"ldr r1, =_ram_end",
)
}
_ => {
concat!(
"ldr r0, =__sbss",
"ldr r1, =__ebss",
)
}
},
// zero out r0..r1
"movs r2, #0",
"0:",
"cmp r1, r0",
"beq 1f",
"stm r0!, {{r2}}",
"b 0b",
"1:",
// If enabled, paint stack/heap RAM with 0xcccccccc.
// `_stack_end` and `_stack_start` come from the linker script.
#[cfg(feature = "paint-stack")]
concat!(
"ldr r0, =_stack_end",
"ldr r1, =_stack_start",
"ldr r2, =0xcccccccc", // This must match STACK_PAINT_VALUE
"0:",
"cmp r1, r0",
"beq 1f",
"stm r0!, {{r2}}",
"b 0b",
"1:",
),
// Initialise .data memory. `__sdata`, `__sidata`, and `__edata` come from the linker script.
"ldr r0, =__sdata",
"ldr r1, =__edata",
"ldr r2, =__sidata",
"0:",
"cmp r1, r0",
"beq 1f",
"ldm r2!, {{r3}}",
"stm r0!, {{r3}}",
"b 0b",
"1:",
// Potentially enable an FPU.
// SCB.CPACR is 0xE000_ED88.
// We enable access to CP10 and CP11 from priviliged and unprivileged mode.
#[cfg(has_fpu)]
concat!(
"ldr r0, =0xE000ED88",
"ldr r1, =(0b1111 << 20)",
"ldr r2, [r0]",
"orr r2, r2, r1",
"str r2, [r0]",
"dsb",
"isb",
),
// Jump to user main function.
// `bl` is used for the extended range, but the user main function should not return,
// so trap on any unexpected return.
"bl main",
"udf #0",
".cfi_endproc"
)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment