Zephyr Nano and Microkernel Computer Science Engineering Department





![An Example Nanokernel Application char __stack fiber. Stack[STACKSIZE]; void fiber. Entry(void) { struct nano_sem An Example Nanokernel Application char __stack fiber. Stack[STACKSIZE]; void fiber. Entry(void) { struct nano_sem](https://slidetodoc.com/presentation_image_h2/c960b6d75b3d7b32d8285f80bdba7afe/image-6.jpg)







- Slides: 13
Zephyr Nano- and Micro-kernel Computer Science & Engineering Department Arizona State University Tempe, AZ 85287 Dr. Yann-Hang Lee yhlee@asu. edu (480) 727 -7507
Nano. Kernel q t. Nano _nanokernel -- The structure to manage all the threads in the nanokernel struct s_NANO { struct tcs *fiber; struct tcs *task; struct tcs *current; /* singly linked list of runnable fibers */ /* pointer to runnable task */ /* currently scheduled thread (fiber or task) */ #if defined(CONFIG_THREAD_MONITOR) struct tcs *threads; /* singly linked list of ALL fiber+tasks */ #endif unsigned nested; /* nested interrupt count */ char *common_isp; /* interrupt stack pointer base */ #if defined(CONFIG_NANO_TIMEOUTS) || defined(CONFIG_NANO_TIMERS) sys_dlist_t timeout_q; int 32_t task_timeout; #endif } t. NANO; CSE 530 EOSI Fall 2016 1
Zephyr Nanokernel Fiber and Task (1) q The fiber and task implementations are identical q To initialize a new thread from its stack space for both fiber threads and kernel tasks. void _new_thread(char *p. Stack. Mem, unsigned stack. Size, void *uk_task_ptr, _thread_entry_t p. Entry, void *parameter 1, void *parameter 2, void *parameter 3, int priority, unsigned options) (Zephyr/arch/x 86/core/thread. c) CSE 530 EOSI Fall 2016 struct tcs { struct tcs *link; uint 32_t flags; uint 32_t basepri; int prio; #ifdef CONFIG_THREAD_CUSTOM_DATA void *custom_data; #endif struct coop. Reg; struct preemp. Reg; #if defined(CONFIG_THREAD_MONITOR) struct __thread_entry *entry; struct tcs *next_thread; #endif #ifdef CONFIG_NANO_TIMEOUTS struct _nano_timeout; #endif #ifdef CONFIG_ERRNO int errno_var; #endif #ifdef CONFIG_MICROKERNEL void *uk_task_ptr; #endif }; 2
Zephyr Nanokernel Fiber and Task (2) q Task flags #define FIBER #define TASK #define INT_ACTIVE #define EXC_ACTIVE #define USE_FP #define USE_SSE #define PREEMPTIBLE #define ESSENTIAL #define NO_METRICS 0 0 x 1 0 x 2 0 x 4 0 x 10 0 x 20 0 x 100 0 x 200 0 x 400 /* 1 = task, 0 = fiber */ /* 1 = executing context is interrupt handler */ /* 1 = executing context is exception handler */ /* 1 = thread uses floating point unit */ /* 1 = thread uses SSEx instructions */ /* 1 = preemptible thread */ /* 1 = system thread that must not abort */ /* 1 = _Swap() not to update task metrics */ stack end q Task stack parameter 3 parameter 2 parameter 1 p. Entry EFALGS _thread_entry_wrapper v use memory area defined statically v include struct tcs and entry point in the stack q The stack when a new task is constructed by a call to _new_thread() 5 extra slots esp Task stack tcs CSE 530 EOSI Fall 2016 p. Stack. Mem 3
Zephyr Fiber q a lightweight, non-preemptible thread of execution q can be spawned by another fiber, by a task, or by the kernel during system initialization task_fiber_start(), fiber_start() v executable immediately or delayed v terminate by simply returning from its entry point function, or aborted v each fiber is anonymous, and cannot be directly referenced by other fibers or tasks once it has started executing. q Nanokernel services v timer – init, start, test, stop v semaphore Ø may be given by any context type: ISRs, fibers, or tasks. Ø taken in a blocking manner by a fiber or task. v data passing (FIFO, LIFO, stack, ring buffer) q Common kernel services v clock, atomic operations CSE 530 EOSI Fall 2016 4
An Example Nanokernel Application char __stack fiber. Stack[STACKSIZE]; void fiber. Entry(void) { struct nano_sem nano. Sem. Task; struct nano_timer; uint 32_t data[2] = {0, 0}; struct nano_sem nano. Sem. Fiber; nano_sem_init(&nano. Sem. Fiber); nano_timer_init(&timer, data); while (1) { /* wait for task to let us have a turn */ nano_fiber_sem_take(&nano. Sem. Fiber, TICKS_UNLIMITED); PRINT("%s: Hello World!n", __func__); nano_fiber_timer_start(&timer, SLEEPTICKS); nano_fiber_timer_test(&timer, TICKS_UNLIMITED); nano_fiber_sem_give(&nano. Sem. Task); } } void main(void) { struct nano_timer; uint 32_t data[2] = {0, 0}; task_fiber_start(&fiber. Stack[0], STACKSIZE, (nano_fiber_entry_t) fiber. Entry, 0, 0, 7, 0) nano_sem_init(&nano. Sem. Task); nano_timer_init(&timer, data); while (1) { /* say "hello" */ PRINT("%s: Hello World!n", __func__); nano_task_timer_start(&timer, SLEEPTICKS); nano_task_timer_test(&timer, TICKS_UNLIMITED); nano_task_sem_give(&nano. Sem. Fiber); nano_task_sem_take(&nano. Sem. Task, TICKS_UNLIMITED); } } CSE 530 EOSI Fall 2016 5
Zephyr Starting Sequence q the entry that GRUB loader will jump to – __start() in arch/x 86/core/crt 0. S v initiate write-back cache, v disable interrupt and load IDT, v set up interrupt stack v clear out BSS double words v Jump to C portion of kernel initialization (jmp _Cstart) q _Cstart -- /kernel/nano_init. c v Initialize nanokernel data structure v initialize thread control block (tcs) for the main task by calling _new_thread() v perform basic hardware initialization v context switch to main task (i. e. _main()) -- _nano_fiber_swap(); v call _Swap() to begin _main task CSE 530 EOSI Fall 2016 6
_Swap() for Cooperative Context Switch q The caller disables interrupts, saves EFLAGS in stack q In _Swap() (/arch/x 86/core/swap. S) v save the current context (registers) onto the stack v save esp into current task’s tcs v schedule: Ø schedule the head of the runnable fiber * list (_nanokernel. fiber). Ø If there are no runnable fibers, then schedule * the task (_nanokernel. task) v recover the stack pointer for the incoming context (tcs->coop. Reg. esp) v restore the context from new stack esp return EIP esp EFLAGS return EIP %edi %esi %ebx %ebp EFLAGS return EIP esp entering _Swap() CSE 530 EOSI Fall 2016 if CONFIG_x 86_IAMCU %ebx before saving %esp 7
Microkernel Objects q Examples: semaphores, mailboxes, timers, and tasks q Scope of objects -- public or private v public object is available for general use by all parts of the application. v private object is intended for use only by a specific part of the application. The object’s name is visible only to code within the file where the object is defined. q Use mdef file to define public objects q Use macro definition for private % TASK NAME PRIO ENTRY STACK GROUPS % ================= TASKA 7 task. A 2048 [EXE] TASKB 7 task. B 2048 [EXE] % SEMA NAME% ======= SEMA TASKASEM SEMA TASKBSEM objects DEFINE_TASK(PRIV_TASK, 10, priv_task_main, 800, EXE); v To make a private object visible extern const ktask_t PRIV_TASK; CSE 530 EOSI Fall 2016 8
An Example Microkernel Application /* application source -- Microkernel version of hello world demo has two tasks that utilize * semaphores and sleeps to take turns printing a greeting message */ #include <zephyr. h> #define SLEEPTIME 500 #define SLEEPTICKS (SLEEPTIME * sys_clock_ticks_per_sec / 1000) void hello. Loop(const char *taskname, ksem_t my. Sem, ksem_t other. Sem) { while (1) { task_sem_take(my. Sem, TICKS_UNLIMITED); PRINT("%s: Hello World!n", taskname); task_sleep(SLEEPTICKS); %prj. mdef task_sem_give(other. Sem); } } % Application : Hello demo void task. A(void) { % TASK NAME PRIO ENTRY STACK GROUPS task_sem_give(TASKASEM); % ================= TASKA 7 task. A 2048 [EXE] hello. Loop(__func__, TASKASEM, TASKBSEM); TASKB 7 task. B 2048 [EXE] } % SEMA NAME% ======= void task. B(void) { SEMA TASKASEM hello. Loop(__func__, TASKBSEM, TASKASEM); SEMA TASKBSEM } CSE 530 EOSI Fall 2016 9
Generated Files for Zephyr Application Building q mdef file: Microkernel definition v define e defines all of the system’s public microkernel objects used in application, such as task, semaphore, timer, etc. v /Zephyr/Kbuild to generate /outdir/misc/generated/sysgen/prj. mdef v /Zephyr/scripts/sysgen (a python script) to generate kernel_main. c kernel_main. h (local copy) micro_private_types. h (local copy) sysgen. h v In kernel_main. c, stacks and tasks (struct k_task) are “defined”. char __noinit __stack __MAIN_stack[2048]; extern char main_task_stack[CONFIG_MAIN_STACK_SIZE]; EXTERN_C void main(void); struct k_task _k_task_obj_MAIN __in_section(_k_task_list, public, task) = {NULL, 10, (ktask_t)&_k_task_obj_MAIN, 0 x 00000001, 0 x 00000003, main, __MAIN_stack, 2048, (taskabortfunction)NULL, NULL}; ktask_t _k_task_ptr_MAIN __in_section(_k_task_ptr, public, task) = (ktask_t)&_k_task_obj_MAIN; CSE 530 EOSI Fall 2016 10
Microkernel Tasks q Note that v in _Cstart() calls Ø nano_init() Ø _sys_device_do_config_level(primary) v different _main() for microkernel q Microkernel initialization v _sys_device_do_config_level() v _k_init_dynamic() v task_fiber_start(_k_server_stack, …) v task_group_start(EXE_GROUP) /* Task control block for microkernel task*/ struct k_task { struct k_task *next; struct k_task *prev; kpriority_t priority; ktask_t id; uint 32_t state; uint 32_t group; void (*fn_start)(void); char *workspace; int worksize; void (*fn_abort)(void); struct k_args *args; }; q current task: _k_current_task q task_start() v send a cmd packet to kernel server fiber which calls start_task() where Ø _new_thread() to create context Ø _k_state_bit_reset() to clear (TF_STOP | TF_TERM), i. e. runnable CSE 530 EOSI Fall 2016 11
Microkernel Server Fiber q Microkernel server fiber to perform service requests from tasks (most operations on microkernel objects) v command packets queued on the microkernel server’s command stack. Ø irq_lock for push and pop operations v fiber is non-preemptable v can run critical section code for microkernel tasks. v automatically spawned with priority 0 (highest) in _main of microkernel task A command packet result command stack microkernel server fiber task B v when the command stack is empty, determine which task to run and then calls _swap(imask) q Task ready lists accessed by next_task_select() struct k_tqhd _k_task_priority_list[16] = {……}; // 16 task queue header uint 32_t _k_task_priority_bitmap[1] = {(1 u << 15)}; // bitmap for task queues CSE 530 EOSI Fall 2016 12