diff --git a/base-hw/src/core/arm_v6/mode_transition.s b/base-hw/src/core/arm_v6/mode_transition.s
index eb870a2725..a8f06e9b38 100644
--- a/base-hw/src/core/arm_v6/mode_transition.s
+++ b/base-hw/src/core/arm_v6/mode_transition.s
@@ -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
diff --git a/base-hw/src/core/arm_v7/mode_transition.s b/base-hw/src/core/arm_v7/mode_transition.s
index 2478fd0523..1dbc38a1ec 100644
--- a/base-hw/src/core/arm_v7/mode_transition.s
+++ b/base-hw/src/core/arm_v7/mode_transition.s
@@ -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
diff --git a/base-hw/src/core/kernel.cc b/base-hw/src/core/kernel.cc
index aea960a8b5..0cde1168c8 100644
--- a/base-hw/src/core/kernel.cc
+++ b/base-hw/src/core/kernel.cc
@@ -27,9 +27,9 @@
#include
/* core includes */
+#include
#include
#include
-#include
#include
/* 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(); }
-
- /**
- * Kernel object that represents a Genode PD
- */
- class Pd : public Object
- {
- 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<= 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(this);
- mtc()->virt_user_entry();
+ mtc()->continue_user(static_cast(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();
+
+ /* initialize mode transition page */
+ return unsynchronized_singleton(k);
+}
diff --git a/base-hw/src/core/kernel/pd.h b/base-hw/src/core/kernel/pd.h
new file mode 100644
index 0000000000..a0aaa8cd25
--- /dev/null
+++ b/base-hw/src/core/kernel/pd.h
@@ -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
+#include
+#include
+#include
+#include
+
+/* 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
+{
+ 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_ */
diff --git a/base-hw/src/core/kernel/thread.h b/base-hw/src/core/kernel/thread.h
index 0ee8f64004..b79024c844 100644
--- a/base-hw/src/core/kernel/thread.h
+++ b/base-hw/src/core/kernel/thread.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;