How to Write A Simple Micro Kernel
Intro
Hello, everybody. You are here to learn how to write a simple micro kernel for ARMs. Last year, I wrote a very easy micro kernel which named Totoro, spent about two months in my spare time. I remember that i was very very excited when the kernel works. Maybe, like Linus Torvalds when he got the Linux running around. You can get more at Linux – a free unix-386 kernel .
I am very happy about this project. Now, let’s start!
Thread
Firstly, we need to understand the concept which named ‘thread’. A thread is combined with task status, task data. It can be paused, resumed, and stop. The main part of thread is called ‘context’. In this micro kernel, a thread, also as known TCB, is consist of register values of soc , like r0, r1, r2, … , pc, lr, sp and so on. The different part of threads is that they have their own procedure.
Context
As we have mentioned above, context is the most important part of thread. Context keeps the states of thread in RAM, and these states will be recovery by scheduler while task switch happens.
Simple Scheduler
A scheduler rules the working logics of the system it running on. Totoro supports robin schedule, high priority task preemption, events model programming.
Basic Data Structures
include/totoro/taskq.h
struct tasklist { struct ttr_tcb *tcb; struct tasklist *next; };
static struct tasklist *migrate(struct ttr_tcb *tcb, struct tasklist **src, struct tasklist **dst)
static void insert(struct tasklist *node, struct tasklist **list);
extern ttr_err_t task_enqueue(struct ttr_tcb *tcb);
extern struct ttr_tcb *task_next(void);
extern void task_init(void);
Task Structure
include/totoro/taskq.h
/* definition for Task(Thread) Control Block */ struct ttr_tcb { /* stack pointer */ volatile void *sp; /* current state of the thread */ uint8_t stat; /* priority of the thread */ uint8_t prior; /* thread's stack size */ uint32_t stack_size; /* thread's stack */ void *stack; /* thread function */ void (*ttr_thread)(void); };
Task Priorities
include/totoro/taskq.h
#define TASK_HIGHEST_PRIORITY ( 0 ) #define TASK_LOWEST_PRIORITY (255) #define TASK_DEFAULT_PRIORITY ( 1 )
Task Status
include/totoro/taskq.h
#define TASK_SUSPENDED ( 0 ) #define TASK_READY ( 1 ) #define TASK_RUNNING ( 2 )
Memag of Task Node
kernel/taskq.c
#define MALLOC_TASK_NODE(node, _tcb) \ ((node = (struct tasklist *)malloc(sizeof(struct tasklist))), \ (!!node ? (node->tcb = _tcb, TTR_ERR_OK) : TTR_ERR_MEM)) #define DELETE_TASK_NODE(node) \ if (node) { \ free(node); \ node->tcb = NULL; \ node = NULL; \ }
Context switch
arch/cortex-m0/gcc/port.S
cpsid i mrs r0, psp subs r0, #32 stmia r0!, {r4 - r11} subs r0, #32 ldr r2, =ttr_running_task ldr r1, [r2] str r0, [r1] ldr r1, =ttr_running_task ldr r2, =ttr_next_task ldr r3, [r2] str r3, [r1] ldr r2, =ttr_next_task ldr r1, [r2] ldr r0, [r1] ldmia r0!, {r4 - r11} msr psp, r0 ldr r0, =0xfffffffd cpsie i bx r0
Driver Interface
drivers/clock, drivers/gpio, drivers/serial
Semaphore
include/totoro/sem.h
extern int sem_signal(sem_t *sem); extern int sem_wait(sem_t *sem, uint32_t timeout);
Mutex
include/totoro/simplelock.h
#define simplelock_get() #define simplelock_put()
Softirq
include/totoro/softirq.h
kernel/timer.c
3 Test Cases
test/ab.c
test/sem.c
test/kt.c
To be continued…