$npx -y skills add mohitmishra786/low-level-dev-skills --skill baremetal-startupBare-metal startup skill for reset-to-main bring-up. Use when writing startup code, vector tables, .data/.bss init, stack setup, or crt0 for Cortex-M/RISC-V. Activates on queries about reset vector, VTOR, startup.s, bss init, or bare-metal entry point.
| 1 | # Bare-Metal Startup |
| 2 | |
| 3 | ## Purpose |
| 4 | |
| 5 | Guide agents through bare-metal startup from reset to `main()`: reset and exception vectors, `.data`/`.bss` initialization, stack and heap setup, C runtime integration with linker scripts, and common Cortex-M and RISC-V bring-up bugs. |
| 6 | |
| 7 | ## When to Use |
| 8 | |
| 9 | - Firmware hangs before reaching `main()` |
| 10 | - Porting to a new MCU without vendor HAL |
| 11 | - Writing custom `startup.s` or `Reset_Handler` |
| 12 | - Integrating with `skills/embedded/linker-scripts` |
| 13 | - Debugging uninitialized globals or stack overflows at boot |
| 14 | |
| 15 | ## Workflow |
| 16 | |
| 17 | ### 1. Boot sequence mental model |
| 18 | |
| 19 | ``` |
| 20 | Power-on / reset |
| 21 | ├── CPU loads SP from vector[0] |
| 22 | ├── CPU branches to Reset_Handler from vector[1] |
| 23 | ├── Reset_Handler: init clocks (optional), copy .data, zero .bss |
| 24 | ├── Configure stack pointer (if not already from vector) |
| 25 | ├── Call SystemInit() / platform_init() |
| 26 | └── Call main() — must not return (loop or WFI) |
| 27 | ``` |
| 28 | |
| 29 | ### 2. Cortex-M vector table |
| 30 | |
| 31 | On Cortex-M, the vector table starts at address 0 or a relocatable base (VTOR): |
| 32 | |
| 33 | | Index | Entry | |
| 34 | |-------|-------| |
| 35 | | 0 | Initial stack pointer (`_estack`) | |
| 36 | | 1 | `Reset_Handler` | |
| 37 | | 2 | `NMI_Handler` | |
| 38 | | 3 | `HardFault_Handler` | |
| 39 | | 4+ | IRQ handlers per NVIC | |
| 40 | |
| 41 | ```asm |
| 42 | /* startup.s — minimal Cortex-M */ |
| 43 | .syntax unified |
| 44 | .thumb |
| 45 | |
| 46 | .section .isr_vector,"a",%progbits |
| 47 | .global g_pfnVectors |
| 48 | g_pfnVectors: |
| 49 | .word _estack |
| 50 | .word Reset_Handler |
| 51 | .word NMI_Handler |
| 52 | .word HardFault_Handler |
| 53 | /* ... device IRQ vectors from vendor CMSIS ... */ |
| 54 | |
| 55 | .section .text.Reset_Handler |
| 56 | .thumb_func |
| 57 | .global Reset_Handler |
| 58 | Reset_Handler: |
| 59 | ldr r0, =_sidata /* .data load address (LMA) */ |
| 60 | ldr r1, =_sdata /* .data VMA start */ |
| 61 | ldr r2, =_edata |
| 62 | b LoopCopyDataInit |
| 63 | CopyDataInit: |
| 64 | ldr r3, [r0], #4 |
| 65 | str r3, [r1], #4 |
| 66 | LoopCopyDataInit: |
| 67 | cmp r1, r2 |
| 68 | blt CopyDataInit |
| 69 | ldr r2, =_sbss |
| 70 | ldr r4, =_ebss |
| 71 | movs r3, #0 |
| 72 | b LoopFillZerobss |
| 73 | FillZerobss: |
| 74 | str r3, [r2], #4 |
| 75 | LoopFillZerobss: |
| 76 | cmp r2, r4 |
| 77 | blt FillZerobss |
| 78 | bl SystemInit |
| 79 | bl main |
| 80 | b . |
| 81 | ``` |
| 82 | |
| 83 | ```c |
| 84 | /* Linker symbols — declared extern in startup */ |
| 85 | extern uint32_t _estack, _sidata, _sdata, _edata, _sbss, _ebss; |
| 86 | ``` |
| 87 | |
| 88 | ### 3. VTOR relocation (Cortex-M) |
| 89 | |
| 90 | ```c |
| 91 | #include "core_cm4.h" /* CMSIS */ |
| 92 | |
| 93 | void relocate_vector_table(uint32_t base) { |
| 94 | SCB->VTOR = base & 0xFFFFFF80U; /* must be aligned per ARM ref manual */ |
| 95 | __DSB(); |
| 96 | __ISB(); |
| 97 | } |
| 98 | ``` |
| 99 | |
| 100 | Bootloader jumping to app often requires setting VTOR to the application's vector table address (e.g., `0x08020000` on STM32 flash). |
| 101 | |
| 102 | ### 4. RISC-V startup (overview) |
| 103 | |
| 104 | ```asm |
| 105 | /* entry.S — simplified */ |
| 106 | .section .text.entry |
| 107 | .global _start |
| 108 | _start: |
| 109 | la sp, _stack_top |
| 110 | la t0, _bss_start |
| 111 | la t1, _bss_end |
| 112 | clear_bss: |
| 113 | beq t0, t1, bss_done |
| 114 | sw zero, 0(t0) |
| 115 | addi t0, t0, 4 |
| 116 | j clear_bss |
| 117 | bss_done: |
| 118 | call main |
| 119 | j . |
| 120 | ``` |
| 121 | |
| 122 | Trap vector: `mtvec` for M-mode; see `skills/platform/riscv-privileged`. |
| 123 | |
| 124 | ### 5. crt0 responsibilities |
| 125 | |
| 126 | | Task | Who does it | |
| 127 | |------|-------------| |
| 128 | | Copy `.data` LMA→VMA | `Reset_Handler` / crt0 | |
| 129 | | Zero `.bss` | `Reset_Handler` | |
| 130 | | Init stack | Vector[0] or explicit `sp` | |
| 131 | | Heap (`_sbrk`) | Optional; libc or custom | |
| 132 | | C++ constructors | `__libc_init_array()` if using full libc | |
| 133 | | FPU enable | `SystemInit` on Cortex-M4F/M7 | |
| 134 | |
| 135 | ### 6. Linker script integration |
| 136 | |
| 137 | ```ld |
| 138 | _estack = ORIGIN(RAM) + LENGTH(RAM); |
| 139 | _sidata = LOADADDR(.data); |
| 140 | ``` |
| 141 | |
| 142 | Cross-link `skills/embedded/linker-scripts` for MEMORY/SECTIONS layout. |
| 143 | |
| 144 | ### 7. Agent usage examples |
| 145 | |
| 146 | ``` |
| 147 | /baremetal-startup My STM32 never reaches main — what should Reset_Handler do? |
| 148 | /baremetal-startup How do I relocate the vector table after bootloader jump? |
| 149 | ``` |
| 150 | |
| 151 | ## Common Problems |
| 152 | |
| 153 | | Symptom | Cause | Fix | |
| 154 | |---------|-------|-----| |
| 155 | | HardFault immediately | Stack pointer invalid | Set `_estack` to valid RAM top | |
| 156 | | Globals wrong at boot | `.data` not copied | Copy LMA→VMA in Reset_Handler | |
| 157 | | BSS non-zero | `.bss` not zeroed | Add bss clear loop | |
| 158 | | IRQs don't fire | VTOR points to wrong table | `SCB->VTOR = app_vector_addr` | |
| 159 | | `main` returns into garbage | No loop after main | `while(1)` or `WFI` loop | |
| 160 | | C++ static init crash | Constructors before clocks | Call `SystemInit` first | |
| 161 | |
| 162 | ## Related Skills |
| 163 | |
| 164 | - `skills/embedded/linker-scripts` — `_estack`, LMA/VMA, section placement |
| 165 | - `skills/baremetal/interrupts-and-exceptions-baremetal` — vector table IRQ entries |
| 166 | - `skills/baremetal/bootloaders-embedded` — VTOR relocation on app jump |
| 167 | - `skills/embedded/openocd-jtag` — halt at `Reset_Handler` with GDB |
| 168 | - `skills/low-level-programming/assembly-arm` — Thumb-2 syntax |
| 169 | - `skills/platform/riscv-privileged` — RISC-V trap setup |