diff --git a/repos/base-sel4/src/core/target.inc b/repos/base-sel4/lib/mk/core.mk similarity index 100% rename from repos/base-sel4/src/core/target.inc rename to repos/base-sel4/lib/mk/core.mk index 66171da107..cd1d61af4e 100644 --- a/repos/base-sel4/src/core/target.inc +++ b/repos/base-sel4/lib/mk/core.mk @@ -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 + diff --git a/repos/base-sel4/src/core/boot_modules.s b/repos/base-sel4/src/core/boot_modules.s new file mode 100644 index 0000000000..53882f41ea --- /dev/null +++ b/repos/base-sel4/src/core/boot_modules.s @@ -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: diff --git a/repos/base-sel4/src/core/include/core_cspace.h b/repos/base-sel4/src/core/include/core_cspace.h index 8f6566a820..194fcd418b 100644 --- a/repos/base-sel4/src/core/include/core_cspace.h +++ b/repos/base-sel4/src/core/include/core_cspace.h @@ -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, }; diff --git a/repos/base-sel4/src/core/include/platform.h b/repos/base-sel4/src/core/include/platform.h index 6d9d23cef4..707c8a796a 100644 --- a/repos/base-sel4/src/core/include/platform.h +++ b/repos/base-sel4/src/core/include/platform.h @@ -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: diff --git a/repos/base-sel4/src/core/platform.cc b/repos/base-sel4/src/core/platform.cc index 3eeabfdf03..e1de333c6f 100644 --- a/repos/base-sel4/src/core/platform.cc +++ b/repos/base-sel4/src/core/platform.cc @@ -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_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(); } diff --git a/repos/base-sel4/src/core/target.mk b/repos/base-sel4/src/core/target.mk index 310689bf0c..2cafe50819 100644 --- a/repos/base-sel4/src/core/target.mk +++ b/repos/base-sel4/src/core/target.mk @@ -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) diff --git a/tool/run/boot_dir/sel4 b/tool/run/boot_dir/sel4 index 4a5d0652da..0a220a6106 100644 --- a/tool/run/boot_dir/sel4 +++ b/tool/run/boot_dir/sel4 @@ -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 }