hw: bootstrap into kernel

Put the initialization of the cpu cores, setup of page-tables, enabling of
MMU and caches into a separate component that is only used to bootstrap
the kernel resp. core.

Ref #2092
This commit is contained in:
Stefan Kalkowski
2016-11-07 18:00:24 +01:00
committed by Norman Feske
parent 8aa8423cfd
commit cf943dac65
178 changed files with 2818 additions and 1806 deletions

View File

@ -0,0 +1,24 @@
/*
* \brief Environment dummy implementation needed by cxx library
* \author Stefan Kalkowski
* \date 2016-09-23
*/
/*
* Copyright (C) 2016 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.
*/
/* base includes */
#include <base/env.h>
/* core includes */
#include <assert.h>
Genode::Env_deprecated * Genode::env_deprecated()
{
assert(false);
return nullptr;
}

View File

@ -0,0 +1,13 @@
TARGET = bootstrap
LIBS = bootstrap-hw
BOOTSTRAP_OBJ = bootstrap.o
$(TARGET): $(BOOTSTRAP_OBJ)
$(VERBOSE)true
.PHONY: $(BOOTSTRAP_OBJ)
$(BOOTSTRAP_OBJ):
$(VERBOSE)$(LD) $(LD_MARCH) -u _start --whole-archive -r $(LINK_ITEMS) $(LIBCXX_GCC) -o $@
clean cleanall:
$(VERBOSE)rm -f $(BOOTSTRAP_OBJ)

View File

@ -0,0 +1,142 @@
/*
* \brief Platform interface
* \author Stefan Kalkowski
* \date 2016-10-19
*/
/*
* Copyright (C) 2016-2017 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.
*/
#ifndef _PLATFORM_H_
#define _PLATFORM_H_
/* Genode includes */
#include <base/allocator_avl.h>
#include <base/internal/elf.h>
#include <util/reconstructible.h>
/* core includes */
#include <bootinfo.h>
#include <board.h>
#include <cpu.h>
#include <pic.h>
#include <rom_fs.h>
using Genode::addr_t;
using Genode::size_t;
using Genode::Bootinfo;
using Genode::Core_mmio;
using Genode::Mapping;
using Genode::Memory_region;
using Genode::Memory_region_array;
using Genode::Rom_module;
class Platform
{
private:
struct Board : Genode::Board
{
Memory_region_array early_ram_regions;
Memory_region_array late_ram_regions;
Core_mmio const core_mmio;
Board();
};
class Ram_allocator : public Genode::Allocator_avl_base
{
private:
using Base = Genode::Allocator_avl_base;
enum { BSZ = Genode::Allocator_avl::slab_block_size() };
Genode::Tslab<Base::Block, BSZ> _slab;
Genode::uint8_t _first_slab[BSZ];
public:
Ram_allocator()
: Genode::Allocator_avl_base(&_slab, sizeof(Base::Block)),
_slab(this, (Genode::Slab_block*)&_first_slab) {}
void * alloc_aligned(size_t size, unsigned align);
bool alloc(size_t size, void **out_addr) override;
void * alloc(size_t size) { return Allocator::alloc(size); }
void add(Memory_region const &);
void remove(Memory_region const &);
template <typename FUNC>
void for_each_free_region(FUNC functor)
{
_block_tree().for_each([&] (Block const & b)
{
if (!b.used())
functor(Genode::Memory_region(b.addr(), b.size()));
});
}
};
struct Pd
{
void * const table_base;
void * const allocator_base;
Bootinfo::Table & table;
Bootinfo::Table_allocator & allocator;
Bootinfo::Mapping_pool mappings;
Pd(Ram_allocator & alloc);
void map(Mapping m);
void map_insert(Mapping m);
};
struct Elf : Genode::Elf_binary
{
Elf(addr_t const addr) : Genode::Elf_binary(addr) { }
template <typename T> void for_each_segment(T functor)
{
Genode::Elf_segment segment;
for (unsigned i = 0; (segment = get_segment(i)).valid(); i++) {
if (segment.flags().skip) continue;
if (segment.mem_size() == 0) continue;
functor(segment);
}
}
};
Board board;
Genode::Cpu cpu;
Genode::Pic pic;
Ram_allocator ram_alloc;
Memory_region const bootstrap_region;
Genode::Constructible<Pd> core_pd;
addr_t core_elf_addr;
Elf core_elf;
addr_t _load_elf();
public:
Platform();
static addr_t mmio_to_virt(addr_t mmio) { return mmio; }
void enable_mmu();
void start_core() __attribute__((noreturn));
};
extern Platform & platform();
#endif /* _PLATFORM_H_ */

View File

@ -0,0 +1,30 @@
/*
* \brief Initialization code for bootstrap
* \author Stefan Kalkowski
* \date 2016-09-22
*/
/*
* Copyright (C) 2016 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.
*/
/* local */
#include <platform.h>
/* base includes */
#include <base/internal/globals.h>
#include <base/internal/unmanaged_singleton.h>
Platform & platform() { return *unmanaged_singleton<Platform>(); }
extern "C" void init() __attribute__ ((noreturn));
extern "C" void init()
{
Genode::init_log();
platform().enable_mmu();
platform().start_core();
}

View File

@ -0,0 +1,32 @@
/*
* \brief Lock dummy implementation
* \author Stefan Kalkowski
* \date 2016-09-23
*/
/*
* Copyright (C) 2016 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.
*/
#include <base/lock.h>
#include <assert.h>
Genode::Cancelable_lock::Cancelable_lock(Genode::Cancelable_lock::State state)
: _state(state), _owner(nullptr) { }
void Genode::Cancelable_lock::unlock()
{
assert(_state == LOCKED);
_state = UNLOCKED;
}
void Genode::Cancelable_lock::lock()
{
assert(_state == UNLOCKED);
_state = LOCKED;
}

View File

@ -0,0 +1,191 @@
/*
* \brief Platform implementation
* \author Stefan Kalkowski
* \date 2016-10-19
*/
/*
* Copyright (C) 2016 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.
*/
/* base-internal includes */
#include <base/internal/crt0.h>
/* core includes */
#include <assert.h>
#include <boot_modules.h>
#include <platform.h>
/*****************************
** Platform::Ram_allocator **
*****************************/
void * Platform::Ram_allocator::alloc_aligned(size_t size, unsigned align)
{
using namespace Genode;
void * ret;
assert(Base::alloc_aligned(round_page(size), &ret,
max(align, get_page_size_log2())).ok());
return ret;
}
bool Platform::Ram_allocator::alloc(size_t size, void **out_addr)
{
*out_addr = alloc_aligned(size, 0);
return true;
}
void Platform::Ram_allocator::add(Memory_region const & region) {
add_range(region.base, region.size); }
void Platform::Ram_allocator::remove(Memory_region const & region) {
remove_range(region.base, region.size); }
/******************
** Platform::Pd **
******************/
Platform::Pd::Pd(Platform::Ram_allocator & alloc)
: table_base(alloc.alloc_aligned(sizeof(Bootinfo::Table),
Bootinfo::Table::ALIGNM_LOG2)),
allocator_base(alloc.alloc_aligned(sizeof(Bootinfo::Table_allocator),
Bootinfo::Table::ALIGNM_LOG2)),
table(*Genode::construct_at<Bootinfo::Table>(table_base)),
allocator(*Genode::construct_at<Bootinfo::Table_allocator>(allocator_base))
{
using namespace Genode;
map_insert(Mapping((addr_t)table_base, (addr_t)table_base,
sizeof(Bootinfo::Table), PAGE_FLAGS_KERN_DATA));
map_insert(Mapping((addr_t)allocator_base, (addr_t)allocator_base,
sizeof(Bootinfo::Table_allocator), PAGE_FLAGS_KERN_DATA));
}
void Platform::Pd::map(Mapping m)
{
try {
table.insert_translation(m.virt(), m.phys(), m.size(), m.flags(),
allocator.alloc());
} catch(Genode::Allocator::Out_of_memory) {
Genode::error("translation table needs to much RAM");
} catch (...) {
Genode::error("invalid mapping ", m);
}
}
void Platform::Pd::map_insert(Mapping m)
{
mappings.add(m);
map(m);
}
/**************
** Platform **
**************/
addr_t Platform::_load_elf()
{
using namespace Genode;
addr_t start = ~0UL;
addr_t end = 0;
auto lambda = [&] (Genode::Elf_segment & segment) {
void * phys = (void*)(core_elf_addr + segment.file_offset());
start = min(start, (addr_t) phys);
size_t const size = round_page(segment.mem_size());
if (segment.flags().w) {
unsigned align_log2;
for (align_log2 = 0; align_log2 < 8*sizeof(addr_t); align_log2++)
if ((addr_t)(1 << align_log2) & (addr_t)phys) break;
void * const dst = ram_alloc.alloc_aligned(segment.mem_size(),
align_log2);
memcpy(dst, phys, segment.file_size());
if (size > segment.file_size())
memset((void *)((addr_t)dst + segment.file_size()),
0, size - segment.file_size());
phys = dst;
}
//FIXME: set read-only, privileged and global accordingly
Page_flags flags{RW, segment.flags().x ? EXEC : NO_EXEC,
USER, NO_GLOBAL, RAM, CACHED};
Mapping m((addr_t)phys, (addr_t)segment.start(), size, flags);
core_pd->map_insert(m);
end = max(end, (addr_t)segment.start() + size);
};
core_elf.for_each_segment(lambda);
return end;
}
void Platform::start_core()
{
typedef void (* Entry)();
Entry __attribute__((noreturn)) const entry
= reinterpret_cast<Entry>(core_elf.entry());
entry();
}
static constexpr Genode::Boot_modules_header & header() {
return *((Genode::Boot_modules_header*) &_boot_modules_headers_begin); }
Platform::Platform()
: bootstrap_region((addr_t)&_prog_img_beg,
((addr_t)&_prog_img_end - (addr_t)&_prog_img_beg)),
core_pd(ram_alloc),
core_elf_addr(header().base),
core_elf(core_elf_addr)
{
using namespace Genode;
/* prepare the ram allocator */
board.early_ram_regions.for_each([this] (Memory_region const & region) {
ram_alloc.add(region); });
ram_alloc.remove(bootstrap_region);
/* now we can use the ram allocator for core's pd */
core_pd.construct(ram_alloc);
/* temporarily map all bootstrap memory 1:1 for transition to core */
// FIXME do not insert as mapping for core
core_pd->map_insert(Mapping(bootstrap_region.base, bootstrap_region.base,
bootstrap_region.size, PAGE_FLAGS_KERN_TEXT));
/* map memory-mapped I/O for core */
board.core_mmio.for_each_mapping([&] (Mapping const & m) {
core_pd->map_insert(m); });
/* load ELF */
addr_t const elf_end = _load_elf();
/* setup boot info page */
void * bi_base = ram_alloc.alloc(sizeof(Bootinfo));
core_pd->map_insert(Mapping((addr_t)bi_base, elf_end, sizeof(Bootinfo),
PAGE_FLAGS_KERN_TEXT));
Bootinfo & bootinfo =
*construct_at<Bootinfo>(bi_base, &core_pd->table, &core_pd->allocator,
core_pd->mappings, board.core_mmio);
/* add all left RAM to bootinfo */
ram_alloc.for_each_free_region([&] (Memory_region const & r) {
bootinfo.ram_regions.add(r); });
board.late_ram_regions.for_each([&] (Memory_region const & r) {
bootinfo.ram_regions.add(r); });
}

View File

@ -0,0 +1,60 @@
/*
* \brief Startup code for bootstrap
* \author Stefan Kalkowski
* \date 2016-09-22
*/
/*
* Copyright (C) 2016 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.
*/
.include "macros.s"
.set STACK_SIZE, 4 * 16 * 1024
.section ".text.crt0"
.global _start
_start:
/* zero-fill BSS segment */
adr r0, _bss_local_start
adr r1, _bss_local_end
ldr r0, [r0]
ldr r1, [r1]
mov r2, #0
1:
cmp r1, r0
ble 2f
str r2, [r0]
add r0, r0, #4
b 1b
2:
.global _start_setup_stack
_start_setup_stack:
/* setup multiprocessor-aware kernel stack-pointer */
adr r0, _start_stack
adr r1, _start_stack_size
ldr r1, [r1]
_init_kernel_sp r0, r1
b init
_bss_local_start:
.long _bss_start
_bss_local_end:
.long _bss_end
_start_stack_size:
.long STACK_SIZE
.align 3
_start_stack:
.rept NR_OF_CPUS
.space STACK_SIZE
.endr

View File

@ -0,0 +1,23 @@
/*
* \brief CPU driver for core
* \author Norman Feske
* \author Martin stein
* \author Stefan Kalkowski
* \date 2012-08-30
*/
/*
* Copyright (C) 2012-2016 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.
*/
#include <cpu.h>
void Genode::Arm::clean_invalidate_data_cache() {
asm volatile ("mcr p15, 0, %[rd], c7, c14, 0" :: [rd]"r"(0) : ); }
void Genode::Cpu::translation_added(Genode::addr_t const addr,
Genode::size_t const size) { }

View File

@ -0,0 +1,108 @@
/*
* \brief CPU-specific initialization code for Arndale
* \author Stefan Kalkowski
* \date 2016-01-07
*/
/*
* Copyright (C) 2016 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.
*/
/* core includes */
#include <cpu.h>
#include <translation_table.h>
static unsigned char hyp_mode_stack[1024];
static inline void prepare_nonsecure_world()
{
using Nsacr = Genode::Cpu::Nsacr;
using Cpsr = Genode::Cpu::Psr;
using Scr = Genode::Cpu::Scr;
/* if we are already in HYP mode we're done (depends on u-boot version) */
if (Cpsr::M::get(Cpsr::read()) == Cpsr::M::HYP)
return;
/* ARM generic timer counter freq needs to be set in secure mode */
volatile unsigned long * mct_control = (unsigned long*) 0x101C0240;
*mct_control = 0x100;
asm volatile ("mcr p15, 0, %0, c14, c0, 0" :: "r" (24000000));
/*
* enable coprocessor 10 + 11 access and SMP bit access in auxiliary control
* register for non-secure world
*/
Nsacr::access_t nsacr = 0;
Nsacr::Cpnsae10::set(nsacr, 1);
Nsacr::Cpnsae11::set(nsacr, 1);
Nsacr::Ns_smp::set(nsacr, 1);
Nsacr::write(nsacr);
asm volatile (
"msr sp_mon, sp \n" /* copy current mode's sp */
"msr lr_mon, lr \n" /* copy current mode's lr */
"cps #22 \n" /* switch to monitor mode */
);
Scr::access_t scr = 0;
Scr::Ns::set(scr, 1);
Scr::Fw::set(scr, 1);
Scr::Aw::set(scr, 1);
Scr::Scd::set(scr, 1);
Scr::Hce::set(scr, 1);
Scr::Sif::set(scr, 1);
Scr::write(scr);
}
static inline void prepare_hypervisor(Genode::Translation_table & table)
{
using Genode::Cpu;
/* set hypervisor exception vector */
Cpu::hyp_exception_entry_at((void*)0xfff00000); /* FIXME */
/* set hypervisor's translation table */
Cpu::Httbr::translation_table((Genode::addr_t)&table);
/* prepare MMU usage by hypervisor code */
Cpu::Htcr::write(Cpu::Ttbcr::init_virt_kernel());
Cpu::Hcptr::write(Cpu::Hcptr::init());
Cpu::Hmair0::write(Cpu::Mair0::init_virt_kernel());
Cpu::Vtcr::write(Cpu::Vtcr::init());
Cpu::Hsctlr::write(Cpu::Sctlr::init_value());
}
static inline void switch_to_supervisor_mode()
{
using Psr = Genode::Cpu::Psr;
Psr::access_t psr = 0;
Psr::M::set(psr, Psr::M::SVC);
Psr::F::set(psr, 1);
Psr::I::set(psr, 1);
asm volatile (
"msr sp_svc, sp \n" /* copy current mode's sp */
"msr lr_svc, lr \n" /* copy current mode's lr */
"msr elr_hyp, lr \n" /* copy current mode's lr to hyp lr */
"msr sp_hyp, %[stack] \n" /* copy to hyp stack pointer */
"msr spsr_cxfs, %[psr] \n" /* set psr for supervisor mode */
"adr lr, 1f \n" /* load exception return address */
"eret \n" /* exception return */
"1:":: [psr] "r" (psr), [stack] "r" (&hyp_mode_stack));
}
void Genode::Cpu::init(Genode::Translation_table & table)
{
prepare_nonsecure_world();
prepare_hypervisor(table);
switch_to_supervisor_mode();
}

View File

@ -0,0 +1,169 @@
/*
* \brief Cpu class implementation specific to Cortex A9 SMP
* \author Stefan Kalkowski
* \date 2015-12-09
*/
/*
* Copyright (C) 2015-2016 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.
*/
#include <base/log.h>
/* core includes */
#include <kernel/lock.h>
#include <platform.h>
//using namespace Kernel;
/* entrypoint for non-boot CPUs */
extern "C" void * _start_setup_stack;
/**
* SMP-safe simple counter
*/
class Cpu_counter
{
private:
Kernel::Lock _lock;
volatile int _value = 0;
public:
void inc()
{
Kernel::Lock::Guard guard(_lock);
Genode::memory_barrier();
_value++;
}
void wait_for(int const v) {
while (_value < v) ; }
};
struct Scu : Genode::Mmio
{
struct Cr : Register<0x0, 32>
{
struct Enable : Bitfield<0, 1> { };
};
struct Dcr : Register<0x30, 32>
{
struct Bit_0 : Bitfield<0, 1> { };
};
struct Iassr : Register<0xc, 32>
{
struct Cpu0_way : Bitfield<0, 4> { };
struct Cpu1_way : Bitfield<4, 4> { };
struct Cpu2_way : Bitfield<8, 4> { };
struct Cpu3_way : Bitfield<12, 4> { };
};
Scu(Genode::addr_t mmio) : Genode::Mmio(mmio) { }
void invalidate()
{
Iassr::access_t iassr = 0;
for (Iassr::access_t way = 0; way <= Iassr::Cpu0_way::mask();
way++) {
Iassr::Cpu0_way::set(iassr, way);
Iassr::Cpu1_way::set(iassr, way);
Iassr::Cpu2_way::set(iassr, way);
Iassr::Cpu3_way::set(iassr, way);
write<Iassr>(iassr);
}
}
void enable(bool err_arm_764369)
{
if (err_arm_764369) write<Dcr::Bit_0>(1);
write<Cr::Enable>(1);
}
};
/*
* The initialization of Cortex A9 multicore systems implies a sophisticated
* algorithm in early revisions of this cpu.
*
* See ARM's Cortex-A9 MPCore TRM r2p0 in section 5.3.5 for more details
*/
void Platform::enable_mmu()
{
using Genode::Cpu;
static volatile bool primary_cpu = true;
static Cpu_counter data_cache_invalidated;
static Cpu_counter data_cache_enabled;
static Cpu_counter smp_coherency_enabled;
bool primary = primary_cpu;
if (primary) primary_cpu = false;
Cpu::Sctlr::init();
Cpu::Psr::write(Cpu::Psr::init_kernel());
/* locally initialize interrupt controller */
pic.init_cpu_local();
cpu.invalidate_inner_data_cache();
data_cache_invalidated.inc();
/* primary cpu wakes up all others */
if (primary && NR_OF_CPUS > 1) {
board.wake_up_all_cpus(&_start_setup_stack);
/* send an IPI to all other cpus */
pic.send_ipi();
}
/* wait for other cores' data cache invalidation */
data_cache_invalidated.wait_for(NR_OF_CPUS);
if (primary) {
Scu scu(Board::SCU_MMIO_BASE);
scu.invalidate();
Board::L2_cache l2_cache(Board::PL310_MMIO_BASE);
l2_cache.disable();
l2_cache.invalidate();
scu.enable(board.errata(Platform::Board::ARM_764369));
}
/* secondary cpus wait for the primary's cache activation */
if (!primary) data_cache_enabled.wait_for(1);
cpu.enable_mmu_and_caches((Genode::addr_t)core_pd->table_base);
data_cache_enabled.inc();
cpu.clean_invalidate_inner_data_cache();
/* wait for other cores' data cache activation */
data_cache_enabled.wait_for(NR_OF_CPUS);
if (primary) {
Board::L2_cache l2_cache(board.core_mmio.virt_addr(Board::PL310_MMIO_BASE));
l2_cache.enable();
}
/* secondary cpus wait for the primary's coherency activation */
if (!primary) smp_coherency_enabled.wait_for(1);
Cpu::Actlr::enable_smp(board);
smp_coherency_enabled.inc();
/*
* strangely, some older versions (imx6) seem to not work cache coherent
* until SMP bit is set, so write back the variable here.
*/
cpu.clean_invalidate_inner_data_cache();
/* wait for other cores' coherency activation */
smp_coherency_enabled.wait_for(NR_OF_CPUS);
}

View File

@ -0,0 +1,48 @@
/*
* \brief Parts of platform that are specific to Arndale
* \author Martin Stein
* \date 2012-04-27
*/
/*
* Copyright (C) 2012 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.
*/
#include <platform.h>
/* entrypoint for non-boot CPUs */
extern "C" void * _start_setup_stack;
Platform::Board::Board()
: early_ram_regions(Memory_region { RAM_0_BASE, RAM_0_SIZE }),
core_mmio(Memory_region { IRQ_CONTROLLER_BASE, IRQ_CONTROLLER_SIZE },
Memory_region { IRQ_CONTROLLER_VT_CTRL_BASE, IRQ_CONTROLLER_VT_CTRL_SIZE },
Memory_region { MCT_MMIO_BASE, MCT_MMIO_SIZE },
Memory_region { UART_2_MMIO_BASE, UART_2_MMIO_SIZE }) { }
void Platform::enable_mmu()
{
using Genode::Cpu;
static volatile bool primary_cpu = true;
pic.init_cpu_local();
cpu.init(*reinterpret_cast<Genode::Translation_table*>(core_pd->table_base));
Cpu::Sctlr::init();
Cpu::Psr::write(Cpu::Psr::init_kernel());
cpu.invalidate_inner_data_cache();
/* primary cpu wakes up all others */
if (primary_cpu && NR_OF_CPUS > 1) {
primary_cpu = false;
board.wake_up_all_cpus(&_start_setup_stack);
}
cpu.enable_mmu_and_caches((Genode::addr_t)core_pd->table_base);
}

View File

@ -0,0 +1,25 @@
/*
* \brief Specific bootstrap implementations
* \author Stefan Kalkowski
* \date 2017-01-27
*/
/*
* Copyright (C) 2017 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.
*/
#include <platform.h>
#include <board.h>
using Genode::Memory_region;
Platform::Board::Board()
: early_ram_regions(Memory_region { RAM0_BASE, RAM0_SIZE },
Memory_region { RAM1_BASE, RAM1_SIZE }),
core_mmio(Memory_region { UART_1_MMIO_BASE, UART_1_MMIO_SIZE },
Memory_region { EPIT_1_MMIO_BASE, EPIT_1_MMIO_SIZE },
Memory_region { IRQ_CONTROLLER_BASE, IRQ_CONTROLLER_SIZE }) {
init(); }

View File

@ -0,0 +1,27 @@
/*
* \brief Specific core implementations
* \author Stefan Kalkowski
* \date 2017-01-27
*/
/*
* Copyright (C) 2017 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.
*/
/* core includes */
#include <platform.h>
#include <drivers/trustzone.h>
using Genode::Memory_region;
Platform::Board::Board()
: early_ram_regions(Memory_region { Trustzone::SECURE_RAM_BASE,
Trustzone::SECURE_RAM_SIZE }),
core_mmio(Memory_region { UART_1_MMIO_BASE, UART_1_MMIO_SIZE },
Memory_region { EPIT_1_MMIO_BASE, EPIT_1_MMIO_SIZE },
Memory_region { IRQ_CONTROLLER_BASE, IRQ_CONTROLLER_SIZE },
Memory_region { CSU_BASE, CSU_SIZE }) {
init(); }

View File

@ -0,0 +1,28 @@
/*
* \brief Specific i.MX53 bootstrap implementations
* \author Stefan Kalkowski
* \date 2012-10-24
*/
/*
* Copyright (C) 2012-2017 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.
*/
/* core includes */
#include <platform.h>
#include <cpu.h>
void Platform::enable_mmu()
{
Genode::Cpu::Sctlr::init();
cpu.enable_mmu_and_caches((addr_t)core_pd->table_base);
}
void Genode::Cpu::translation_added(Genode::addr_t const addr,
Genode::size_t const size) { }

View File

@ -0,0 +1,44 @@
/*
* \brief Specific bootstrap implementations
* \author Stefan Kalkowski
* \author Josef Soentgen
* \author Martin Stein
* \date 2014-02-25
*/
/*
* Copyright (C) 2014-2016 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.
*/
/* core includes */
#include <platform.h>
#include <cpu.h>
using namespace Genode;
Platform::Board::Board()
: early_ram_regions(Memory_region { RAM0_BASE, RAM0_SIZE }),
core_mmio(Memory_region { UART_1_MMIO_BASE,
UART_1_MMIO_SIZE },
Memory_region { CORTEX_A9_PRIVATE_MEM_BASE,
CORTEX_A9_PRIVATE_MEM_SIZE },
Memory_region { PL310_MMIO_BASE,
PL310_MMIO_SIZE }) { init(); }
bool Cortex_a9::Board::errata(Cortex_a9::Board::Errata err)
{
switch (err) {
case Cortex_a9::Board::ARM_754322:
case Cortex_a9::Board::ARM_764369:
case Cortex_a9::Board::ARM_775420:
case Cortex_a9::Board::PL310_588369:
case Cortex_a9::Board::PL310_727915:
case Cortex_a9::Board::PL310_769419:
return true;
};
return false;
}

View File

@ -0,0 +1,16 @@
/*
* \brief Cpu-specific code for Cortex A15
* \author Stefan Kalkowski
* \date 2016-01-07
*/
/*
* Copyright (C) 2016 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.
*/
#include <cpu.h>
void Genode::Cpu::init(Genode::Translation_table&) {}

View File

@ -0,0 +1,51 @@
/*
* \brief Parts of platform that are specific to Pandaboard
* \author Stefan Kalkowski
* \date 2017-01-30
*/
/*
* Copyright (C) 2017 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.
*/
#include <platform.h>
#include <cortex_a9_wugen.h>
Platform::Board::Board()
: early_ram_regions(Memory_region { RAM_0_BASE, RAM_0_SIZE }),
core_mmio(Memory_region { CORTEX_A9_PRIVATE_MEM_BASE,
CORTEX_A9_PRIVATE_MEM_SIZE },
Memory_region { TL16C750_3_MMIO_BASE,
TL16C750_MMIO_SIZE },
Memory_region { PL310_MMIO_BASE,
PL310_MMIO_SIZE }) { }
void Cortex_a9::Board::wake_up_all_cpus(void * const ip)
{
Genode::Cortex_a9_wugen wugen;
wugen.init_cpu_1(ip);
asm volatile("dsb\n"
"sev\n");
}
bool Cortex_a9::Board::errata(Cortex_a9::Board::Errata err)
{
switch (err) {
case Cortex_a9::Board::PL310_588369:
case Cortex_a9::Board::PL310_727915: return true;
default: ;
};
return false;
}
void Genode::Cpu::Actlr::enable_smp(Genode::Board & board)
{
Board::Secure_monitor monitor;
monitor.call(Board::Secure_monitor::CPU_ACTLR_SMP_BIT_RAISE, 0);
}

View File

@ -0,0 +1,52 @@
/*
* \brief Pbxa9 specific platform implementation
* \author Stefan Kalkowski
* \date 2016-10-20
*/
/*
* Copyright (C) 2016 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.
*/
/* bootstrap includes */
#include <platform.h>
Platform::Board::Board()
: early_ram_regions(Memory_region { RAM_0_BASE, RAM_0_SIZE },
Memory_region { RAM_1_BASE, RAM_1_SIZE }),
core_mmio(Memory_region { Board::CORTEX_A9_PRIVATE_MEM_BASE,
Board::CORTEX_A9_PRIVATE_MEM_SIZE },
Memory_region { Board::PL011_0_MMIO_BASE,
Board::PL011_0_MMIO_SIZE },
Memory_region { Board::PL310_MMIO_BASE,
Board::PL310_MMIO_SIZE }) { }
bool Cortex_a9::Board::errata(Cortex_a9::Board::Errata err) {
return false; }
void Cortex_a9::Board::wake_up_all_cpus(void * const ip)
{
/**
* set the entrypoint for the other CPUs via the flags register
* of the system control registers. ARMs boot monitor code will
* read out this register and jump to it after the cpu received
* an interrupt
*/
struct System_control : Genode::Mmio
{
struct Flagsset : Register<0x30, 32> { };
struct Flagsclr : Register<0x34, 32> { };
System_control(void * const ip)
: Mmio(SYSTEM_CONTROL_MMIO_BASE)
{
write<Flagsclr>(~0UL);
write<Flagsset>(reinterpret_cast<Flagsset::access_t>(ip));
}
} sc(ip);
}

View File

@ -0,0 +1,19 @@
/*
* \brief CPU core implementation
* \author Sebastian Sumpf
* \author Stefan Kalkowski
* \date 2016-02-10
*/
/*
* Copyright (C) 2016 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.
*/
/* core includes */
#include <cpu.h>
void Genode::Cpu::translation_added(addr_t const addr, size_t const size) {
Genode::Cpu::sfence(); }

View File

@ -0,0 +1,51 @@
/**
* \brief Kernel startup code
* \author Sebastian Sumpf
* \author Stefan Kalkowski
* \date 2015-06-010
*/
/*
* Copyright (C) 2015-2016 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.
*/
.set STACK_SIZE, 64 * 1024
.section ".text.crt0"
.global _start
_start:
j _start_next_page
/* leave first page empty for mode-transition page located at 0x100 */
.space 4096
_start_next_page:
/* clear the bss segment */
la a0, _bss_start
la a1, _bss_end
1:
sd x0, (a0)
addi a0, a0, 8
bne a0, a1, 1b
la sp, _stack_area_start
la a0, STACK_SIZE
ld a0, (a0)
add sp, sp, a0
/* save kernel stack pointer in mscratch */
csrw mscratch, sp
jal setup_riscv_exception_vector
jal init
1: j 1b
.align 3
_stack_area_start:
.space STACK_SIZE

View File

@ -0,0 +1,30 @@
/*
* \brief Exception vector initialization
* \author Sebastian Sumpf
* \date 2015-07-12
*/
/*
* Copyright (C) 2015-2016 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.
*/
/* Core includes */
#include <kernel/cpu.h>
extern int _machine_begin, _machine_end;
extern "C" void setup_riscv_exception_vector()
{
using namespace Genode;
/* retrieve exception vector */
addr_t vector;
asm volatile ("csrr %0, mtvec\n" : "=r"(vector));
/* copy machine mode exception vector */
memcpy((void *)vector,
&_machine_begin, (addr_t)&_machine_end - (addr_t)&_machine_begin);
}

View File

@ -0,0 +1,59 @@
/*
* \brief Platform implementations specific for RISC-V
* \author Stefan Kalkowski
* \author Sebastian Sumpf
* \date 2016-11-23
*/
/*
* Copyright (C) 2016 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.
*/
#include <platform.h>
Platform::Board::Board()
: early_ram_regions(Genode::Memory_region { 0, 128 * 1024 * 1024 } ) {}
struct Mstatus : Genode::Register<64>
{
enum {
USER = 0,
SUPERVISOR = 1,
Sv39 = 9,
};
struct Ie : Bitfield<0, 1> { };
struct Priv : Bitfield<1, 2> { };
struct Ie1 : Bitfield<3, 1> { };
struct Priv1 : Bitfield<4, 2> { };
struct Fs : Bitfield<12, 2> { enum { INITIAL = 1 }; };
struct Vm : Bitfield<17, 5> { };
};
void Platform::enable_mmu()
{
using Genode::Cpu;
/* read status register */
Mstatus::access_t mstatus = 0;
Mstatus::Vm::set(mstatus, Mstatus::Sv39); /* enable Sv39 paging */
Mstatus::Fs::set(mstatus, Mstatus::Fs::INITIAL); /* enable FPU */
Mstatus::Ie1::set(mstatus, 1); /* user mode interrupt */
Mstatus::Priv1::set(mstatus, Mstatus::USER); /* set user mode */
Mstatus::Ie::set(mstatus, 0); /* disable interrupts */
Mstatus::Priv::set(mstatus, Mstatus::SUPERVISOR); /* set supervisor mode */
asm volatile ("csrw sasid, %0\n" /* address space id */
"csrw sptbr, %1\n" /* set page table */
"csrw mstatus, %2\n" /* change mode */
:
: "r" (0/*core_pd.asid*/),
"r" (core_pd->table_base),
"r" (mstatus)
: "memory");
}

View File

@ -0,0 +1,46 @@
/*
* \brief Platform implementations specific for base-hw and Raspberry Pi
* \author Norman Feske
* \author Stefan Kalkowski
* \date 2013-04-05
*/
/*
* Copyright (C) 2013-2016 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.
*/
#include <platform.h>
using Genode::Memory_region;
/**
* Leave out the first page (being 0x0) from bootstraps RAM allocator,
* some code does not feel happy with addresses being zero
*/
Platform::Board::Board()
: early_ram_regions(Memory_region { RAM_0_BASE + 0x1000,
RAM_0_SIZE - 0x1000 }),
late_ram_regions(Memory_region { RAM_0_BASE, 0x1000 }),
core_mmio(Memory_region { PL011_0_MMIO_BASE,
PL011_0_MMIO_SIZE },
Memory_region { SYSTEM_TIMER_MMIO_BASE,
SYSTEM_TIMER_MMIO_SIZE },
Memory_region { IRQ_CONTROLLER_BASE,
IRQ_CONTROLLER_SIZE },
Memory_region { USB_DWC_OTG_BASE,
USB_DWC_OTG_SIZE }) {}
void Platform::enable_mmu()
{
Genode::Cpu::Sctlr::init();
Genode::Cpu::Psr::write(Genode::Cpu::Psr::init_kernel());
/* check for mapping restrictions */
assert(!Genode::Cpu::restricted_page_mappings());
cpu.enable_mmu_and_caches((addr_t)core_pd->table_base);
}

View File

@ -0,0 +1,118 @@
/*
* \brief Startup code for kernel
* \author Adrian-Ken Rueegsegger
* \author Martin Stein
* \author Reto Buerki
* \author Stefan Kalkowski
* \date 2015-02-06
*/
/*
* Copyright (C) 2011-2015 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.
*/
.include "macros.s"
.section ".text.crt0"
/* magic multi-boot header to make GRUB happy */
.long 0x1badb002
.long 0x0
.long 0xe4524ffe
/**********************************
** Startup code for primary CPU **
**********************************/
.code32
.global _start
_start:
/**
* zero-fill BSS segment
*/
leal _bss_start, %edi
leal _bss_end, %ecx
sub %edi, %ecx
shr $2, %ecx
xor %eax, %eax
rep stosl
/* Enable PAE (prerequisite for IA-32e mode) */
movl %cr4, %eax
btsl $5, %eax
movl %eax, %cr4
/* Load initial pagetables */
leal _kernel_pml4, %eax
mov %eax, %cr3
/* Enable IA-32e mode and execute-disable */
movl $0xc0000080, %ecx
rdmsr
btsl $8, %eax
btsl $11, %eax
wrmsr
/* Enable paging, write protection and caching */
movl %cr0, %eax
btsl $16, %eax
btrl $29, %eax
btrl $30, %eax
btsl $31, %eax
movl %eax, %cr0
/* Set up GDT */
lgdt _mt_gdt_ptr
/* Indirect long jump to 64-bit code */
ljmp $8, $_start64
.code64
_start64:
/*
* Set up kernel segment selectors
*/
mov $0x10, %eax
mov %eax, %ss
mov %eax, %ds
mov %eax, %es
mov %eax, %fs
mov %eax, %gs
/*
* Install initial temporary environment that is replaced later by the
* environment that init_main_thread creates.
*/
leaq _stack_high@GOTPCREL(%rip),%rax
movq (%rax), %rsp
movq __initial_bx@GOTPCREL(%rip),%rax
movq %rbx, (%rax)
/* kernel-initialization */
call init
/* catch erroneous return of the kernel initialization */
1: jmp 1b
_define_gdt 0
/*********************************
** .bss (non-initialized data) **
*********************************/
.bss
/* stack of the temporary initial environment */
.p2align 8
.space 32 * 1024
_stack_high:
.globl __initial_bx
__initial_bx:
.space 8

View File

@ -0,0 +1,67 @@
/*
* \brief Initial pagetables for x86_64
* \author Adrian-Ken Rueegsegger
* \author Reto Buerki
* \author Stefan Kalkowski
* \date 2015-04-22
*/
/*
* Copyright (C) 2015-2016 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.
*/
.include "macros.s"
.data
/********************************************
** Identity mapping from 4KiB to 1GiB **
** plus mappings for LAPIC, I/O APIC MMIO **
** Page 0 containing the Bios Data Area **
** gets mapped to 2MiB - 4KiB readonly. **
********************************************/
/* PML4 */
.p2align MIN_PAGE_SIZE_LOG2
.global _kernel_pml4
_kernel_pml4:
.quad _kernel_pdp + 0xf
.fill 511, 8, 0x0
/* PDP */
.p2align MIN_PAGE_SIZE_LOG2
_kernel_pdp:
.quad _kernel_pd + 0xf
.fill 2, 8, 0x0
.quad _kernel_pd_503 + 0xf
.fill 508, 8, 0x0
/* PD */
.p2align MIN_PAGE_SIZE_LOG2
_kernel_pd:
.quad _kernel_pt_bda + 0xf
.set entry, 0x20018f
.rept 511
.quad entry
.set entry, entry + 0x200000
.endr
.p2align MIN_PAGE_SIZE_LOG2
_kernel_pd_503:
.fill 502, 8, 0x0
.quad 0xfec0019f
.quad 0xfee0019f
.fill 8, 8, 0x0
.p2align MIN_PAGE_SIZE_LOG2
_kernel_pt_bda:
.fill 1, 8, 0x0
.set entry, 0x118f
.rept 510
.quad entry
.set entry, entry + 0x1000
.endr
.quad 0x000001

View File

@ -0,0 +1,52 @@
/*
* \brief Initial pagetables for x86_64_muen
* \author Adrian-Ken Rueegsegger
* \author Reto Buerki
* \date 2015-04-22
*/
/*
* Copyright (C) 2015 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.
*/
.include "macros.s"
.data
/*****************************************
** Identity mapping from 2MiB to 1GiB **
** plus mappings for Muen pvirt pages **
*****************************************/
/* PML4 */
.p2align MIN_PAGE_SIZE_LOG2
.global _kernel_pml4
_kernel_pml4:
.quad _kernel_pdp + 0xf
.fill 511, 8, 0x0
/* PDP */
.p2align MIN_PAGE_SIZE_LOG2
_kernel_pdp:
.quad _kernel_pd + 0xf
.fill 55, 8, 0x0
.quad _kernel_pd_pvirt + 0xf
.fill 455, 8, 0x0
/* PD */
.p2align MIN_PAGE_SIZE_LOG2
_kernel_pd:
.quad 0
.set entry, 0x20018f
.rept 511
.quad entry
.set entry, entry + 0x200000
.endr
.p2align MIN_PAGE_SIZE_LOG2
_kernel_pd_pvirt:
.quad 0xe0000018f
.fill 511, 8, 0x0

View File

@ -0,0 +1,75 @@
/*
* \brief Platform implementations specific for x86_64
* \author Reto Buerki
* \author Stefan Kalkowski
* \date 2015-05-04
*/
/*
* Copyright (C) 2015-2016 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.
*/
/* core includes */
#include <bios_data_area.h>
#include <cpu.h>
#include <platform.h>
#include <multiboot.h>
using namespace Genode;
/* contains physical pointer to multiboot */
extern "C" Genode::addr_t __initial_bx;
Platform::Board::Board()
: core_mmio(Memory_region { 0, 0x1000 },
Memory_region { Board::MMIO_LAPIC_BASE,
Board::MMIO_LAPIC_SIZE },
Memory_region { Board::MMIO_IOAPIC_BASE,
Board::MMIO_IOAPIC_SIZE },
Memory_region { __initial_bx & ~0xFFFUL,
get_page_size() })
{
using Mmap = Multiboot_info::Mmap;
static constexpr size_t initial_map_max = 1024 * 1024 * 1024;
for (unsigned i = 0; true; i++) {
Mmap v = Multiboot_info(__initial_bx).phys_ram(i);
if (!v.base) break;
Mmap::Addr::access_t base = v.read<Mmap::Addr>();
Mmap::Length::access_t size = v.read<Mmap::Length>();
/*
* Exclude first physical page, so that it will become part of the
* MMIO allocator. The framebuffer requests this page as MMIO.
*/
if (base == 0 && size >= get_page_size()) {
base = get_page_size();
size -= get_page_size();
}
if (base >= initial_map_max) {
late_ram_regions.add(Memory_region { base, size });
continue;
}
if (base + size <= initial_map_max) {
early_ram_regions.add(Memory_region { base, size });
continue;
}
size_t low_size = initial_map_max - base;
early_ram_regions.add(Memory_region { base, low_size });
late_ram_regions.add(Memory_region { initial_map_max, size - low_size });
}
}
void Platform::enable_mmu() {
Cpu::Cr3::write(Cpu::Cr3::init((addr_t)core_pd->table_base)); }
addr_t Bios_data_area::_mmio_base_virt() { return 0x1ff000; }

View File

@ -0,0 +1,39 @@
/*
* \brief Platform implementations specific for x86_64
* \author Reto Buerki
* \author Stefan Kalkowski
* \date 2015-05-04
*/
/*
* Copyright (C) 2015-2016 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.
*/
/* core includes */
#include <cpu.h>
#include <platform.h>
#include <muen/sinfo.h>
using namespace Genode;
Platform::Board::Board()
: core_mmio(Memory_region { Sinfo::PHYSICAL_BASE_ADDR, Sinfo::SIZE },
Memory_region { TIMER_BASE_ADDR, TIMER_SIZE },
Memory_region { TIMER_PREEMPT_BASE_ADDR, TIMER_PREEMPT_SIZE })
{
struct Sinfo::Memregion_info region;
Sinfo sinfo(Sinfo::PHYSICAL_BASE_ADDR);
if (!sinfo.get_memregion_info("ram", &region))
error("Unable to retrieve base-hw ram region");
else
early_ram_regions.add(Memory_region { region.address, region.size });
}
void Platform::enable_mmu() {
Cpu::Cr3::write(Cpu::Cr3::init((addr_t)core_pd->table_base)); }

View File

@ -0,0 +1,32 @@
/*
* \brief Platform implementations specific for base-hw and Zynq
* \author Johannes Schlatow
* \author Stefan Kalkowski
* \date 2014-12-15
*/
/*
* Copyright (C) 2014-2016 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.
*/
/* core includes */
#include <platform.h>
Platform::Board::Board()
: early_ram_regions(Memory_region { RAM_0_BASE + 0x1000,
RAM_0_SIZE - 0x1000 }),
late_ram_regions(Memory_region { RAM_0_BASE, 0x1000 }),
core_mmio(Memory_region { CORTEX_A9_PRIVATE_MEM_BASE,
CORTEX_A9_PRIVATE_MEM_SIZE },
Memory_region { KERNEL_UART_BASE,
KERNEL_UART_SIZE },
Memory_region { PL310_MMIO_BASE,
PL310_MMIO_SIZE }) { }
bool Cortex_a9::Board::errata(Cortex_a9::Board::Errata err) {
return false; }

View File

@ -0,0 +1,28 @@
/*
* \brief Thread implementation needed by cxx library
* \author Stefan Kalkowski
* \date 2016-10-19
*/
/*
* Copyright (C) 2016 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.
*/
/* base includes */
#include <base/thread.h>
/* local includes */
#include <assert.h>
Genode::Thread * Genode::Thread::myself()
{
assert(false);
return nullptr;
}
Genode::Thread::Name Genode::Thread::name() const { return "bootstrap"; }