Porting
HAL functions and files required for a new architecture or board.
The kernel calls hardware only through include/bedrock/br_hal.h. A port implements those functions in arch/<arch>/, adds a board directory in boards/<board>/ and build targets in chorus.build. Kernel sources do not change.
Reference implementations: arch/arm-cortex-m/ with boards/qemu-cortex-m3/, and arch/host-x86-64/.
HAL functions
Timer
void br_hal_timer_init(void);
br_time_t br_hal_timer_get_us(void);
void br_hal_timer_set_alarm(br_time_t abs_us);
void br_hal_timer_cancel_alarm(void);
| Function | Requirement |
|---|---|
br_hal_timer_init |
Start a free-running time source. Called from br_kernel_init() after br_hal_board_init(). |
br_hal_timer_get_us |
Microseconds since init. Monotonic. Must handle wrap of the hardware counter. |
br_hal_timer_set_alarm |
Arm a one-shot alarm at absolute time abs_us. Replaces any earlier alarm. On expiry, call br_time_alarm_handler(). |
br_hal_timer_cancel_alarm |
Disarm the alarm. |
The timer interrupt must also call br_sched_tick(elapsed_us) for round-robin time slicing. It is not declared in a public header. Both reference ports declare it extern.
Interrupt control
uint32_t br_hal_irq_disable(void);
void br_hal_irq_restore(uint32_t state);
bool br_hal_in_isr(void);
br_hal_irq_disable returns the previous state. Calls nest, so br_hal_irq_restore must restore exactly that state instead of enabling interrupts unconditionally. br_hal_in_isr returns true in interrupt or exception context.
Context switch
void *br_hal_stack_init(void *stack_top, br_task_entry_t entry, void *arg);
void br_hal_context_switch(void **old_sp, void **new_sp);
void br_hal_start_first_task(void *sp) __attribute__((noreturn));
void br_hal_check_stack_overflow(br_tcb_t *tcb);
| Function | Requirement |
|---|---|
br_hal_stack_init |
Build the initial frame below stack_top (highest address) so that restoring it starts entry(arg). Return the resulting stack pointer. |
br_hal_context_switch |
Save the current context, store its stack pointer in *old_sp, restore from *new_sp. Called with interrupts disabled. It may defer the switch until interrupts are restored, as PendSV does on Cortex-M. |
br_hal_start_first_task |
Load sp and start the first task. Never returns. |
br_hal_check_stack_overflow |
Compare *tcb->stack_canary with BR_STACK_CANARY and call br_hal_panic() on mismatch. Called before every switch. |
sp is the first member of br_tcb_t, so assembly can reach it at offset 0.
Board and panic
void br_hal_board_init(void);
void br_hal_panic(const char *msg, const char *file, int line) __attribute__((noreturn));
br_hal_board_init runs first in br_kernel_init(), before the timer. It may be empty.
br_hal_panic stops the system. The Cortex-M port disables interrupts, prints the arguments to UART and loops on wfi.
Startup code
The Cortex-M port uses arch/arm-cortex-m/startup.c:
- A vector table in section
.isr_vector, starting with the initial stack pointer_estack. Reset_Handlercopies.datafrom_sidatato_sdata.._edata, zeroes_sbss.._ebssand callsmain().SVC_Handler,PendSV_HandlerandSysTick_Handlerentries. Other exceptions go to a default handler that loops.
Linker script
boards/<board>/linker.ld must define:
MEMORYregions for flash and RAM.ENTRY(Reset_Handler)..textwithKEEP(*(.isr_vector))at the start of flash..datawith its run address in RAM and load address in flash..bssin RAM.- The symbols
_sidata,_sdata,_edata,_sbss,_ebss,_estack.
Board files
| File | Purpose |
|---|---|
boards/<board>/linker.ld |
Memory layout |
boards/<board>/defconfig |
Default .config for chorus defconfig |
To make the architecture selectable, add a config ARCH_<NAME> entry to the choice ARCH block in Kconfig.
Build targets
Add compile rules for the new arch/<arch>/*.c files to chorus.build, a libbedrock_hal archive for them, and a link rule that uses the new linker script. The existing Cortex-M and host-* targets show the pattern.