2016-11-07 17:00:24 +00:00
|
|
|
/*
|
|
|
|
* \brief Platform implementation
|
|
|
|
* \author Stefan Kalkowski
|
|
|
|
* \date 2016-10-19
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
2017-02-20 12:23:52 +00:00
|
|
|
* Copyright (C) 2016-2017 Genode Labs GmbH
|
2016-11-07 17:00:24 +00:00
|
|
|
*
|
|
|
|
* This file is part of the Genode OS framework, which is distributed
|
2017-02-20 12:23:52 +00:00
|
|
|
* under the terms of the GNU Affero General Public License version 3.
|
2016-11-07 17:00:24 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include <base/internal/crt0.h>
|
2017-02-21 12:46:59 +00:00
|
|
|
#include <hw/assert.h>
|
2016-11-07 17:00:24 +00:00
|
|
|
|
|
|
|
#include <boot_modules.h>
|
|
|
|
#include <platform.h>
|
|
|
|
|
2017-02-21 12:46:59 +00:00
|
|
|
using namespace Bootstrap;
|
|
|
|
|
2016-11-07 17:00:24 +00:00
|
|
|
|
|
|
|
/*****************************
|
|
|
|
** Platform::Ram_allocator **
|
|
|
|
*****************************/
|
|
|
|
|
|
|
|
void * Platform::Ram_allocator::alloc_aligned(size_t size, unsigned align)
|
|
|
|
{
|
|
|
|
using namespace Genode;
|
2017-02-21 12:46:59 +00:00
|
|
|
using namespace Hw;
|
2016-11-07 17:00:24 +00:00
|
|
|
|
|
|
|
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)
|
2017-02-21 12:46:59 +00:00
|
|
|
: table_base(alloc.alloc_aligned(sizeof(Table), Table::ALIGNM_LOG2)),
|
|
|
|
array_base(alloc.alloc_aligned(sizeof(Table_array), Table::ALIGNM_LOG2)),
|
|
|
|
table(*Genode::construct_at<Table>(table_base)),
|
|
|
|
array(*Genode::construct_at<Table_array>(array_base))
|
2016-11-07 17:00:24 +00:00
|
|
|
{
|
|
|
|
using namespace Genode;
|
2017-06-20 13:25:04 +00:00
|
|
|
addr_t const table_virt_base = Hw::Mm::core_page_tables().base;
|
|
|
|
map_insert(Mapping((addr_t)table_base, table_virt_base,
|
2017-02-21 12:46:59 +00:00
|
|
|
sizeof(Table), Hw::PAGE_FLAGS_KERN_DATA));
|
2017-06-20 13:25:04 +00:00
|
|
|
map_insert(Mapping((addr_t)array_base, table_virt_base + sizeof(Table),
|
2017-02-21 12:46:59 +00:00
|
|
|
sizeof(Table_array), Hw::PAGE_FLAGS_KERN_DATA));
|
2016-11-07 17:00:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Platform::Pd::map(Mapping m)
|
|
|
|
{
|
|
|
|
try {
|
|
|
|
table.insert_translation(m.virt(), m.phys(), m.size(), m.flags(),
|
2017-02-21 12:46:59 +00:00
|
|
|
array.alloc());
|
|
|
|
} catch (Hw::Out_of_tables &) {
|
2016-11-07 17:00:24 +00:00
|
|
|
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 **
|
|
|
|
**************/
|
|
|
|
|
2017-06-20 13:25:04 +00:00
|
|
|
Mapping Platform::_load_elf()
|
2016-11-07 17:00:24 +00:00
|
|
|
{
|
|
|
|
using namespace Genode;
|
2017-02-21 12:46:59 +00:00
|
|
|
using namespace Hw;
|
2016-11-07 17:00:24 +00:00
|
|
|
|
2017-06-20 13:25:04 +00:00
|
|
|
Mapping ret;
|
2016-11-07 17:00:24 +00:00
|
|
|
auto lambda = [&] (Genode::Elf_segment & segment) {
|
|
|
|
void * phys = (void*)(core_elf_addr + segment.file_offset());
|
|
|
|
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,
|
2017-06-20 13:25:04 +00:00
|
|
|
USER, GLOBAL, RAM, CACHED};
|
2016-11-07 17:00:24 +00:00
|
|
|
Mapping m((addr_t)phys, (addr_t)segment.start(), size, flags);
|
2017-06-20 13:25:04 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Do not map the read-only, non-executable segment containing
|
|
|
|
* the boot modules, although it is a loadable segment, which we
|
|
|
|
* define so that the modules are loaded as ELF image
|
|
|
|
* via the bootloader
|
|
|
|
*/
|
|
|
|
if (segment.flags().x || segment.flags().w)
|
|
|
|
core_pd->map_insert(m);
|
|
|
|
else
|
|
|
|
ret = m;
|
2016-11-07 17:00:24 +00:00
|
|
|
};
|
|
|
|
core_elf.for_each_segment(lambda);
|
2017-06-20 13:25:04 +00:00
|
|
|
return ret;
|
2016-11-07 17:00:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
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,
|
2017-02-21 12:46:59 +00:00
|
|
|
bootstrap_region.size, Hw::PAGE_FLAGS_KERN_TEXT));
|
2016-11-07 17:00:24 +00:00
|
|
|
|
|
|
|
/* map memory-mapped I/O for core */
|
|
|
|
board.core_mmio.for_each_mapping([&] (Mapping const & m) {
|
|
|
|
core_pd->map_insert(m); });
|
|
|
|
|
|
|
|
/* load ELF */
|
2017-06-20 13:25:04 +00:00
|
|
|
Mapping boot_modules = _load_elf();
|
2016-11-07 17:00:24 +00:00
|
|
|
|
|
|
|
/* setup boot info page */
|
2017-02-21 12:46:59 +00:00
|
|
|
void * bi_base = ram_alloc.alloc(sizeof(Boot_info));
|
2017-06-20 13:25:04 +00:00
|
|
|
core_pd->map_insert(Mapping((addr_t)bi_base, Hw::Mm::boot_info().base,
|
|
|
|
sizeof(Boot_info), Hw::PAGE_FLAGS_KERN_TEXT));
|
2017-02-21 12:46:59 +00:00
|
|
|
Boot_info & bootinfo =
|
|
|
|
*construct_at<Boot_info>(bi_base, (addr_t)&core_pd->table,
|
2017-08-11 12:29:16 +00:00
|
|
|
(addr_t)&core_pd->array,
|
2017-06-20 13:25:04 +00:00
|
|
|
core_pd->mappings, boot_modules,
|
|
|
|
board.core_mmio, board.acpi_rsdp);
|
2016-11-07 17:00:24 +00:00
|
|
|
|
|
|
|
/* 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); });
|
|
|
|
}
|