295 lines
8.3 KiB
C++
295 lines
8.3 KiB
C++
/*
|
|
* \brief Platform interface
|
|
* \author Norman Feske
|
|
* \date 2015-05-01
|
|
*/
|
|
|
|
/*
|
|
* Copyright (C) 2015-2017 Genode Labs GmbH
|
|
*
|
|
* This file is part of the Genode OS framework, which is distributed
|
|
* under the terms of the GNU Affero General Public License version 3.
|
|
*/
|
|
|
|
#ifndef _CORE__INCLUDE__PLATFORM_H_
|
|
#define _CORE__INCLUDE__PLATFORM_H_
|
|
|
|
/* local includes */
|
|
#include <platform_generic.h>
|
|
#include <core_mem_alloc.h>
|
|
#include <vm_space.h>
|
|
#include <core_cspace.h>
|
|
#include <initial_untyped_pool.h>
|
|
#include <assertion.h>
|
|
|
|
namespace Genode {
|
|
class Platform;
|
|
template <Genode::size_t> class Static_allocator;
|
|
class Address_space;
|
|
}
|
|
|
|
|
|
/**
|
|
* Allocator operating on a static memory pool
|
|
*
|
|
* \param MAX maximum number of 4096 blocks
|
|
*
|
|
* The size of a single ELEM must be a multiple of sizeof(long).
|
|
*/
|
|
template <Genode::size_t MAX>
|
|
class Genode::Static_allocator : public Allocator
|
|
{
|
|
private:
|
|
|
|
Bit_allocator<MAX> _used { };
|
|
|
|
struct Elem_space { uint8_t space[4096]; };
|
|
|
|
Elem_space _elements[MAX];
|
|
|
|
public:
|
|
|
|
class Alloc_failed { };
|
|
|
|
bool alloc(size_t size, void **out_addr) override
|
|
{
|
|
*out_addr = nullptr;
|
|
|
|
if (size > sizeof(Elem_space)) {
|
|
error("unexpected allocation size of ", size);
|
|
return false;
|
|
}
|
|
|
|
try {
|
|
*out_addr = &_elements[_used.alloc()]; }
|
|
catch (typename Bit_allocator<MAX>::Out_of_indices) {
|
|
return false; }
|
|
|
|
return true;
|
|
}
|
|
|
|
size_t overhead(size_t) const override { return 0; }
|
|
|
|
void free(void *ptr, size_t) override
|
|
{
|
|
Elem_space *elem = reinterpret_cast<Elem_space *>(ptr);
|
|
unsigned const index = elem - &_elements[0];
|
|
_used.free(index);
|
|
}
|
|
|
|
bool need_size_for_free() const override { return false; }
|
|
};
|
|
|
|
class Genode::Platform : public Platform_generic
|
|
{
|
|
private:
|
|
|
|
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 */
|
|
|
|
Initial_untyped_pool _initial_untyped_pool { };
|
|
|
|
/*
|
|
* 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;
|
|
|
|
/*
|
|
* Allocator for tracking unused virtual addresses, which are not
|
|
* backed by page tables.
|
|
*/
|
|
Phys_allocator _unused_virt_alloc;
|
|
|
|
void _init_unused_phys_alloc();
|
|
bool const _init_unused_phys_alloc_done;
|
|
|
|
Rom_fs _rom_fs { }; /* ROM file system */
|
|
|
|
/*
|
|
* Virtual address range usable by non-core processes
|
|
*/
|
|
addr_t _vm_base = 0;
|
|
size_t _vm_size = 0;
|
|
|
|
/*
|
|
* Until this point, no interaction with the seL4 kernel was needed.
|
|
* However, the next steps involve the invokation of system calls and
|
|
* the use of kernel services. To use the kernel bindings, we first
|
|
* need to initialize the TLS mechanism that is used to find the IPC
|
|
* buffer for the calling thread.
|
|
*/
|
|
void init_sel4_ipc_buffer();
|
|
bool const _init_sel4_ipc_buffer_done;
|
|
|
|
/* allocate 1st-level CNode */
|
|
Cnode _top_cnode { Cap_sel(seL4_CapInitThreadCNode),
|
|
Cnode_index(Core_cspace::top_cnode_sel()),
|
|
Core_cspace::NUM_TOP_SEL_LOG2,
|
|
_initial_untyped_pool };
|
|
|
|
/* allocate 2nd-level CNode to align core's CNode with the LSB of the CSpace*/
|
|
Cnode _core_pad_cnode { Cap_sel(seL4_CapInitThreadCNode),
|
|
Cnode_index(Core_cspace::core_pad_cnode_sel()),
|
|
Core_cspace::NUM_CORE_PAD_SEL_LOG2,
|
|
_initial_untyped_pool };
|
|
|
|
/* allocate 3rd-level CNode for core's objects */
|
|
Cnode _core_cnode { Cap_sel(seL4_CapInitThreadCNode),
|
|
Cnode_index(Core_cspace::core_cnode_sel()),
|
|
Core_cspace::NUM_CORE_SEL_LOG2, _initial_untyped_pool };
|
|
|
|
/* allocate 2nd-level CNode for storing page-frame cap selectors */
|
|
Cnode _phys_cnode { Cap_sel(seL4_CapInitThreadCNode),
|
|
Cnode_index(Core_cspace::phys_cnode_sel()),
|
|
Core_cspace::NUM_PHYS_SEL_LOG2, _initial_untyped_pool };
|
|
|
|
/* allocate 2nd-level CNode for storing cap selectors for untyped 4k objects */
|
|
Cnode _untyped_cnode { Cap_sel(seL4_CapInitThreadCNode),
|
|
Cnode_index(Core_cspace::untyped_cnode_4k()),
|
|
Core_cspace::NUM_PHYS_SEL_LOG2, _initial_untyped_pool };
|
|
|
|
/* allocate 2nd-level CNode for storing cap selectors for untyped 16k objects */
|
|
Cnode _untyped_cnode_16k { Cap_sel(seL4_CapInitThreadCNode),
|
|
Cnode_index(Core_cspace::untyped_cnode_16k()),
|
|
Core_cspace::NUM_PHYS_SEL_LOG2, _initial_untyped_pool };
|
|
|
|
/*
|
|
* XXX Consider making Bit_allocator::_reserve public so that we can
|
|
* turn the bit allocator into a private member of 'Core_sel_alloc'.
|
|
*/
|
|
typedef Bit_allocator<1 << Core_cspace::NUM_CORE_SEL_LOG2> Core_sel_bit_alloc;
|
|
|
|
struct Core_sel_alloc : Cap_sel_alloc, private Core_sel_bit_alloc
|
|
{
|
|
Lock _lock { };
|
|
|
|
Core_sel_alloc() { _reserve(0, Core_cspace::core_static_sel_end()); }
|
|
|
|
Cap_sel alloc() override
|
|
{
|
|
Lock::Guard guard(_lock);
|
|
|
|
try {
|
|
return Cap_sel(Core_sel_bit_alloc::alloc()); }
|
|
catch (Bit_allocator::Out_of_indices) {
|
|
throw Alloc_failed(); }
|
|
}
|
|
|
|
void free(Cap_sel sel) override
|
|
{
|
|
Lock::Guard guard(_lock);
|
|
|
|
Core_sel_bit_alloc::free(sel.value());
|
|
}
|
|
|
|
} _core_sel_alloc { };
|
|
|
|
/**
|
|
* Replace initial CSpace with custom CSpace layout
|
|
*/
|
|
void _switch_to_core_cspace();
|
|
bool const _switch_to_core_cspace_done;
|
|
|
|
Static_allocator<sizeof(void *) * 6> _core_page_table_registry_alloc { };
|
|
Page_table_registry _core_page_table_registry;
|
|
|
|
/**
|
|
* Pre-populate core's '_page_table_registry' with the information
|
|
* about the initial page tables and page frames as set up by the
|
|
* kernel
|
|
*/
|
|
void _init_core_page_table_registry();
|
|
bool const _init_core_page_table_registry_done;
|
|
|
|
Cap_sel _init_asid_pool();
|
|
Cap_sel const _asid_pool_sel = _init_asid_pool();
|
|
|
|
/**
|
|
* Shortcut for physical memory allocator
|
|
*/
|
|
Range_allocator &_phys_alloc = _core_mem_alloc.phys_alloc();
|
|
|
|
/**
|
|
* Initialize core allocators
|
|
*/
|
|
void _init_allocators();
|
|
bool const _init_allocators_done;
|
|
|
|
Vm_space _core_vm_space;
|
|
|
|
void _init_rom_modules();
|
|
|
|
/**
|
|
* Unmap page frame provided by kernel during early bootup.
|
|
*/
|
|
long _unmap_page_frame(Cap_sel const &);
|
|
|
|
public:
|
|
|
|
/**
|
|
* Constructor
|
|
*/
|
|
Platform();
|
|
|
|
|
|
/********************************
|
|
** Generic platform interface **
|
|
********************************/
|
|
|
|
Range_allocator &ram_alloc() override { return _core_mem_alloc.phys_alloc(); }
|
|
Range_allocator &io_mem_alloc() override { return _io_mem_alloc; }
|
|
Range_allocator &io_port_alloc() override { return _io_port_alloc; }
|
|
Range_allocator &irq_alloc() override { return _irq_alloc; }
|
|
Range_allocator ®ion_alloc() override { return _core_mem_alloc.virt_alloc(); }
|
|
Range_allocator &core_mem_alloc() override { return _core_mem_alloc; }
|
|
addr_t vm_start() const override { return _vm_base; }
|
|
size_t vm_size() const override { return _vm_size; }
|
|
Rom_fs &rom_fs() override { return _rom_fs; }
|
|
|
|
Affinity::Space affinity_space() const override {
|
|
return sel4_boot_info().numNodes; }
|
|
|
|
bool supports_direct_unmap() const override { return true; }
|
|
|
|
Address_space &core_pd() { ASSERT_NEVER_CALLED; }
|
|
|
|
|
|
/*******************
|
|
** seL4 specific **
|
|
*******************/
|
|
|
|
Cnode &phys_cnode() { return _phys_cnode; }
|
|
Cnode &top_cnode() { return _top_cnode; }
|
|
Cnode &core_cnode() { return _core_cnode; }
|
|
|
|
Vm_space &core_vm_space() { return _core_vm_space; }
|
|
|
|
Cap_sel_alloc &core_sel_alloc() { return _core_sel_alloc; }
|
|
unsigned alloc_core_rcv_sel();
|
|
|
|
void reset_sel(unsigned sel);
|
|
|
|
Cap_sel asid_pool() const { return _asid_pool_sel; }
|
|
|
|
void wait_for_exit() override;
|
|
|
|
/**
|
|
* Determine size of a core local mapping required for a
|
|
* core_rm_session detach().
|
|
*/
|
|
size_t region_alloc_size_at(void * addr) {
|
|
return (_core_mem_alloc.virt_alloc())()->size_at(addr); }
|
|
|
|
size_t max_caps() const override
|
|
{
|
|
return 1UL << Core_cspace::NUM_CORE_SEL_LOG2;
|
|
}
|
|
|
|
bool core_needs_platform_pd() const override { return false; }
|
|
};
|
|
|
|
#endif /* _CORE__INCLUDE__PLATFORM_H_ */
|