diff --git a/repos/base-hw/lib/mk/arm/core.inc b/repos/base-hw/lib/mk/arm/core.inc index 5bfd4ecb3..309b16949 100644 --- a/repos/base-hw/lib/mk/arm/core.inc +++ b/repos/base-hw/lib/mk/arm/core.inc @@ -9,6 +9,9 @@ INC_DIR += $(REP_DIR)/src/core/include/spec/arm # add C++ sources SRC_CC += spec/arm/kernel/thread_base.cc +SRC_CC += spec/arm/kernel/thread.cc +SRC_CC += spec/arm/kernel/cpu.cc +SRC_CC += spec/arm/kernel/vm.cc # add assembly sources SRC_S += spec/arm/crt0.s diff --git a/repos/base-hw/src/core/include/kernel/cpu.h b/repos/base-hw/src/core/include/kernel/cpu.h index 21150e987..f660d50ab 100644 --- a/repos/base-hw/src/core/include/kernel/cpu.h +++ b/repos/base-hw/src/core/include/kernel/cpu.h @@ -16,6 +16,7 @@ #define _KERNEL__CPU_H_ /* core includes */ +#include #include #include #include @@ -25,6 +26,11 @@ namespace Kernel { + /** + * CPU context of a kernel stack + */ + class Cpu_context; + /** * Context of a job (thread, VM, idle) that shall be executed by a CPU */ @@ -56,6 +62,28 @@ namespace Kernel Cpu_pool * cpu_pool(); } +class Kernel::Cpu_context : Genode::Cpu::Context +{ + private: + + /** + * Hook for environment specific initializations + * + * \param stack_size size of kernel stack + * \param table base of transit translation table + */ + void _init(size_t const stack_size, addr_t const table); + + public: + + /** + * Constructor + * + * \param table mode-transition table + */ + Cpu_context(Genode::Translation_table * const table); +}; + class Kernel::Cpu_domain_update : public Double_list_item { friend class Cpu_domain_update_list; @@ -199,15 +227,7 @@ class Kernel::Cpu_idle : public Genode::Cpu::User_context, public Cpu_job * Cpu_job interface */ - void exception(unsigned const cpu) - { - switch (cpu_exception) { - case INTERRUPT_REQUEST: _interrupt(cpu); return; - case FAST_INTERRUPT_REQUEST: _interrupt(cpu); return; - case RESET: return; - default: assert(0); } - } - + void exception(unsigned const cpu); void proceed(unsigned const cpu_id); Cpu_job * helping_sink() { return this; } }; diff --git a/repos/base-hw/src/core/include/kernel/pd.h b/repos/base-hw/src/core/include/kernel/pd.h index dc779f874..9bb23f256 100644 --- a/repos/base-hw/src/core/include/kernel/pd.h +++ b/repos/base-hw/src/core/include/kernel/pd.h @@ -24,7 +24,7 @@ #include #include #include -#include +#include #include /* structure of the mode transition */ @@ -76,11 +76,6 @@ class Kernel::Lock namespace Kernel { - /** - * CPU context of the kernel - */ - class Cpu_context; - /** * Controls the mode-transition page * @@ -112,28 +107,6 @@ namespace Kernel Lock & data_lock(); } -class Kernel::Cpu_context : Cpu::Context -{ - private: - - /** - * Hook for environment specific initializations - * - * \param stack_size size of kernel stack - * \param table base of transit translation table - */ - void _init(size_t const stack_size, addr_t const table); - - public: - - /** - * Constructor - * - * \param table mode-transition table - */ - Cpu_context(Genode::Translation_table * const table); -}; - class Kernel::Mode_transition_control { friend class Pd; @@ -143,7 +116,6 @@ class Kernel::Mode_transition_control typedef Early_translations_allocator Allocator; typedef Early_translations_slab Slab; typedef Genode::Translation_table Table; - typedef Genode::Cpu_state_modes Cpu_state_modes; typedef Genode::Page_flags Page_flags; Allocator _allocator; @@ -244,7 +216,7 @@ class Kernel::Mode_transition_control /** * Continue execution of 'vm' at 'cpu' */ - void continue_vm(Cpu_state_modes * const vm, unsigned const cpu) { + void continue_vm(Vm_state * const vm, unsigned const cpu) { _continue_client(vm, cpu, (addr_t)&_mt_vm_entry_pic); } } __attribute__((aligned(Mode_transition_control::ALIGN))); diff --git a/repos/base-hw/src/core/include/kernel/vm.h b/repos/base-hw/src/core/include/kernel/vm.h index 79668e352..72fa7b30d 100644 --- a/repos/base-hw/src/core/include/kernel/vm.h +++ b/repos/base-hw/src/core/include/kernel/vm.h @@ -14,10 +14,8 @@ #ifndef _KERNEL__VM_H_ #define _KERNEL__VM_H_ -/* Genode includes */ -#include - /* core includes */ +#include #include #include #include @@ -41,11 +39,6 @@ class Kernel::Vm : public Object, { private: - struct Vm_state : Genode::Cpu_state_modes - { - Genode::addr_t dfar; - }; - Vm_state * const _state; Signal_context * const _context; @@ -76,21 +69,7 @@ class Kernel::Vm : public Object, ** Cpu_job ** *************/ - void exception(unsigned const cpu) - { - switch(_state->cpu_exception) { - case Genode::Cpu_state::INTERRUPT_REQUEST: - case Genode::Cpu_state::FAST_INTERRUPT_REQUEST: - _interrupt(cpu); - return; - case Genode::Cpu_state::DATA_ABORT: - _state->dfar = Cpu::Dfar::read(); - default: - Cpu_job::_deactivate_own_share(); - _context->submit(1); - } - } - + void exception(unsigned const cpu); void proceed(unsigned const cpu) { mtc()->continue_vm(_state, cpu); } Cpu_job * helping_sink() { return this; } }; diff --git a/repos/base-hw/src/core/include/spec/arm/kernel/vm_state.h b/repos/base-hw/src/core/include/spec/arm/kernel/vm_state.h new file mode 100644 index 000000000..223352f54 --- /dev/null +++ b/repos/base-hw/src/core/include/spec/arm/kernel/vm_state.h @@ -0,0 +1,29 @@ +/* + * \brief CPU context of a virtual machine + * \author Stefan Kalkowski + * \author Martin Stein + * \date 2013-10-30 + */ + +/* + * Copyright (C) 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__VM_STATE_H_ +#define _KERNEL__VM_STATE_H_ + +/* Genode includes */ +#include + +namespace Kernel +{ + /** + * CPU context of a virtual machine + */ + struct Vm_state : Genode::Cpu_state_modes { Genode::addr_t dfar; }; +} + +#endif /* _KERNEL__VM_STATE_H_ */ \ No newline at end of file diff --git a/repos/base-hw/src/core/kernel/cpu.cc b/repos/base-hw/src/core/kernel/cpu.cc index 6cf9fd142..01e6e70f4 100644 --- a/repos/base-hw/src/core/kernel/cpu.cc +++ b/repos/base-hw/src/core/kernel/cpu.cc @@ -124,15 +124,6 @@ void Cpu_job::affinity(Cpu * const cpu) ** Cpu_idle ** **************/ -Cpu_idle::Cpu_idle(Cpu * const cpu) : Cpu_job(Cpu_priority::min, 0) -{ - Cpu_job::cpu(cpu); - cpu_exception = RESET; - ip = (addr_t)&_main; - sp = (addr_t)&_stack[stack_size]; - init_thread((addr_t)core_pd()->translation_table(), core_pd()->id()); -} - void Cpu_idle::proceed(unsigned const cpu) { mtc()->continue_user(this, cpu); } diff --git a/repos/base-hw/src/core/kernel/thread.cc b/repos/base-hw/src/core/kernel/thread.cc index 8e89bb995..53c3881b6 100644 --- a/repos/base-hw/src/core/kernel/thread.cc +++ b/repos/base-hw/src/core/kernel/thread.cc @@ -159,14 +159,6 @@ void Thread::_become_inactive(State const s) } -Thread::Thread(unsigned const priority, unsigned const quota, - char const * const label) -: - Thread_base(this), Cpu_job(priority, quota), _state(AWAITS_START), _pd(0), - _utcb_phys(0), _signal_receiver(0), _label(label) -{ cpu_exception = RESET; } - - void Thread::init(Cpu * const cpu, Pd * const pd, Native_utcb * const utcb_phys, bool const start) { @@ -199,39 +191,6 @@ Cpu_job * Thread::helping_sink() { return static_cast(Ipc_node::helping_sink()); } -void Thread::exception(unsigned const cpu) -{ - switch (cpu_exception) { - case SUPERVISOR_CALL: - _call(); - return; - case PREFETCH_ABORT: - _mmu_exception(); - return; - case DATA_ABORT: - _mmu_exception(); - return; - case INTERRUPT_REQUEST: - _interrupt(cpu); - return; - case FAST_INTERRUPT_REQUEST: - _interrupt(cpu); - return; - case UNDEFINED_INSTRUCTION: - if (_cpu->retry_undefined_instr(&_lazy_state)) { return; } - PWRN("undefined instruction"); - _stop(); - return; - case RESET: - return; - default: - PWRN("unknown exception"); - _stop(); - return; - } -} - - void Thread::_receive_yielded_cpu() { if (_state == AWAITS_RESUME) { _become_active(); } @@ -822,26 +781,6 @@ void Thread::_call_bin_signal_receiver() } -void Thread::_call_new_vm() -{ - /* lookup signal context */ - auto const context = Signal_context::pool()->object(user_arg_3()); - if (!context) { - PWRN("failed to lookup signal context"); - user_arg_0(0); - return; - } - /* create virtual machine */ - typedef Genode::Cpu_state_modes Cpu_state_modes; - auto const allocator = reinterpret_cast(user_arg_1()); - auto const state = reinterpret_cast(user_arg_2()); - Vm * const vm = new (allocator) Vm(state, context); - - /* return kernel name of virtual machine */ - user_arg_0(vm->id()); -} - - void Thread::_call_run_vm() { /* lookup virtual machine */ diff --git a/repos/base-hw/src/core/spec/arm/kernel/cpu.cc b/repos/base-hw/src/core/spec/arm/kernel/cpu.cc new file mode 100644 index 000000000..998381e52 --- /dev/null +++ b/repos/base-hw/src/core/spec/arm/kernel/cpu.cc @@ -0,0 +1,46 @@ +/* + * \brief Class for kernel data that is needed to manage a specific CPU + * \author Martin Stein + * \author Stefan Kalkowski + * \date 2014-01-14 + */ + +/* + * Copyright (C) 2014 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. + */ + +/* core includes */ +#include +#include + +using namespace Kernel; + + +void Cpu_context::_init(size_t const stack_size, addr_t const table) +{ + r12 = stack_size; + cpu_exception = Genode::Cpu::Ttbr0::init(table); +} + + +Cpu_idle::Cpu_idle(Cpu * const cpu) : Cpu_job(Cpu_priority::min, 0) +{ + Cpu_job::cpu(cpu); + cpu_exception = RESET; + ip = (addr_t)&_main; + sp = (addr_t)&_stack[stack_size]; + init_thread((addr_t)core_pd()->translation_table(), core_pd()->id()); +} + + +void Cpu_idle::exception(unsigned const cpu) +{ + switch (cpu_exception) { + case INTERRUPT_REQUEST: _interrupt(cpu); return; + case FAST_INTERRUPT_REQUEST: _interrupt(cpu); return; + case RESET: return; + default: assert(0); } +} diff --git a/repos/base-hw/src/core/spec/arm/kernel/thread.cc b/repos/base-hw/src/core/spec/arm/kernel/thread.cc new file mode 100644 index 000000000..7064e6fff --- /dev/null +++ b/repos/base-hw/src/core/spec/arm/kernel/thread.cc @@ -0,0 +1,143 @@ +/* + * \brief Kernel backend for execution contexts in userland + * \author Martin Stein + * \author Stefan Kalkowski + * \date 2013-11-11 + */ + +/* + * Copyright (C) 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. + */ + +/* core includes */ +#include +#include +#include +#include + +using namespace Kernel; + + +Thread::Thread(unsigned const priority, unsigned const quota, + char const * const label) +: + Thread_base(this), Cpu_job(priority, quota), _state(AWAITS_START), _pd(0), + _utcb_phys(0), _signal_receiver(0), _label(label) +{ cpu_exception = RESET; } + + +void Thread::_call_new_vm() +{ + /* lookup signal context */ + auto const context = Signal_context::pool()->object(user_arg_3()); + if (!context) { + PWRN("failed to lookup signal context"); + user_arg_0(0); + return; + } + /* create virtual machine */ + typedef Genode::Cpu_state_modes Cpu_state_modes; + auto const allocator = reinterpret_cast(user_arg_1()); + auto const state = reinterpret_cast(user_arg_2()); + Vm * const vm = new (allocator) Vm(state, context); + + /* return kernel name of virtual machine */ + user_arg_0(vm->id()); +} + + +void Thread::exception(unsigned const cpu) +{ + switch (cpu_exception) { + case SUPERVISOR_CALL: + _call(); + return; + case PREFETCH_ABORT: + _mmu_exception(); + return; + case DATA_ABORT: + _mmu_exception(); + return; + case INTERRUPT_REQUEST: + _interrupt(cpu); + return; + case FAST_INTERRUPT_REQUEST: + _interrupt(cpu); + return; + case UNDEFINED_INSTRUCTION: + if (_cpu->retry_undefined_instr(&_lazy_state)) { return; } + PWRN("undefined instruction"); + _stop(); + return; + case RESET: + return; + default: + PWRN("unknown exception"); + _stop(); + return; + } +} + + +addr_t Thread::* Thread::_reg(addr_t const id) const +{ + static addr_t Thread::* const _regs[] = { + /* [0] */ (addr_t Thread::*)&Thread::r0, + /* [1] */ (addr_t Thread::*)&Thread::r1, + /* [2] */ (addr_t Thread::*)&Thread::r2, + /* [3] */ (addr_t Thread::*)&Thread::r3, + /* [4] */ (addr_t Thread::*)&Thread::r4, + /* [5] */ (addr_t Thread::*)&Thread::r5, + /* [6] */ (addr_t Thread::*)&Thread::r6, + /* [7] */ (addr_t Thread::*)&Thread::r7, + /* [8] */ (addr_t Thread::*)&Thread::r8, + /* [9] */ (addr_t Thread::*)&Thread::r9, + /* [10] */ (addr_t Thread::*)&Thread::r10, + /* [11] */ (addr_t Thread::*)&Thread::r11, + /* [12] */ (addr_t Thread::*)&Thread::r12, + /* [13] */ (addr_t Thread::*)&Thread::sp, + /* [14] */ (addr_t Thread::*)&Thread::lr, + /* [15] */ (addr_t Thread::*)&Thread::ip, + /* [16] */ (addr_t Thread::*)&Thread::cpsr, + /* [17] */ (addr_t Thread::*)&Thread::cpu_exception, + /* [18] */ (addr_t Thread::*)&Thread::_fault_pd, + /* [19] */ (addr_t Thread::*)&Thread::_fault_addr, + /* [20] */ (addr_t Thread::*)&Thread::_fault_writes, + /* [21] */ (addr_t Thread::*)&Thread::_fault_signal + }; + return id < sizeof(_regs)/sizeof(_regs[0]) ? _regs[id] : 0; +} + + +Thread_event Thread::* Thread::_event(unsigned const id) const +{ + static Thread_event Thread::* _events[] = { + /* [0] */ &Thread::_fault + }; + return id < sizeof(_events)/sizeof(_events[0]) ? _events[id] : 0; +} + + +void Thread::_mmu_exception() +{ + _become_inactive(AWAITS_RESUME); + if (in_fault(_fault_addr, _fault_writes)) { + _fault_pd = (addr_t)_pd->platform_pd(); + _fault_signal = _fault.signal_context_id(); + + /** + * core should never raise a page-fault, + * if this happens print out an error message with debug information + */ + if (_pd == Kernel::core_pd()) + PERR("Pagefault in core thread (%s): ip=%p fault=%p", + label(), (void*)ip, (void*)_fault_addr); + + _fault.submit(); + return; + } + PERR("unknown MMU exception"); +} diff --git a/repos/base-hw/src/core/spec/arm/kernel/thread_base.cc b/repos/base-hw/src/core/spec/arm/kernel/thread_base.cc index 5a97ecf46..3dca6539d 100644 --- a/repos/base-hw/src/core/spec/arm/kernel/thread_base.cc +++ b/repos/base-hw/src/core/spec/arm/kernel/thread_base.cc @@ -14,8 +14,6 @@ /* core includes */ #include -#include -#include using namespace Kernel; @@ -34,82 +32,6 @@ Thread_base::Thread_base(Thread * const t) { } -/******************** - ** Kernel::Thread ** - ********************/ - -addr_t Thread::* Thread::_reg(addr_t const id) const -{ - static addr_t Thread::* const _regs[] = { - /* [0] */ (addr_t Thread::*)&Thread::r0, - /* [1] */ (addr_t Thread::*)&Thread::r1, - /* [2] */ (addr_t Thread::*)&Thread::r2, - /* [3] */ (addr_t Thread::*)&Thread::r3, - /* [4] */ (addr_t Thread::*)&Thread::r4, - /* [5] */ (addr_t Thread::*)&Thread::r5, - /* [6] */ (addr_t Thread::*)&Thread::r6, - /* [7] */ (addr_t Thread::*)&Thread::r7, - /* [8] */ (addr_t Thread::*)&Thread::r8, - /* [9] */ (addr_t Thread::*)&Thread::r9, - /* [10] */ (addr_t Thread::*)&Thread::r10, - /* [11] */ (addr_t Thread::*)&Thread::r11, - /* [12] */ (addr_t Thread::*)&Thread::r12, - /* [13] */ (addr_t Thread::*)&Thread::sp, - /* [14] */ (addr_t Thread::*)&Thread::lr, - /* [15] */ (addr_t Thread::*)&Thread::ip, - /* [16] */ (addr_t Thread::*)&Thread::cpsr, - /* [17] */ (addr_t Thread::*)&Thread::cpu_exception, - /* [18] */ (addr_t Thread::*)&Thread::_fault_pd, - /* [19] */ (addr_t Thread::*)&Thread::_fault_addr, - /* [20] */ (addr_t Thread::*)&Thread::_fault_writes, - /* [21] */ (addr_t Thread::*)&Thread::_fault_signal - }; - return id < sizeof(_regs)/sizeof(_regs[0]) ? _regs[id] : 0; -} - - -Thread_event Thread::* Thread::_event(unsigned const id) const -{ - static Thread_event Thread::* _events[] = { - /* [0] */ &Thread::_fault - }; - return id < sizeof(_events)/sizeof(_events[0]) ? _events[id] : 0; -} - - -void Thread::_mmu_exception() -{ - _become_inactive(AWAITS_RESUME); - if (in_fault(_fault_addr, _fault_writes)) { - _fault_pd = (addr_t)_pd->platform_pd(); - _fault_signal = _fault.signal_context_id(); - - /** - * core should never raise a page-fault, - * if this happens print out an error message with debug information - */ - if (_pd == Kernel::core_pd()) - PERR("Pagefault in core thread (%s): ip=%p fault=%p", - label(), (void*)ip, (void*)_fault_addr); - - _fault.submit(); - return; - } - PERR("unknown MMU exception"); -} - - -/************************* - ** Kernel::Cpu_context ** - *************************/ - -void Kernel::Cpu_context::_init(size_t const stack_size, addr_t const table) -{ - r12 = stack_size; - cpu_exception = Genode::Cpu::Ttbr0::init(table); -} - - /************************* ** CPU-state utilities ** *************************/ diff --git a/repos/base-hw/src/core/spec/arm/kernel/vm.cc b/repos/base-hw/src/core/spec/arm/kernel/vm.cc new file mode 100644 index 000000000..ad04f0f46 --- /dev/null +++ b/repos/base-hw/src/core/spec/arm/kernel/vm.cc @@ -0,0 +1,33 @@ +/* + * \brief Kernel backend for virtual machines + * \author Martin Stein + * \date 2013-10-30 + */ + +/* + * Copyright (C) 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. + */ + +/* core includes */ +#include + +using namespace Kernel; + + +void Vm::exception(unsigned const cpu) +{ + switch(_state->cpu_exception) { + case Genode::Cpu_state::INTERRUPT_REQUEST: + case Genode::Cpu_state::FAST_INTERRUPT_REQUEST: + _interrupt(cpu); + return; + case Genode::Cpu_state::DATA_ABORT: + _state->dfar = Cpu::Dfar::read(); + default: + Cpu_job::_deactivate_own_share(); + _context->submit(1); + } +}