Architecture
Kernel components, memory model, boot sequence and the reference ports.
The kernel owns the boot process, the scheduler and the hardware abstraction layer. Application code runs as tasks.
Source layout
bedrock-core/
├── include/bedrock/ Public headers
├── kernel/ Scheduler, tasks, time, IPC, panic
├── arch/
│ ├── arm-cortex-m/ Cortex-M3 port
│ └── host-x86-64/ Linux process port for tests
├── boards/
│ └── qemu-cortex-m3/ Linker script and defconfig
├── lib/ Fixed-block pool allocator
├── examples/ Example application and test programs
├── docs/ Documentation, EN and RU
├── 3rd/tools/ chorus and kconfig-tools submodules
├── Kconfig
└── chorus.build
Scheduler
kernel/br_sched.c
- One ready queue per priority level,
CONFIG_NUM_PRIORITIESin total. Priority 0 is the highest. - The highest-priority ready task runs. Tasks of equal priority are kept in FIFO order and rotate when their time slice expires.
- The slice is
CONFIG_RR_TIME_SLICE_US. The port’s timer interrupt callsbr_sched_tick()with the elapsed time. If the slice is used up and another task of the same priority is ready, the scheduler switches. Otherwise the slice is renewed. br_sched_lock()andbr_sched_unlock()nest. Rescheduling is skipped while the lock depth is above zero.- Before each switch the outgoing task’s stack canary is checked with
br_hal_check_stack_overflow().
Tasks
kernel/br_task.c
- TCBs are stored in a static array of
CONFIG_MAX_TASKSentries. br_task_create()takes the first slot in stateBR_TASK_INACTIVE.br_task_delete()returns a slot to that state.- States:
INACTIVE,READY,RUNNING,BLOCKED,SUSPENDED. br_kernel_init()creates an idle task at priorityCONFIG_NUM_PRIORITIES - 1with a stack ofCONFIG_DEFAULT_STACK_SIZEbytes.- The word at the lowest address of each task stack is set to
0xDEADBEEFand used as the canary.
Time
kernel/br_time.c
br_time_tis a 64-bit count of microseconds.- Sleeping and timed-out tasks are kept in one list sorted by wake time. Each TCB has a separate link (
sleep_next) for this list, so a task can be in an IPC wait queue and the sleep list at once. - After every change to the list the kernel calls
br_hal_timer_set_alarm()with the earliest wake time, orbr_hal_timer_cancel_alarm()when the list is empty. - When the alarm fires, the port calls
br_time_alarm_handler(). It moves every expired task to its ready queue with resultBR_ERR_TIMEOUT, reprograms the alarm and reschedules.
IPC
kernel/br_ipc.c
| Object | Behaviour |
|---|---|
| Semaphore | Counting, with a maximum. give wakes the first waiter instead of incrementing when one exists. |
| Mutex | Owned lock. When a higher-priority task blocks on it, the owner is raised to that priority until unlock. Ownership passes directly to the first waiter. |
| Message queue | Ring buffer of fixed-size messages in caller memory. Separate wait queues for senders and receivers. |
Wait queues are ordered by priority. Tasks of equal priority are kept in arrival order.
All blocking calls take a timeout. 0 returns immediately. BR_TIME_INFINITE waits without a timeout. Any other value also inserts the task into the sleep list.
Memory
- The kernel does not call
malloc. - Task stacks, message queue buffers and IPC objects are allocated by the caller, statically or on a stack.
lib/br_pool.cprovides a fixed-block allocator over a caller buffer. Pool descriptors come from a static array ofBR_POOL_MAX_POOLSentries.
Boot sequence
Reset_Handlercopies.datafrom flash, zeroes.bssand callsmain().main()callsbr_kernel_init(), which marks all TCBs inactive, callsbr_hal_board_init()andbr_hal_timer_init(), initializes the scheduler and creates the idle task.- The application creates its tasks.
br_kernel_start()starts the highest-priority ready task and does not return.
Cortex-M3 port
arch/arm-cortex-m/, boards/qemu-cortex-m3/
Target: QEMU lm3s6965evb, 256 KB flash at 0x00000000, 64 KB SRAM at 0x20000000.
br_hal_stack_init()builds an exception frame: xPSR, PC, LR, R12, R3 to R0, withargin R0, followed by zeroed R4 to R11. LR points to a handler that loops forever, so a task entry function that returns stops in that loop.br_hal_context_switch()stores the two stack pointer addresses and pends PendSV.PendSV_Handlersaves and restores R4 to R11 and swaps PSP.br_hal_start_first_task()enters the first task through ansvc 0exception.- Interrupt control uses PRIMASK.
br_hal_in_isr()reads the active vector fromSCB->ICSR. - UART0 at
0x4000C000, polled, transmit only. br_hal_panic()disables interrupts, prints the message, file and line to UART0, then halts in awfiloop.
Timer
The time source is SysTick with a reload value of 0xFFFFFF, running from the core clock. The microsecond counter is advanced on every SysTick wrap.
br_hal_timer_set_alarm() only records the target time. The alarm and the round-robin tick are both checked in SysTick_Handler, which runs once per wrap. At the default 16 MHz clock that is about every 1.05 s. Sleep wake-ups and time-slice rotation on this port are therefore rounded up to the wrap period.
Host port
arch/host-x86-64/
Runs the kernel as a Linux process for testing.
- Tasks are
ucontext_tcontexts switched withswapcontext. - Time is read from
CLOCK_MONOTONIC. SIGALRMfromsetitimer(ITIMER_REAL)acts as the timer interrupt.- Interrupt disable and restore block and unblock
SIGALRMwithsigprocmask.