From 1843f10c6227ae9c25f68a11cf4eacbd6bc9109f Mon Sep 17 00:00:00 2001 From: Martin Stein Date: Fri, 6 Sep 2013 17:37:09 +0200 Subject: [PATCH] hw: PD in extra header with asserts reviewed ref #528 --- base-hw/src/core/arm_v6/mode_transition.s | 12 +- base-hw/src/core/arm_v7/mode_transition.s | 12 +- base-hw/src/core/kernel.cc | 188 +++----------------- base-hw/src/core/kernel/pd.h | 206 ++++++++++++++++++++++ base-hw/src/core/kernel/thread.h | 1 - 5 files changed, 241 insertions(+), 178 deletions(-) create mode 100644 base-hw/src/core/kernel/pd.h 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;