sel4: print boot info

This commit is contained in:
Norman Feske 2014-10-16 20:29:41 +02:00 committed by Christian Helmuth
parent 6b9185ab34
commit 52c4dc8ec8
3 changed files with 189 additions and 8 deletions

View File

@ -18,7 +18,7 @@ a modern microkernel jointly developed by NICTA and General Dynamics.
A fresh Genode source-code repository
=====================================
#####################################
Following the convention to host each kernel in its dedicated _base-<kernel>_
source repository, the seL4-specific code will go to _base-sel4_. This way,
@ -65,7 +65,7 @@ _contrib/sel4-<hash>/src/kernel/sel4_.
Building the kernel for the first time
======================================
######################################
For getting acquainted with the code base, the README.md file provides a
good starting point. It seems to contain exactly the information that I need
@ -207,7 +207,7 @@ directory of the kernel.
Starting the kernel in Qemu
===========================
###########################
To test-drive the kernel, we need to create a bootable image including a boot
loader, the boot-loader configuration, and the kernel. To spare us the
@ -291,7 +291,7 @@ a root task to the system.
A root task for exercising the kernel interface
===============================================
###############################################
At this point, there are two options. We could either start with a very
minimalistic hello-world program that is completely unrelated to Genode. Such
@ -611,7 +611,7 @@ the statement '*(int *)0x1122 = 0;'
Issuing the first system call
=============================
#############################
We have successfully started our custom root task but we have not interacted
with the kernel yet. So it is time to take a look at seL4's system-call
@ -818,3 +818,115 @@ When running it via 'make run/test', it produces the expected result:
! int main(): a message printed via Genode's PDBG
Exploration of the kernel interface
###################################
Now that we have a nice playground in place, it is time to explore the
actual kernel interface step by step. The goal is to get a tangible
feeling for the kernel and to exercise the functionality that is needed
by Genode. Those functionalities are:
* Access to boot information such as the memory layout and the boot modules
* Multi-threading
* Process-local synchronization
* Synchronous inter-process communication between threads
* Address-space creation
* Page-fault handling
At this point, it is useful to take a look at the excellent seL4 reference
manual to learn the concepts behind the kernel interface:
:[http://sel4.systems/Docs/seL4-manual.pdf]:
seL4 reference manual
Obtaining boot information
==========================
The manual mentions the function 'seL4_GetBootInfo' to obtain a pointer to
a boot-info structure. The function implementation, however, requires a
prior all of 'seL4_InitBootInfo' from the startup code. According to the
manual, the startup code gets the pointer passed in a CPU register. It
presumably registers this pointer via 'seL4_InitBootInfo'. Of course, we
don't want to change Genode's kernel-agnostic startup code by inserting
a call to the 'seL4_InitBootInfo' function. Fortunately, this is not the
first time, Genode has to pick up a register value passed by the kernel to
root task via a CPU register. The startup code already saves the initial
stack pointer, EAX and EDI. The seL4 manual does not state, which register
is used. In the kernel code ('create_initial_thread'), the register is denoted
at "capRegister". A look into _ia32/arch/machine/registerset.h_ reveals that
this register is actually EBX on the x86 architecture. Since EBX is not
saved by Genode's startup code yet, we need to enhance the startup code
a bit to save the initial EBX value in the variable '_initial_bx'.
The boot-info type is declared in _sel4/bootinfo.h_. When including the
header, we have to expand our _sel4/stdint.h_ version by a definition
of 'uint8_t'. Also, the header expects CONFIG_MAX_NUM_BOOTINFO_UNTYPED_CAPS
to be defined. We are just using the kernel's default config value, which
we copy to our _sel4/autoconf.h_ file.
! #define CONFIG_MAX_NUM_BOOTINFO_UNTYPED_CAPS 800
With those changes in place, we can access the boot info with a utility like
this:
! #include <sel4/bootinfo.h>
!
! static seL4_BootInfo const *boot_info()
! {
! extern Genode::addr_t __initial_bx;
! return (seL4_BootInfo const *)__initial_bx;
! }
While writing a simple 'dump_boot_info' function, I noticed that some boot-info
fields mentioned in the manual and present on the master branch, have
disappeared in the experimental branch, i.e., 'numDeviceRegions'.
Anyway, the output of 'dump_boot_info' function looks like this:
! --- boot info at 102c000 ---
! ipcBuffer: 102b000
! initThreadCNodeSizeBits: 12
! untyped: [38,4d)
! [38] [00100000,00107fff]
! [39] [00108000,00109fff]
! [3a] [001a0000,001bffff]
! [3b] [001c0000,001fffff]
! [3c] [00200000,003fffff]
! [3d] [00400000,007fffff]
! [3e] [00800000,00ffffff]
! [3f] [01000000,01ffffff]
! [40] [02000000,02ffffff]
! [41] [03000000,037fffff]
! [42] [03800000,03bfffff]
! [43] [03c00000,03dfffff]
! [44] [03e00000,03efffff]
! [45] [03f00000,03f7ffff]
! [46] [03f80000,03fbffff]
! [47] [03fc0000,03fdffff]
! [48] [03fe0000,03feffff]
! [49] [03ff0000,03ff7fff]
! [4a] [03ff8000,03ffbfff]
! [4b] [03ffc000,03ffdfff]
! [4c] [00189000,001897ff]
Creating a thread
=================
On seL4, kernel objects are created by turning untyped memory into kernel
memory using the 'seL4_Untype_Retype' function. As a first test. I am going to
manually define the parameters for this function using the information from
the boot info.
But before I can start using this function, we first need to generate some
stub code. We need to generate _sel4/invocation.h_ and its corresponding
_sel4/arch/invocation.h_. The rules in the platform library are quickly added,
taking the seL4 Makefile as inspiration. We also need to generate the
_interfaces/sel4_client.h_ stub code. In the stub code, we find the function
'seL4_Untyped_RetypeAtOffset', which pretty much matches the signature of
'seL4_Untype_Retype' explained in the manual. This is just another difference
from the master branch.

View File

@ -21,14 +21,15 @@ LIBSEL4_DIR := $(call select_from_ports,sel4)/src/kernel/sel4/libsel4
#
SEL4_ARCH_INCLUDES := objecttype.h types.h bootinfo.h constants.h functions.h \
pfIPC.h syscalls.h exIPC.h
pfIPC.h syscalls.h exIPC.h invocation.h
SEL4_INCLUDES := objecttype.h types.h bootinfo.h errors.h constants.h \
messages.h sel4.h benchmark.h types.bf macros.h \
types_gen.h syscall.h
types_gen.h syscall.h invocation.h
SEL4_INCLUDE_SYMLINKS += $(addprefix $(BUILD_BASE_DIR)/include/sel4/, $(SEL4_INCLUDES))
SEL4_INCLUDE_SYMLINKS += $(addprefix $(BUILD_BASE_DIR)/include/sel4/arch/,$(SEL4_ARCH_INCLUDES))
SEL4_INCLUDE_SYMLINKS += $(BUILD_BASE_DIR)/include/sel4/interfaces/sel4_client.h
SEL4_INCLUDE_DIRS = $(sort $(dir $(SEL4_INCLUDE_SYMLINKS)))
@ -61,5 +62,22 @@ $(BUILD_BASE_DIR)/include/sel4/syscall.h: $(LIBSEL4_DIR)/include/api/syscall.xml
$(VERBOSE)python $(LIBSEL4_DIR)/tools/syscall_header_gen.py \
--xml $< --libsel4_header $@
$(BUILD_BASE_DIR)/include/sel4/invocation.h: $(LIBSEL4_DIR)/include/interfaces/sel4.xml
$(MSG_CONVERT)$(notdir $@)
$(VERBOSE)python $(LIBSEL4_DIR)/tools/invocation_header_gen.py \
--xml $< --libsel4 --dest $@
$(BUILD_BASE_DIR)/include/sel4/arch/invocation.h: $(LIBSEL4_DIR)/arch_include/ia32/interfaces/sel4arch.xml
$(MSG_CONVERT)arch/$(notdir $@)
$(VERBOSE)python $(LIBSEL4_DIR)/tools/invocation_header_gen.py \
--xml $< --libsel4 --arch --dest $@
SEL4_CLIENT_H_SRC := $(LIBSEL4_DIR)/include/interfaces/sel4.xml \
$(LIBSEL4_DIR)/arch_include/ia32/interfaces/sel4arch.xml
$(BUILD_BASE_DIR)/include/sel4/interfaces/sel4_client.h: $(SEL4_CLIENT_H_SRC)
$(MSG_CONVERT)$(notdir $@)
$(VERBOSE)python $(LIBSEL4_DIR)/tools/syscall_stub_gen.py \
-a ia32 -o $@ $(SEL4_CLIENT_H_SRC)
endif

View File

@ -13,10 +13,61 @@
/* Genode includes */
#include <base/printf.h>
#include <base/stdint.h>
#include <util/string.h>
/* seL4 includes */
#include <sel4/bootinfo.h>
static seL4_BootInfo const *boot_info()
{
extern Genode::addr_t __initial_bx;
return (seL4_BootInfo const *)__initial_bx;
}
static void dump_untyped_ranges(seL4_BootInfo const &bi,
unsigned start, unsigned size)
{
for (unsigned i = start; i < start + size; i++) {
/* index into 'untypedPaddrList' */
unsigned const k = i - bi.untyped.start;
PINF(" [%02x] [%08lx,%08lx]",
i,
(long)bi.untypedPaddrList[k],
(long)bi.untypedPaddrList[k] + (1UL << bi.untypedSizeBitsList[k]) - 1);
}
}
static void dump_boot_info(seL4_BootInfo const &bi)
{
PINF("--- boot info at %p ---", &bi);
PINF("ipcBuffer: %p", bi.ipcBuffer);
PINF("initThreadCNodeSizeBits: %d", (int)bi.initThreadCNodeSizeBits);
PINF("untyped: [%x,%x)", bi.untyped.start, bi.untyped.end);
dump_untyped_ranges(bi, bi.untyped.start,
bi.untyped.end - bi.untyped.start);
PINF("deviceUntyped: [%x,%x)",
bi.deviceUntyped.start, bi.deviceUntyped.end);
dump_untyped_ranges(bi, bi.deviceUntyped.start,
bi.deviceUntyped.end - bi.deviceUntyped.start);
}
extern char _bss_start, _bss_end;
int main()
{
PDBG("a message printed via Genode's PDBG");
seL4_BootInfo const *bi = boot_info();
dump_boot_info(*bi);
*(int *)0x1122 = 0;
return 0;