sel4: move core to a libaray, add boot_modules.s

This commit is contained in:
Norman Feske 2015-05-11 18:55:30 +02:00 committed by Christian Helmuth
parent 51f02340b6
commit f19f454ae5
7 changed files with 362 additions and 42 deletions
repos/base-sel4
tool/run/boot_dir

View File

@ -31,7 +31,6 @@ SRC_CC += \
context_area.cc \
capability_space.cc
LIBS += core_printf base-common syscall
INC_DIR += $(REP_DIR)/src/core/include \
@ -57,3 +56,4 @@ vpath dataspace_component.cc $(GEN_CORE_DIR)
vpath core_mem_alloc.cc $(GEN_CORE_DIR)
vpath dump_alloc.cc $(GEN_CORE_DIR)
vpath %.cc $(REP_DIR)/src/core

View File

@ -0,0 +1,32 @@
/*
* \brief Dummy boot-modules-file for building standalone images of core
* \author Martin Stein
* \date 2011-12-16
*/
/*
* Copyright (C) 2011-2014 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
.section .data
.global _boot_modules_headers_begin
_boot_modules_headers_begin:
/* no headers */
.global _boot_modules_headers_end
_boot_modules_headers_end:
.section .data.boot_modules_binaries
.global _boot_modules_binaries_begin
_boot_modules_binaries_begin:
/* no binaries */
.global _boot_modules_binaries_end
_boot_modules_binaries_end:

View File

@ -32,12 +32,12 @@ class Genode::Core_cspace
/* selectors for statically created CNodes */
enum Static_cnode_sel {
TOP_CNODE_SEL = 0x200,
CORE_PAD_CNODE_SEL = 0x201,
CORE_CNODE_SEL = 0x202,
PHYS_CNODE_SEL = 0x203,
CORE_VM_PAD_CNODE_SEL = 0x204,
CORE_VM_CNODE_SEL = 0x205,
TOP_CNODE_SEL = 0xa00,
CORE_PAD_CNODE_SEL = 0xa01,
CORE_CNODE_SEL = 0xa02,
PHYS_CNODE_SEL = 0xa03,
CORE_VM_PAD_CNODE_SEL = 0xa04,
CORE_VM_CNODE_SEL = 0xa05,
CORE_STATIC_SEL_END,
};

View File

@ -32,11 +32,22 @@ class Genode::Platform : public Platform_generic
typedef Core_mem_allocator::Phys_allocator Phys_allocator;
Core_mem_allocator _core_mem_alloc; /* core-accessible memory */
Phys_allocator _io_mem_alloc; /* MMIO allocator */
Phys_allocator _io_port_alloc; /* I/O port allocator */
Phys_allocator _irq_alloc; /* IRQ allocator */
Rom_fs _rom_fs; /* ROM file system */
/*
* Allocator for tracking unused physical addresses, which is used
* to allocate a range within the phys CNode for ROM modules.
*/
Phys_allocator _unused_phys_alloc;
void _init_unused_phys_alloc();
bool const _init_unused_phys_alloc_done;
Rom_fs _rom_fs; /* ROM file system */
/**
* Shortcut for physical memory allocator
@ -52,8 +63,8 @@ class Genode::Platform : public Platform_generic
/**
* Initialize core allocators
*/
void _init_allocators();
bool _init_allocators_done;
void _init_allocators();
bool const _init_allocators_done;
/*
* Until this point, no interaction with the seL4 kernel was needed.
@ -62,7 +73,7 @@ class Genode::Platform : public Platform_generic
* need to initialize the TLS mechanism that is used to find the IPC
* buffer for the calling thread.
*/
bool _init_sel4_ipc_buffer_done;
bool const _init_sel4_ipc_buffer_done;
/* allocate 1st-level CNode */
Cnode _top_cnode { seL4_CapInitThreadCNode, Core_cspace::TOP_CNODE_SEL,
@ -91,8 +102,8 @@ class Genode::Platform : public Platform_generic
/**
* Replace initial CSpace with custom CSpace layout
*/
void _switch_to_core_cspace();
bool _switch_to_core_cspace_done;
void _switch_to_core_cspace();
bool const _switch_to_core_cspace_done;
Page_table_registry _core_page_table_registry;
@ -101,12 +112,12 @@ class Genode::Platform : public Platform_generic
* about the initial page tables and page frames as set up by the
* kernel
*/
void _init_core_page_table_registry();
bool _init_core_page_table_registry_done;
void _init_core_page_table_registry();
bool const _init_core_page_table_registry_done;
Vm_space _core_vm_space;
int _init_rom_fs();
void _init_rom_modules();
public:

View File

@ -35,6 +35,23 @@ static bool const verbose_boot_info = true;
extern unsigned _prog_img_beg, _prog_img_end;
/******************
** Boot modules **
******************/
struct Boot_module_header
{
char const *name; /* physical address of null-terminated string */
addr_t const base; /* physical address of module data */
size_t const size; /* size of module data in bytes */
};
extern Boot_module_header _boot_modules_headers_begin;
extern Boot_module_header _boot_modules_headers_end;
extern int _boot_modules_binaries_begin;
extern int _boot_modules_binaries_end;
/****************************************
** Support for core memory management **
****************************************/
@ -62,10 +79,18 @@ bool Core_mem_allocator::Mapped_mem_allocator::_unmap_local(addr_t virt_addr,
** Platform interface **
************************/
void Platform::_init_unused_phys_alloc()
{
_unused_phys_alloc.add_range(0, ~0UL);
}
/**
* Initialize allocator with untyped memory ranges according to the boot info
*/
static void init_allocator(Range_allocator &alloc, seL4_BootInfo const &bi,
static void init_allocator(Range_allocator &alloc,
Range_allocator &unused_phys_alloc,
seL4_BootInfo const &bi,
unsigned const start_idx, unsigned const num_idx)
{
for (unsigned i = start_idx; i < start_idx + num_idx; i++) {
@ -77,6 +102,8 @@ static void init_allocator(Range_allocator &alloc, seL4_BootInfo const &bi,
size_t const size = 1UL << bi.untypedSizeBitsList[k];
alloc.add_range(base, size);
unused_phys_alloc.remove_range(base, size);
}
}
@ -95,11 +122,13 @@ void Platform::_init_allocators()
_irq_alloc.add_range(0, 255);
/* physical memory ranges */
init_allocator(*_core_mem_alloc.phys_alloc(), bi, bi.untyped.start,
init_allocator(*_core_mem_alloc.phys_alloc(), _unused_phys_alloc,
bi, bi.untyped.start,
bi.untyped.end - bi.untyped.start);
/* I/O memory ranges */
init_allocator(_io_mem_alloc, bi, bi.deviceUntyped.start,
init_allocator(_io_mem_alloc, _unused_phys_alloc,
bi, bi.deviceUntyped.start,
bi.deviceUntyped.end - bi.deviceUntyped.start);
/* core's virtual memory */
@ -114,7 +143,7 @@ void Platform::_init_allocators()
* attempt to map a page frame.
*/
addr_t const core_virt_beg = trunc_page((addr_t)&_prog_img_beg),
core_virt_end = round_page((addr_t)&_prog_img_end)
core_virt_end = round_page((addr_t)&_boot_modules_binaries_end)
+ 64*1024;
size_t const core_size = core_virt_end - core_virt_beg;
@ -159,6 +188,9 @@ void Platform::_switch_to_core_cspace()
for (unsigned sel = bi.deviceUntyped.start; sel < bi.deviceUntyped.end; sel++)
_core_cnode.copy(initial_cspace, sel);
for (unsigned sel = bi.userImageFrames.start; sel < bi.userImageFrames.end; sel++)
_core_cnode.copy(initial_cspace, sel);
/* copy statically created CNode selectors to core's CNode */
_core_cnode.copy(initial_cspace, Core_cspace::TOP_CNODE_SEL);
_core_cnode.copy(initial_cspace, Core_cspace::CORE_PAD_CNODE_SEL);
@ -225,10 +257,90 @@ void Platform::_init_core_page_table_registry()
}
void Platform::_init_rom_modules()
{
seL4_BootInfo const &bi = sel4_boot_info();
/*
* Slab allocator for allocating 'Rom_module' meta data.
*/
static long slab_block[4096];
static Tslab<Rom_module, sizeof(slab_block)>
rom_module_slab(core_mem_alloc(), (Genode::Slab_block *)slab_block);;
/*
* Allocate unused range of phys CNode address space where to make the
* boot modules available.
*/
void *out_ptr = nullptr;
size_t const modules_size = (addr_t)&_boot_modules_binaries_end
- (addr_t)&_boot_modules_binaries_begin + 1;
Range_allocator::Alloc_return const alloc_ret =
_unused_phys_alloc.alloc_aligned(modules_size, &out_ptr, get_page_size_log2());
if (alloc_ret.is_error()) {
PERR("could not reserve phys CNode space for boot modules");
struct Init_rom_modules_failed { };
throw Init_rom_modules_failed();
}
/*
* Calculate frame frame selector used to back the boot modules
*/
addr_t const unused_range_start = (addr_t)out_ptr;
addr_t const unused_first_frame_sel = unused_range_start >> get_page_size_log2();
addr_t const modules_start = (addr_t)&_boot_modules_binaries_begin;
addr_t const modules_core_offset = modules_start
- (addr_t)&_prog_img_beg;
addr_t const modules_first_frame_sel = bi.userImageFrames.start
+ (modules_core_offset >> get_page_size_log2());
Boot_module_header const *header = &_boot_modules_headers_begin;
for (; header < &_boot_modules_headers_end; header++) {
/* offset relative to first module */
addr_t const module_offset = header->base - modules_start;
addr_t const module_offset_frames = module_offset >> get_page_size_log2();
size_t const module_size = round_page(header->size);
addr_t const module_frame_sel = modules_first_frame_sel
+ module_offset_frames;
size_t const module_num_frames = module_size >> get_page_size_log2();
/*
* Destination frame within phys CNode
*/
addr_t const dst_frame = unused_first_frame_sel + module_offset_frames;
/*
* Install the module's frame selectors into phys CNode
*/
Cnode_base const initial_cspace(seL4_CapInitThreadCNode, 32);
for (unsigned i = 0; i < module_num_frames; i++)
_phys_cnode.copy(initial_cspace, module_frame_sel + i, dst_frame + i);
PLOG("boot module '%s' (%zd bytes)", header->name, header->size);
/*
* Register ROM module, the base address refers to location of the
* ROM module within the phys CNode address space.
*/
Rom_module * rom_module = new (rom_module_slab)
Rom_module(dst_frame << get_page_size_log2(), header->size,
(const char*)header->name);
_rom_fs.insert(rom_module);
}
}
Platform::Platform()
:
_io_mem_alloc(core_mem_alloc()), _io_port_alloc(core_mem_alloc()),
_irq_alloc(core_mem_alloc()),
_unused_phys_alloc(core_mem_alloc()),
_init_unused_phys_alloc_done((_init_unused_phys_alloc(), true)),
_vm_base(0x1000),
_vm_size(2*1024*1024*1024UL - _vm_base), /* use the lower 2GiB */
_init_allocators_done((_init_allocators(), true)),
@ -244,19 +356,19 @@ Platform::Platform()
Core_cspace::CORE_VM_ID,
_core_page_table_registry)
{
/* XXX add boot modules to ROM fs */
/*
* Print statistics about allocator initialization
*/
printf("VM area at [%08lx,%08lx)\n", _vm_base, _vm_base + _vm_size);
if (verbose_boot_info) {
printf(":phys_alloc: "); _core_mem_alloc.phys_alloc()->raw()->dump_addr_tree();
printf(":virt_alloc: "); _core_mem_alloc.virt_alloc()->raw()->dump_addr_tree();
printf(":io_mem_alloc: "); _io_mem_alloc.raw()->dump_addr_tree();
printf(":phys_alloc: "); _core_mem_alloc.phys_alloc()->raw()->dump_addr_tree();
printf(":unused_phys_alloc:"); _unused_phys_alloc.raw()->dump_addr_tree();
printf(":virt_alloc: "); _core_mem_alloc.virt_alloc()->raw()->dump_addr_tree();
printf(":io_mem_alloc: "); _io_mem_alloc.raw()->dump_addr_tree();
}
_init_rom_modules();
}

View File

@ -1 +1,13 @@
include $(PRG_DIR)/target.inc
TARGET = core
LIBS += core
SRC_S = boot_modules.s
# XXX hack, based on base-hw/lib/mk/core.mk
ifneq ($(wildcard $(BUILD_BASE_DIR)/boot_modules.s),)
BOOT_MODULES_VPATH = $(BUILD_BASE_DIR)
INC_DIR += $(BOOT_MODULES_VPATH)
else
# use dummy boot-modules by default
BOOT_MODULES_VPATH = $(REP_DIR)/src/core/
endif
vpath boot_modules.s $(BOOT_MODULES_VPATH)

View File

@ -1,15 +1,165 @@
#
# Based on boot_dir/hw
#
##
# Populate directory with binaries on seL4
# Ensure that the next Genode build includes no target specific boot modules
#
proc clean_boot_modules { } {
exec rm -rf boot_modules.s var/libcache/boot_modules/boot_modules.o }
proc run_boot_dir_hook { } {
clean_boot_modules
}
proc run_boot_string { } {
return "kernel initialized"
}
##
# Populate boot directory with binaries on hw
#
proc run_boot_dir {binaries} {
#
# Collect contents of the ISO image
#
# adapt to wether this is a core-internal test or a common scenario
global core_test
if {[info exists core_test]} {
set core_bin "test-[run_name]"
set core_target "test/[run_name]"
} else {
set core_bin "core"
set core_target "core"
}
# strip binaries
copy_and_strip_genode_binaries_to_run_dir $binaries
build { kernel }
exec cp bin/sel4 [run_dir]/sel4
# append init config
if {[file exists "[run_dir]/genode/config"] == 1} {
append binaries " config"
}
#
# Compose a platform specific assembly file 'boot_modules.s', that
# enables the creation of a single boot image. The file rawly includes
# all binaries given in 'binaries', minus 'core', if given, plus 'config',
# if available. It also provides a simple file system, that enables Genode
# to access these BLOBs. To build a single image this file is simply
# linked against core. To build core stand-alone this file is substituted
# by a dummy version. 'boot_modules.s' must be composed on demand, because
# it depends on the individual run scenario.
#
set boot_modules "[run_dir]/boot_modules.s"
if {[have_spec "64bit"]} {
set address_type ".quad"
} else {
set address_type ".long"
}
# introduce boot module headers
exec echo -e \
"/*" \
"\n * This file was automatically generated by the procedure" \
"\n * 'run_boot_dir' in 'tool/run/boot_dir/sel4'." \
"\n */" \
"\n" \
"\n /* alignment constraints */" \
"\n .set MIN_PAGE_SIZE_LOG2, 12" \
"\n .set DATA_ACCESS_ALIGNM_LOG2, 2" \
"\n" \
"\n.section .data" \
"\n" \
"\n.p2align DATA_ACCESS_ALIGNM_LOG2" \
"\n.global _boot_modules_headers_begin" \
"\n_boot_modules_headers_begin:" > $boot_modules
# generate header for each boot module except core
set i 1
foreach binary $binaries {
if {$binary == $core_bin} { continue }
exec echo -e \
"\n${address_type} _boot_module_${i}_name" \
"\n${address_type} _boot_module_${i}_begin" \
"\n${address_type} _boot_module_${i}_end -" \
" _boot_module_${i}_begin" >> $boot_modules
incr i
}
# end boot module headers
exec echo -e \
"\n.global _boot_modules_headers_end" \
"\n_boot_modules_headers_end:" >> $boot_modules
# generate name string for each module except core
set i 1
foreach binary $binaries {
if {$binary == $core_bin} { continue }
exec echo -e \
"\n.p2align DATA_ACCESS_ALIGNM_LOG2" \
"\n_boot_module_${i}_name:" \
"\n.string \"${binary}\"" \
"\n.byte 0" >> $boot_modules
incr i
}
exec echo -e \
"\n.section .data.boot_modules_binaries" \
"\n" \
"\n.global _boot_modules_binaries_begin" \
"\n_boot_modules_binaries_begin:" >> $boot_modules
# include raw data of modules consecutively but page aligned
set i 1
foreach binary $binaries {
if {$binary == $core_bin} { continue }
exec echo -e \
"\n.p2align MIN_PAGE_SIZE_LOG2" \
"\n_boot_module_${i}_begin:" \
"\n.incbin \"[run_dir]/genode/${binary}\"" \
"\n_boot_module_${i}_end:" >> $boot_modules
incr i
}
# finish boot modules file
exec echo -e \
"\n.global _boot_modules_binaries_end" \
"\n_boot_modules_binaries_end:" >> $boot_modules
clean_boot_modules
exec ln -s $boot_modules boot_modules.s
# recompile core with boot modules
exec cp -L bin/$core_bin $core_target/$core_bin.standalone
exec find . -type f -name $core_bin -delete
set timeout 10000
set pid [eval "spawn make $core_target"]
expect { eof { } }
if {[lindex [wait $pid] end] != 0} {
clean_boot_modules
puts stderr "Error: Genode build failed"
exit -1
}
clean_boot_modules
exec rm -rf "[run_dir]/genode"
# offer ELF image
set elf_img "[run_dir]/image.elf"
if {[have_spec "x86_64"]} {
# as startup is done in 32 bit mode, GRUB expects a 32 bit image
exec [cross_dev_prefix]objcopy -O elf32-i386 bin/$core_bin $elf_img
}
if {[expr [have_spec "arm"] || [have_spec "x86_32"]]} {
exec cp -L bin/$core_bin $elf_img
}
exec [cross_dev_prefix]strip $elf_img
if {[have_include "image/iso"] || [have_include "image/disk"]} {
#
# Install isolinux/GRUB files and bender
@ -24,20 +174,23 @@ proc run_boot_dir {binaries} {
puts $fh "default 0"
puts $fh "\ntitle Genode on seL4"
puts $fh " kernel /sel4"
puts $fh " module /image.elf"
# if only one binary was specified, use it as root task
if {[llength $binaries] == 1} {
puts $fh " module /genode/[lindex $binaries 0]"
# for real scenarios, use core as root task
} else {
puts $fh " module /genode/core"
}
close $fh
}
#
# Build image
#
run_image
run_image $elf_img
# set symbolic link to image.elf file in TFTP directory for PXE boot
if {[have_include "load/tftp"]} {
exec ln -sf [pwd]/$elf_img [load_tftp_base_dir][load_tftp_offset_dir]
if {[have_include "image/uboot"]} {
exec ln -sf [pwd]/[run_dir]/uImage [load_tftp_base_dir][load_tftp_offset_dir]
}
}
# retrieve stand-alone core
exec cp $core_target/$core_bin.standalone bin/$core_bin
exec rm $core_target/$core_bin.standalone
}