genode/repos/base-sel4/src/core/include/platform.h
Norman Feske 9e6f3be806 sel4: update to version 2.1
This patch updates seL4 from the experimental branch of one year ago to
the master branch of version 2.1. The transition has the following
implications.

In contrast to the experimental branch, the master branch has no way to
manually define the allocation of kernel objects within untyped memory
ranges. Instead, the kernel maintains a built-in allocation policy. This
policy rules out the deallocation of once-used parts of untyped memory.
The only way to reuse memory is to revoke the entire untyped memory
range. Consequently, we cannot share a large untyped memory range for
kernel objects of different protection domains. In order to reuse memory
at a reasonably fine granularity, we need to split the initial untyped
memory ranges into small chunks that can be individually revoked. Those
chunks are called "untyped pages". An untyped page is a 4 KiB untyped
memory region.

The bootstrapping of core has to employ a two-stage allocation approach
now. For creating the initial kernel objects for core, which remain
static during the entire lifetime of the system, kernel objects are
created directly out of the initial untyped memory regions as reported
by the kernel. The so-called "initial untyped pool" keeps track of the
consumption of those untyped memory ranges by mimicking the kernel's
internal allocation policy. Kernel objects created this way can be of
any size. For example the phys CNode, which is used to store page-frame
capabilities is 16 MiB in size. Also, core's CSpace uses a relatively
large CNode.

After the initial setup phase, all remaining untyped memory is turned
into untyped pages. From this point on, new created kernel objects
cannot exceed 4 KiB in size because one kernel object cannot span
multiple untyped memory regions. The capability selectors for untyped
pages are organized similarly to those of page-frame capabilities. There
is a new 2nd-level CNode (UNTYPED_CORE_CNODE) that is dimensioned
according to the maximum amount of physical memory (1M entries, each
entry representing 4 KiB). The CNode is organized such that an index
into the CNode directly corresponds to the physical frame number of the
underlying memory. This way, we can easily determine a untyped page
selector for any physical addresses, i.e., for revoking the kernel
objects allocated at a specific physical page. The downside is the need
for another 16 MiB chunk of meta data. Also, we need to keep in mind
that this approach won't scale to 64-bit systems. We will eventually
need to replace the PHYS_CORE_CNODE and UNTYPED_CORE_CNODE by CNode
hierarchies to model a sparsely populated CNode.

The size constrain of kernel objects has the immediate implication that
the VM CSpaces of protection domains must be organized via several
levels of CNodes. I.e., as the top-level CNode of core has a size of
2^12, the remaining 20 PD-specific CSpace address bits are organized as
a 2nd-level 2^4 padding CNode, a 3rd-level 2^8 CNode, and several
4th-level 2^8 leaf CNodes. The latter contain the actual selectors for
the page tables and page-table entries of the respective PD.

As another slight difference from the experimental branch, the master
branch requires the explicit assignment of page directories to an ASID
pool.

Besides the adjustment to the new seL4 version, the patch introduces a
dedicated type for capability selectors. Previously, we just used to
represent them as unsigned integer values, which became increasingly
confusing. The new type 'Cap_sel' is a PD-local capability selector. The
type 'Cnode_index' is an index into a CNode (which is not generally not
the entire CSpace of the PD).

Fixes #1887
2016-02-26 11:36:55 +01:00

199 lines
5.8 KiB
C++

/*
* \brief Platform interface
* \author Norman Feske
* \date 2015-05-01
*/
/*
* 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.
*/
#ifndef _CORE__INCLUDE__PLATFORM_H_
#define _CORE__INCLUDE__PLATFORM_H_
/* Genode includes */
#include <base/printf.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>
namespace Genode { class Platform; }
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;
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;
size_t _vm_size;
/*
* 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.
*/
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 pages */
Cnode _untyped_cnode { Cap_sel(seL4_CapInitThreadCNode),
Cnode_index(Core_cspace::UNTYPED_CNODE_SEL),
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_PHYS_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;
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();
public:
/**
* Constructor
*/
Platform();
/********************************
** Generic platform interface **
********************************/
Range_allocator *ram_alloc() { return _core_mem_alloc.phys_alloc(); }
Range_allocator *io_mem_alloc() { return &_io_mem_alloc; }
Range_allocator *io_port_alloc() { return &_io_port_alloc; }
Range_allocator *irq_alloc() { return &_irq_alloc; }
Range_allocator *region_alloc() { return _core_mem_alloc.virt_alloc(); }
Range_allocator *core_mem_alloc() { return &_core_mem_alloc; }
addr_t vm_start() const { return _vm_base; }
size_t vm_size() const { return _vm_size; }
Rom_fs *rom_fs() { return &_rom_fs; }
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();
};
#endif /* _CORE__INCLUDE__PLATFORM_H_ */