mirror of
https://github.com/genodelabs/genode.git
synced 2025-01-31 16:35:28 +00:00
parent
5f64411ad7
commit
1843f10c62
@ -118,8 +118,8 @@
|
||||
* region, thus one should map it solely accessable for privileged modes.
|
||||
*/
|
||||
.p2align 12
|
||||
.global _mode_transition_begin
|
||||
_mode_transition_begin:
|
||||
.global _mt_begin
|
||||
_mt_begin:
|
||||
|
||||
/*
|
||||
* On user exceptions the CPU has to jump to one of the following
|
||||
@ -225,10 +225,10 @@
|
||||
_mt_buffer: .long 0
|
||||
|
||||
.p2align 2
|
||||
.global _mode_transition_end
|
||||
_mode_transition_end:
|
||||
.global _mt_end
|
||||
_mt_end:
|
||||
|
||||
/* FIXME this exists only because _vm_mon_entry pollutes kernel.cc */
|
||||
.global _mon_vm_entry
|
||||
_mon_vm_entry:
|
||||
.global _mt_vm_entry_pic
|
||||
_mt_vm_entry_pic:
|
||||
1: b 1b
|
||||
|
@ -248,8 +248,8 @@
|
||||
* region, thus one should map it solely accessable for privileged modes.
|
||||
*/
|
||||
.p2align 12 /* page-aligned */
|
||||
.global _mode_transition_begin
|
||||
_mode_transition_begin:
|
||||
.global _mt_begin
|
||||
_mt_begin:
|
||||
|
||||
/*
|
||||
* On user exceptions the CPU has to jump to one of the following
|
||||
@ -299,8 +299,8 @@
|
||||
.global _mt_buffer
|
||||
_mt_buffer: .long 0
|
||||
|
||||
.global _mode_transition_end
|
||||
_mode_transition_end:
|
||||
.global _mt_end
|
||||
_mt_end:
|
||||
|
||||
/*
|
||||
* On vm exceptions the CPU has to jump to one of the following
|
||||
@ -328,6 +328,6 @@
|
||||
|
||||
/* kernel must jump to this point to switch to a vm */
|
||||
.p2align 2
|
||||
.global _mon_vm_entry
|
||||
_mon_vm_entry:
|
||||
.global _mt_vm_entry_pic
|
||||
_mt_vm_entry_pic:
|
||||
_kernel_to_vm
|
||||
|
@ -27,9 +27,9 @@
|
||||
#include <base/thread_state.h>
|
||||
|
||||
/* core includes */
|
||||
#include <kernel/pd.h>
|
||||
#include <platform_thread.h>
|
||||
#include <platform_pd.h>
|
||||
#include <tlb.h>
|
||||
#include <trustzone.h>
|
||||
|
||||
/* base-hw includes */
|
||||
@ -42,15 +42,6 @@ extern Genode::Native_utcb * _main_utcb;
|
||||
extern int _kernel_stack_high;
|
||||
extern "C" void CORE_MAIN();
|
||||
|
||||
/* get structure of mode transition PIC */
|
||||
extern int _mode_transition_begin;
|
||||
extern int _mode_transition_end;
|
||||
extern int _mt_user_entry_pic;
|
||||
extern int _mon_vm_entry;
|
||||
extern Genode::addr_t _mt_client_context_ptr;
|
||||
extern Genode::addr_t _mt_master_context_begin;
|
||||
extern Genode::addr_t _mt_master_context_end;
|
||||
|
||||
namespace Kernel
|
||||
{
|
||||
/* import Genode types */
|
||||
@ -58,138 +49,6 @@ namespace Kernel
|
||||
typedef Genode::umword_t umword_t;
|
||||
|
||||
class Schedule_context;
|
||||
|
||||
/**
|
||||
* Controls the mode transition code
|
||||
*
|
||||
* The code that switches between kernel/user mode must not exceed the
|
||||
* smallest page size supported by the MMU. The Code must be position
|
||||
* independent. This code has to be mapped in every PD, to ensure
|
||||
* appropriate kernel invokation on CPU interrupts.
|
||||
* This class controls the settings like kernel, user, and VM states
|
||||
* that are handled by the mode transition PIC.
|
||||
*/
|
||||
struct Mode_transition_control
|
||||
{
|
||||
enum {
|
||||
SIZE_LOG2 = Tlb::MIN_PAGE_SIZE_LOG2,
|
||||
SIZE = 1 << SIZE_LOG2,
|
||||
VIRT_BASE = Cpu::EXCEPTION_ENTRY,
|
||||
VIRT_END = VIRT_BASE + SIZE,
|
||||
ALIGNM_LOG2 = SIZE_LOG2,
|
||||
};
|
||||
|
||||
addr_t const _virt_user_entry;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
Mode_transition_control() :
|
||||
_virt_user_entry(VIRT_BASE + ((addr_t)&_mt_user_entry_pic -
|
||||
(addr_t)&_mode_transition_begin))
|
||||
{
|
||||
/* check if mode transition PIC fits into aligned region */
|
||||
addr_t const pic_begin = (addr_t)&_mode_transition_begin;
|
||||
addr_t const pic_end = (addr_t)&_mode_transition_end;
|
||||
size_t const pic_size = pic_end - pic_begin;
|
||||
assert(pic_size <= SIZE);
|
||||
|
||||
/* check if kernel context fits into the mode transition */
|
||||
addr_t const kc_begin = (addr_t)&_mt_master_context_begin;
|
||||
addr_t const kc_end = (addr_t)&_mt_master_context_end;
|
||||
size_t const kc_size = kc_end - kc_begin;
|
||||
assert(sizeof(Cpu::Context) <= kc_size);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch next kernelmode context
|
||||
*/
|
||||
void fetch_master_context(Cpu::Context * const c) {
|
||||
memcpy(&_mt_master_context_begin, c, sizeof(Cpu::Context)); }
|
||||
|
||||
/**
|
||||
* Page aligned physical base of the mode transition PIC
|
||||
*/
|
||||
addr_t phys_base() { return (addr_t)&_mode_transition_begin; }
|
||||
|
||||
/**
|
||||
* Jump to the usermode entry PIC
|
||||
*/
|
||||
void virt_user_entry() {
|
||||
((void(*)(void))_virt_user_entry)(); }
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Static mode transition control
|
||||
*/
|
||||
static Mode_transition_control * mtc()
|
||||
{ return unsynchronized_singleton<Mode_transition_control>(); }
|
||||
|
||||
/**
|
||||
* Kernel object that represents a Genode PD
|
||||
*/
|
||||
class Pd : public Object<Pd, MAX_PDS>
|
||||
{
|
||||
Tlb * const _tlb;
|
||||
Platform_pd * const _platform_pd;
|
||||
|
||||
/* keep ready memory for size aligned extra costs at construction */
|
||||
enum { EXTRA_SPACE_SIZE = 2*Tlb::MAX_COSTS_PER_TRANSLATION };
|
||||
char _extra_space[EXTRA_SPACE_SIZE];
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
Pd(Tlb * const t, Platform_pd * const platform_pd)
|
||||
: _tlb(t), _platform_pd(platform_pd)
|
||||
{
|
||||
/* try to add translation for mode transition region */
|
||||
Page_flags::access_t const flags = Page_flags::mode_transition();
|
||||
unsigned const slog2 =
|
||||
tlb()->insert_translation(mtc()->VIRT_BASE,
|
||||
mtc()->phys_base(),
|
||||
mtc()->SIZE_LOG2, flags);
|
||||
|
||||
/* extra space needed to translate mode transition region */
|
||||
if (slog2)
|
||||
{
|
||||
/* Get size aligned extra space */
|
||||
addr_t const es = (addr_t)&_extra_space;
|
||||
addr_t const es_end = es + sizeof(_extra_space);
|
||||
addr_t const aligned_es = (es_end - (1<<slog2)) &
|
||||
~((1<<slog2)-1);
|
||||
addr_t const aligned_es_end = aligned_es + (1<<slog2);
|
||||
|
||||
/* check attributes of aligned extra space */
|
||||
assert(aligned_es >= es && aligned_es_end <= es_end)
|
||||
|
||||
/* translate mode transition region globally */
|
||||
tlb()->insert_translation(mtc()->VIRT_BASE,
|
||||
mtc()->phys_base(),
|
||||
mtc()->SIZE_LOG2, flags,
|
||||
(void *)aligned_es);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the CPU context 'c' to this PD
|
||||
*/
|
||||
void append_context(Cpu::Context * const c)
|
||||
{
|
||||
c->protection_domain(id());
|
||||
c->tlb(tlb()->base());
|
||||
}
|
||||
|
||||
/***************
|
||||
** Accessors **
|
||||
***************/
|
||||
|
||||
Tlb * const tlb() { return _tlb; }
|
||||
Platform_pd * const platform_pd() { return _platform_pd; }
|
||||
};
|
||||
}
|
||||
|
||||
namespace Kernel
|
||||
@ -229,7 +88,6 @@ namespace Kernel
|
||||
return pd;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get core attributes
|
||||
*/
|
||||
@ -325,8 +183,7 @@ void Kernel::Thread::handle_exception()
|
||||
|
||||
void Kernel::Thread::proceed()
|
||||
{
|
||||
_mt_client_context_ptr = (addr_t)static_cast<Genode::Cpu_state*>(this);
|
||||
mtc()->virt_user_entry();
|
||||
mtc()->continue_user(static_cast<Cpu::Context *>(this));
|
||||
}
|
||||
|
||||
|
||||
@ -353,7 +210,6 @@ void Kernel::Thread::_awaits_irq()
|
||||
|
||||
namespace Kernel
|
||||
{
|
||||
|
||||
void deliver_signal(Signal_handler * const dst,
|
||||
void * const base,
|
||||
size_t const size)
|
||||
@ -406,14 +262,7 @@ namespace Kernel
|
||||
}
|
||||
}
|
||||
|
||||
void proceed()
|
||||
{
|
||||
/* set context pointer for mode switch */
|
||||
_mt_client_context_ptr = (addr_t)_state;
|
||||
|
||||
/* jump to assembler path */
|
||||
((void(*)(void))&_mon_vm_entry)();
|
||||
}
|
||||
void proceed() { mtc()->continue_vm(_state); }
|
||||
};
|
||||
|
||||
|
||||
@ -1109,17 +958,6 @@ extern "C" void kernel()
|
||||
/* enable kernel timer */
|
||||
pic()->unmask(Timer::IRQ);
|
||||
|
||||
/* compose kernel CPU context */
|
||||
static Cpu::Context kernel_context;
|
||||
kernel_context.ip = (addr_t)kernel;
|
||||
kernel_context.sp = (addr_t)&_kernel_stack_high;
|
||||
|
||||
/* add kernel to the core PD */
|
||||
core()->append_context(&kernel_context);
|
||||
|
||||
/* offer the final kernel context to the mode transition page */
|
||||
mtc()->fetch_master_context(&kernel_context);
|
||||
|
||||
/* TrustZone initialization code */
|
||||
trustzone_initialization(pic());
|
||||
|
||||
@ -1272,3 +1110,23 @@ void Thread::kill_signal_context_done()
|
||||
user_arg_0(1);
|
||||
_schedule();
|
||||
}
|
||||
|
||||
static Kernel::Mode_transition_control * Kernel::mtc()
|
||||
{
|
||||
/* compose CPU context for kernel entry */
|
||||
struct Kernel_context : Cpu::Context
|
||||
{
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
Kernel_context()
|
||||
{
|
||||
ip = (addr_t)kernel;
|
||||
sp = (addr_t)&_kernel_stack_high;
|
||||
core()->admit(this);
|
||||
}
|
||||
} * const k = unsynchronized_singleton<Kernel_context>();
|
||||
|
||||
/* initialize mode transition page */
|
||||
return unsynchronized_singleton<Mode_transition_control>(k);
|
||||
}
|
||||
|
206
base-hw/src/core/kernel/pd.h
Normal file
206
base-hw/src/core/kernel/pd.h
Normal file
@ -0,0 +1,206 @@
|
||||
/*
|
||||
* \brief Kernel backend for protection domains
|
||||
* \author Martin Stein
|
||||
* \date 2012-11-30
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2012-2013 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 _KERNEL__PD_H_
|
||||
#define _KERNEL__PD_H_
|
||||
|
||||
/* core includes */
|
||||
#include <kernel/configuration.h>
|
||||
#include <kernel/object.h>
|
||||
#include <tlb.h>
|
||||
#include <cpu.h>
|
||||
#include <assert.h>
|
||||
|
||||
/* structure of the mode transition */
|
||||
extern int _mt_begin;
|
||||
extern int _mt_end;
|
||||
extern int _mt_user_entry_pic;
|
||||
extern int _mt_vm_entry_pic;
|
||||
extern Genode::addr_t _mt_client_context_ptr;
|
||||
extern Genode::addr_t _mt_master_context_begin;
|
||||
extern Genode::addr_t _mt_master_context_end;
|
||||
|
||||
namespace Kernel
|
||||
{
|
||||
/**
|
||||
* Controls the mode-transition page
|
||||
*
|
||||
* The mode transition page is a small memory region that is mapped by
|
||||
* every PD to the same virtual address. It contains code that acts as a
|
||||
* link between high privileged CPU mode (often called kernel) and low
|
||||
* privileged CPU mode (often called userland). The mode transition
|
||||
* control provides a simple interface to access the code from within
|
||||
* the kernel.
|
||||
*/
|
||||
struct Mode_transition_control;
|
||||
|
||||
/**
|
||||
* Return the system wide mode-transition control
|
||||
*/
|
||||
static Mode_transition_control * mtc();
|
||||
|
||||
/**
|
||||
* Kernel backend of protection domains
|
||||
*/
|
||||
class Pd;
|
||||
}
|
||||
|
||||
class Kernel::Mode_transition_control
|
||||
{
|
||||
friend class Pd;
|
||||
|
||||
private:
|
||||
|
||||
typedef Genode::Cpu Cpu;
|
||||
typedef Genode::Cpu_state_modes Cpu_state_modes;
|
||||
typedef Genode::Page_flags Page_flags;
|
||||
|
||||
addr_t const _virt_user_entry;
|
||||
|
||||
public:
|
||||
|
||||
enum {
|
||||
SIZE_LOG2 = Tlb::MIN_PAGE_SIZE_LOG2,
|
||||
SIZE = 1 << SIZE_LOG2,
|
||||
VIRT_BASE = Cpu::EXCEPTION_ENTRY,
|
||||
VIRT_END = VIRT_BASE + SIZE,
|
||||
ALIGNM_LOG2 = SIZE_LOG2,
|
||||
};
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* \param c CPU context for kernel mode entry
|
||||
*/
|
||||
Mode_transition_control(Cpu::Context * const c)
|
||||
:
|
||||
_virt_user_entry(VIRT_BASE + ((addr_t)&_mt_user_entry_pic -
|
||||
(addr_t)&_mt_begin))
|
||||
{
|
||||
/* check if mode transition fits into aligned region */
|
||||
addr_t const mt_begin = (addr_t)&_mt_begin;
|
||||
addr_t const mt_end = (addr_t)&_mt_end;
|
||||
size_t const mt_size = mt_end - mt_begin;
|
||||
assert(mt_size <= SIZE);
|
||||
|
||||
/* check if kernel context fits into the mode transition */
|
||||
addr_t const kc_begin = (addr_t)&_mt_master_context_begin;
|
||||
addr_t const kc_end = (addr_t)&_mt_master_context_end;
|
||||
size_t const kc_size = kc_end - kc_begin;
|
||||
assert(sizeof(Cpu::Context) <= kc_size);
|
||||
|
||||
/* fetch kernel-mode context */
|
||||
Genode::memcpy(&_mt_master_context_begin, c, sizeof(Cpu::Context));
|
||||
}
|
||||
|
||||
/**
|
||||
* Map the mode transition page to a virtual address space
|
||||
*
|
||||
* \param tlb translation buffer of the address space
|
||||
* \param ram RAM donation for mapping (first try without)
|
||||
*
|
||||
* \return RAM-donation size that is needed to do the mapping
|
||||
*/
|
||||
size_t map(Tlb * tlb, addr_t ram = 0)
|
||||
{
|
||||
Page_flags::access_t const flags = Page_flags::mode_transition();
|
||||
addr_t const phys_base = (addr_t)&_mt_begin;
|
||||
return tlb->insert_translation(VIRT_BASE, phys_base, SIZE_LOG2,
|
||||
flags, (void *)ram);
|
||||
}
|
||||
|
||||
/**
|
||||
* Continue user-mode execution with CPU context 'c'
|
||||
*/
|
||||
void continue_user(Cpu::Context * const c)
|
||||
{
|
||||
_mt_client_context_ptr = (addr_t)c;
|
||||
((void(*)(void))_virt_user_entry)();
|
||||
}
|
||||
|
||||
/**
|
||||
* Continue VM execution with CPU state 's'
|
||||
*/
|
||||
void continue_vm(Cpu_state_modes * s)
|
||||
{
|
||||
_mt_client_context_ptr = (addr_t)s;
|
||||
((void(*)(void))&_mt_vm_entry_pic)();
|
||||
}
|
||||
};
|
||||
|
||||
class Kernel::Pd : public Object<Pd, MAX_PDS>
|
||||
{
|
||||
private:
|
||||
|
||||
typedef Genode::Cpu Cpu;
|
||||
|
||||
Tlb * const _tlb;
|
||||
Platform_pd * const _platform_pd;
|
||||
|
||||
/* keep ready memory for size-aligned extra costs at construction */
|
||||
enum { EXTRA_RAM_SIZE = 2 * Tlb::MAX_COSTS_PER_TRANSLATION };
|
||||
char _extra_ram[EXTRA_RAM_SIZE];
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* \param tlb translation lookaside buffer of the PD
|
||||
* \param platform_pd core object of the PD
|
||||
*/
|
||||
Pd(Tlb * const tlb, Platform_pd * const platform_pd)
|
||||
:
|
||||
_tlb(tlb), _platform_pd(platform_pd)
|
||||
{
|
||||
/* try to add translation for mode transition region */
|
||||
unsigned const slog2 = mtc()->map(tlb);
|
||||
|
||||
/* extra ram needed to translate mode transition region */
|
||||
if (slog2)
|
||||
{
|
||||
/* get size aligned extra ram */
|
||||
addr_t const ram = (addr_t)&_extra_ram;
|
||||
addr_t const ram_end = ram + sizeof(_extra_ram);
|
||||
addr_t const aligned_ram = (ram_end - (1 << slog2)) &
|
||||
~((1 << slog2) - 1);
|
||||
addr_t const aligned_ram_end = aligned_ram + (1 << slog2);
|
||||
|
||||
/* check attributes of aligned extra ram */
|
||||
assert(aligned_ram >= ram && aligned_ram_end <= ram_end)
|
||||
|
||||
/* translate mode transition region globally */
|
||||
mtc()->map(tlb, aligned_ram);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Let the CPU context 'c' join the PD
|
||||
*/
|
||||
void admit(Cpu::Context * const c)
|
||||
{
|
||||
c->protection_domain(id());
|
||||
c->tlb(tlb()->base());
|
||||
}
|
||||
|
||||
|
||||
/***************
|
||||
** Accessors **
|
||||
***************/
|
||||
|
||||
Tlb * tlb() const { return _tlb; }
|
||||
|
||||
Platform_pd * platform_pd() const { return _platform_pd; }
|
||||
};
|
||||
|
||||
#endif /* _KERNEL__PD_H_ */
|
@ -33,7 +33,6 @@ namespace Genode
|
||||
namespace Kernel
|
||||
{
|
||||
typedef Genode::Cpu Cpu;
|
||||
typedef Genode::Page_flags Page_flags;
|
||||
typedef Genode::Core_tlb Core_tlb;
|
||||
typedef Genode::Pagefault Pagefault;
|
||||
typedef Genode::Native_utcb Native_utcb;
|
||||
|
Loading…
x
Reference in New Issue
Block a user