Codezero (L4 microkernel) developer starting guide
Forum » Personal / Blog » Codezero (L4 microkernel) developer starting guide
Started by: dpcdpc
On: 1266714954|%e %b %Y, %H:%M %Z|agohover
Number of posts: 1
rss icon RSS: New posts
Summary:
Concept of microkernel was one of those ideas that I've had fallen in love at the first sight. It's a beauty of KISS rule applied to kernel programming. I'm especially interested in the modern, so called second generation microkernel, called L4 . I've was researching a subject for a long time, but never actually got my hands dirty with it. It always seemed to hard to start developing such creature - set up development environment, understand how things work or write the code from scratch. Finally - I've reached a point where I'm able to work with L4 kernel. And I'd like to write down my experience so that others can at least research the subject and play with it for fun or more meaningful goals. If you'd like to start working with L4 yourself - go ahead and read this article.
Codezero (L4 microkernel) developer starting guide
dpcdpc 1266714954|%e %b %Y, %H:%M %Z|agohover

Introduction

So you'd like to start developing a microkernel? To do so you obviously need to have some experience with:

  • C programming
  • low level computer fundamentals

and have some UNIX (possibly Linux) installed.

If you don't know what L4 is, please read a wikipedia page about L4 microkernel family.

To start working with L4 you'll first have to understand how it works. The good starting point is L4 User Manual by Ihor Kuz from NICTA.

Due to its nature L4 perfectly matches the requirements of modern embedded systems. And now days almost all embedded systems are targeting the ARM architecture. The ARM reference manual contains all the information you could possibly need working with this architecture. However if this subject is completely new for you - you should probably search for more beginner-friendly documentation.

Implementation

There are several implementations of L4 out there, but the one that I've looked for to start playing with had to be:

  • Open Sourced
  • written in C & assembler
  • easy to start playing with

After some time I've discovered Codezero Embedded Hypervizor and OS. As this project is quite new its codebase is not that overwhelming for a newcomer, however complete enough to give working and efficient starting point for my microkernel developing journey. Developers seem to put a lot of effort to maintain really well structured and clean code which seems very good for a project from which I'd like to learn.

Starting

While the Codezero Starting Guide is a good starting point and most of the time really useful it has some problems too: it's too lengthy and time consuming to follow and it contains some mistakes. That's why I've decided to automate all the work and set up my own Codezero git fork for newcomers. The init-build-env branch is where I accumulate all the changes that make life easier for a Codezero newcomer like me. With this changes you should be able to have L4 based project running in up to 30 minutes with most of the time spent on waiting for automated download and compilation process to complete.

Setting up tools and building codezero

To start just grab a copy of my Codezero's init-build-env repository with git:

git clone git@github.com:dpc/codezero.git

If you don't know what git is, how to run it or how it works - you should really spend some time getting familiar with it. Try Github's Introduction to Git.

So now, enter the project directory and run the tool script that will setup building environment for you:

cd codezero
./tools/init-build-env.sh

This script will do almost everything what is described in the Codezero's Getting Started page. It will download, build and install environment tools in [[~/opt/arm]] so that the only thing that you have to do (hopefully!) is to press enter once during installation, and add one directory to your PATH environment afterwards.

Just follow the process, install missing software if needed and rerun the script if required.

After successful execution you will have a build environment ready to build a codezero project.

First configure the project. The defaults are fine so just run:

./configure.py

and press q to save the settings.

To build the project run:

./build.py

If everything was prepared correctly the build process should create something like the following in the build directory:

codezero$ ls build
config.cml  configdata  config.h  config.rules  cont0  conts  final.elf  kernel.elf  loader  rules.compiled

Runing codezero

To run and debug Codezero we will use a Qemu to emulate a fully working ARM-based system for us. So you should have qemu installed:

codezero$ which qemu-system-arm
/usr/bin/qemu-system-arm

There are two options on how to debug the system:

  • plain gdb
  • insight frontend to gdb

As I don't like GUI applications in development process I'll describe using ./tools/run-qemu-gdb only. For Insight - you may use ./tools/run-qemu-insight - it does essentially the same thing.

So to make life easier link the script:

ln -s tools/run-qemu-insight gdb

and run it with:

./gdb

so you should get:

codezero$ ./gdb
Qemu started.
System serial console accessible via `telnet localhost 12445`
GNU gdb (Sourcery G++ Lite 2009q3-67) 6.8.50.20090630-cvs
Copyright (C) 2009 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "--host=i686-pc-linux-gnu --target=arm-none-linux-gnueabi".
For bug reporting instructions, please see:
<https://support.codesourcery.com/GNUToolchain/>.
QEMU 0.11.0 monitor - type 'help' for more information
(qemu) 0x00100000 in ?? ()
add symbol table from file "build/kernel.elf" at
        .text_addr = 0x8000
(gdb)

What have just happened?

The script started Qemu to emulate an ARM system for us with a Codezero kernel image loaded. The virtual machine is stopped and waiting for commands. Two network sockets were created by the Qemu - one for gdb to control and debug the system and second emulating ARM system serial console - which embedded systems usually use as a basic I/O system.

Then - right after qemu - gdb is being started with symbols loaded and connected to qemu virtual machine so we can navigate through the source code as it's being executed and control the execution.

To connect to the system serial console, open new terminal and run:

$ telnet localhost 12445
Trying ::1...
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.

Voila! You now have a L4 microkernel running in an ARM virtual machine and you're connected to it's serial port. Was not that hard, was it?

Initial debugging

As you may not know - the starting process for the Codezero is done in two steps. First - the loader is initializing the platform and then puts the kernel into the right place in the system's memory. Then it passes the execution to the kernel itself and gets out the way.

So, in the running gdb session try dissasemble command (or just dissas alias):

(gdb) disas
Dump of assembler code for function _start:
0x00100000 <_start+0>:  ldr     sp, [pc, #4]    ; 0x10000c <_start+12>
0x00100004 <_start+4>:  bl      0x102a8c <platform_init>
0x00100008 <_start+8>:  bl      0x1003a0 <main>
0x0010000c <_start+12>: andseq  lr, lr, r8, lsr #31
End of assembler dump.
(gdb)

It's here where everything starts. Corresponding code is in the loader/libs/c/crt/sys-userspace/arch-arm/crt0.S file and all the loader code is int the loader subdirectory. The starting point is written in the ARM assembler.

stepi will advance one CPU instruction forward. Run it two times, like this:

(gdb) stepi
0x00100004 in _start ()
(gdb) stepi
platform_init () at conts/libdev/uart/src/platform_init.c:56
56      {
(gdb)

As you may see the execution flow has reached the C code that is responsible for initializing the platform code. As we're now in the C code we can use list command to see the C code listing (or a l alias):

(gdb) l
51
52              return 0;
53      }
54
55      void platform_init(void)
56      {
57              uart.base = PL011_BASE;
58              pl011_initialise(&uart);
59      }
60
(gdb)

So we can see that platform_init function is doing only one thing here: initializing the UART.

As this is not a GDB tutorial I will not cover more about using gdb commands here. There are plenty of such tutorial on web - just look for it.

To advance to the point where the loaded gets out of the way do:

(gdb) tbreak arch_start_kernel
Temporary breakpoint 1 at 0x100374: file loader/main.c, line 103.
(gdb) c
Continuing.

Breakpoint 1, arch_start_kernel (entry=0x102aa8) at loader/main.c:103
103             printf("elf-loader:\tStarting kernel\n\r");
(gdb)

And then:

(gdb) l
98              return 0;
99      }
100
101     void arch_start_kernel(void *entry)
102     {
103             printf("elf-loader:\tStarting kernel\n\r");
104             void (*func)(unsigned long) = (void (*)(unsigned long)) (*(unsigned long*)entry);
105             func(0);
106     }
107
(gdb) n
103             printf("elf-loader:\tStarting kernel\n\r");
(gdb) n
arch_start_kernel (entry=0x102aa8) at loader/main.c:104
104             void (*func)(unsigned long) = (void (*)(unsigned long)) (*(unsigned long*)entry);
(gdb) n
105             func(0);
(gdb) n
0x00008000 in _start_text ()
(gdb)

You could be wondering at this point where are we. Well, we are at src/arch/arm/head.S on the line 27.

(gdb) disassemble                                                                                
Dump of assembler code for function _start_text:                                                 
0x00008000 <_start_text+0>:     msr     CPSR_fc, #19                                             
0x00008004 <_start_text+4>:     mrc     15, 0, r0, cr1, cr0, {0}                                 
0x00008008 <_start_text+8>:     bic     r0, r0, #1                                               
0x0000800c <_start_text+12>:    bic     r0, r0, #4                                               
0x00008010 <_start_text+16>:    bic     r0, r0, #4096   ; 0x1000                                 
0x00008014 <_start_text+20>:    bic     r0, r0, #8                                               
0x00008018 <_start_text+24>:    mcr     15, 0, r0, cr1, cr0, {0}                                 
0x0000801c <_start_text+28>:    ldr     sp, [pc, #40]   ; 0x804c <_kernel_init_stack>            
0x00008020 <_start_text+32>:    msr     CPSR_fc, #215   ; 0xd7                                   
0x00008024 <_start_text+36>:    ldr     sp, [pc, #36]   ; 0x8050 <_kernel_abt_stack>             
0x00008028 <_start_text+40>:    msr     CPSR_fc, #210   ; 0xd2                                   
0x0000802c <_start_text+44>:    ldr     sp, [pc, #32]   ; 0x8054 <_kernel_irq_stack>             
0x00008030 <_start_text+48>:    msr     CPSR_fc, #209   ; 0xd1                                   
0x00008034 <_start_text+52>:    ldr     sp, [pc, #28]   ; 0x8058 <_kernel_fiq_stack>             
0x00008038 <_start_text+56>:    msr     CPSR_fc, #219   ; 0xdb                                   
0x0000803c <_start_text+60>:    ldr     sp, [pc, #24]   ; 0x805c <_kernel_und_stack>             
0x00008040 <_start_text+64>:    msr     CPSR_fc, #211   ; 0xd3                                   
0x00008044 <_start_text+68>:    bl      0x1493c <start_kernel>                                   
0x00008048 <_start_text+72>:    b       0x8048 <_start_text+72>                                  
End of assembler dump.                                                                           
(gdb)

To skip this code use step. This will get us to the next C code:

(gdb) s
Single stepping until exit from function _start_text,
which has no line number information.
start_kernel () at src/glue/arm/init.c:295
295             printascii("\n"__KERNELNAME__": start kernel...\n");
(gdb) l
290             scheduler_start();
291     }
292
293     void start_kernel(void)
294     {
295             printascii("\n"__KERNELNAME__": start kernel...\n");
296
297             /*
298              * Initialise section mappings
299              * for the kernel area
(gdb)

Last words

I think this is enough to start with. You should now concentrate on using debugger, reading a source code and available documentation to learn how do the things work in the Codezero L4 microkernel.

It may take you some time, but I hope you will have much more enthusiasm now - with a working codebase and debugger - to learn about L4 and Codezero. And eventually you may start to contribute to this wonderful project yourself.

If you had any problems or you find anything not clear enough, just leave me a note in a comment and I'll try to help and correct any mistakes that I've made.

Last edited on 1266717142|%e %b %Y, %H:%M %Z|agohover By dpc + Show more
Reply  |  Options
Unfold Codezero (L4 microkernel) developer starting guide by dpcdpc, 1266714954|%e %b %Y, %H:%M %Z|agohover
New Post
Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-ShareAlike 3.0 License