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_Handler copies .data from _sidata to _sdata.._edata, zeroes _sbss.._ebss and calls main().
  • SVC_Handler, PendSV_Handler and SysTick_Handler entries. Other exceptions go to a default handler that loops.

Linker script

boards/<board>/linker.ld must define:

  • MEMORY regions for flash and RAM.
  • ENTRY(Reset_Handler).
  • .text with KEEP(*(.isr_vector)) at the start of flash.
  • .data with its run address in RAM and load address in flash.
  • .bss in 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.