parent
0635d5fffb
commit
d6a05245f2
|
@ -9,8 +9,8 @@ INC_DIR += $(BASE_DIR)/../base-hw/src/core/spec/arm
|
||||||
|
|
||||||
# add C++ sources
|
# add C++ sources
|
||||||
SRC_CC += spec/32bit/memory_map.cc
|
SRC_CC += spec/32bit/memory_map.cc
|
||||||
|
SRC_CC += spec/arm/cpu.cc
|
||||||
SRC_CC += spec/arm/kernel/thread.cc
|
SRC_CC += spec/arm/kernel/thread.cc
|
||||||
SRC_CC += spec/arm/kernel/pd.cc
|
|
||||||
SRC_CC += spec/arm/platform_support.cc
|
SRC_CC += spec/arm/platform_support.cc
|
||||||
|
|
||||||
# add assembly sources
|
# add assembly sources
|
||||||
|
|
|
@ -9,6 +9,7 @@ INC_DIR += $(BASE_DIR)/../base-hw/src/core/spec/cortex_a15
|
||||||
INC_DIR += $(BASE_DIR)/../base-hw/src/core/spec/arm_gic
|
INC_DIR += $(BASE_DIR)/../base-hw/src/core/spec/arm_gic
|
||||||
|
|
||||||
# add C++ sources
|
# add C++ sources
|
||||||
|
SRC_CC += spec/cortex_a15/cpu.cc
|
||||||
SRC_CC += spec/cortex_a15/kernel/cpu.cc
|
SRC_CC += spec/cortex_a15/kernel/cpu.cc
|
||||||
SRC_CC += spec/arm/smp/kernel/thread_update_pd.cc
|
SRC_CC += spec/arm/smp/kernel/thread_update_pd.cc
|
||||||
SRC_CC += spec/arm/smp/kernel/cpu.cc
|
SRC_CC += spec/arm/smp/kernel/cpu.cc
|
||||||
|
|
|
@ -13,7 +13,6 @@ SRC_CC += spec/cortex_a9/kernel/cpu.cc
|
||||||
SRC_CC += spec/cortex_a9/fpu.cc
|
SRC_CC += spec/cortex_a9/fpu.cc
|
||||||
SRC_CC += spec/cortex_a9/board.cc
|
SRC_CC += spec/cortex_a9/board.cc
|
||||||
SRC_CC += spec/cortex_a9/timer.cc
|
SRC_CC += spec/cortex_a9/timer.cc
|
||||||
SRC_CC += spec/arm/cpu.cc
|
|
||||||
SRC_CC += spec/arm/smp/kernel/thread_update_pd.cc
|
SRC_CC += spec/arm/smp/kernel/thread_update_pd.cc
|
||||||
SRC_CC += spec/arm/smp/kernel/cpu.cc
|
SRC_CC += spec/arm/smp/kernel/cpu.cc
|
||||||
SRC_CC += spec/arm_gic/pic.cc
|
SRC_CC += spec/arm_gic/pic.cc
|
||||||
|
|
|
@ -11,7 +11,6 @@ INC_DIR += $(REP_DIR)/src/core/spec/imx53
|
||||||
|
|
||||||
SRC_CC += spec/imx53/pic.cc
|
SRC_CC += spec/imx53/pic.cc
|
||||||
SRC_CC += spec/imx53/timer.cc
|
SRC_CC += spec/imx53/timer.cc
|
||||||
SRC_CC += spec/arm/cpu_trustzone.cc
|
|
||||||
|
|
||||||
ifneq ($(filter-out $(SPECS),trustzone),)
|
ifneq ($(filter-out $(SPECS),trustzone),)
|
||||||
SRC_CC += kernel/vm_thread_off.cc
|
SRC_CC += kernel/vm_thread_off.cc
|
||||||
|
|
|
@ -18,7 +18,6 @@ SRC_S += spec/x86_64/crt0.s
|
||||||
SRC_S += spec/x86_64/exception_vector.s
|
SRC_S += spec/x86_64/exception_vector.s
|
||||||
|
|
||||||
# add C++ sources
|
# add C++ sources
|
||||||
SRC_CC += spec/x86_64/muen/kernel/cpu_exception.cc
|
|
||||||
SRC_CC += spec/x86_64/muen/kernel/thread_exception.cc
|
SRC_CC += spec/x86_64/muen/kernel/thread_exception.cc
|
||||||
SRC_CC += spec/x86_64/muen/platform_support.cc
|
SRC_CC += spec/x86_64/muen/platform_support.cc
|
||||||
SRC_CC += spec/x86_64/muen/kernel/vm.cc
|
SRC_CC += spec/x86_64/muen/kernel/vm.cc
|
||||||
|
@ -34,7 +33,6 @@ SRC_CC += spec/x86_64/bios_data_area.cc
|
||||||
SRC_CC += spec/x86_64/cpu.cc
|
SRC_CC += spec/x86_64/cpu.cc
|
||||||
SRC_CC += spec/x86_64/fpu.cc
|
SRC_CC += spec/x86_64/fpu.cc
|
||||||
SRC_CC += spec/x86_64/kernel/cpu.cc
|
SRC_CC += spec/x86_64/kernel/cpu.cc
|
||||||
SRC_CC += spec/x86_64/kernel/pd.cc
|
|
||||||
SRC_CC += spec/x86_64/kernel/thread.cc
|
SRC_CC += spec/x86_64/kernel/thread.cc
|
||||||
SRC_CC += spec/x86_64/kernel/thread.cc
|
SRC_CC += spec/x86_64/kernel/thread.cc
|
||||||
SRC_CC += spec/x86_64/platform_support_common.cc
|
SRC_CC += spec/x86_64/platform_support_common.cc
|
||||||
|
|
|
@ -5,8 +5,8 @@ CC_OPT += -fno-delete-null-pointer-checks
|
||||||
# add C++ sources
|
# add C++ sources
|
||||||
SRC_CC += platform_services.cc
|
SRC_CC += platform_services.cc
|
||||||
SRC_CC += kernel/vm_thread_off.cc kernel/kernel.cc
|
SRC_CC += kernel/vm_thread_off.cc kernel/kernel.cc
|
||||||
|
SRC_CC += spec/riscv/cpu.cc
|
||||||
SRC_CC += spec/riscv/kernel/thread.cc
|
SRC_CC += spec/riscv/kernel/thread.cc
|
||||||
SRC_CC += spec/riscv/kernel/pd.cc
|
|
||||||
SRC_CC += spec/riscv/kernel/cpu.cc
|
SRC_CC += spec/riscv/kernel/cpu.cc
|
||||||
SRC_CC += spec/riscv/platform_support.cc
|
SRC_CC += spec/riscv/platform_support.cc
|
||||||
SRC_CC += spec/riscv/timer.cc
|
SRC_CC += spec/riscv/timer.cc
|
||||||
|
|
|
@ -27,7 +27,6 @@ SRC_CC += spec/x86_64/bios_data_area.cc
|
||||||
SRC_CC += spec/x86_64/cpu.cc
|
SRC_CC += spec/x86_64/cpu.cc
|
||||||
SRC_CC += spec/x86_64/fpu.cc
|
SRC_CC += spec/x86_64/fpu.cc
|
||||||
SRC_CC += spec/x86_64/kernel/cpu.cc
|
SRC_CC += spec/x86_64/kernel/cpu.cc
|
||||||
SRC_CC += spec/x86_64/kernel/pd.cc
|
|
||||||
SRC_CC += spec/x86_64/kernel/thread.cc
|
SRC_CC += spec/x86_64/kernel/thread.cc
|
||||||
SRC_CC += spec/x86_64/kernel/thread.cc
|
SRC_CC += spec/x86_64/kernel/thread.cc
|
||||||
SRC_CC += spec/x86_64/platform_support_common.cc
|
SRC_CC += spec/x86_64/platform_support_common.cc
|
||||||
|
|
|
@ -133,7 +133,6 @@ Cpu::Idle_thread::Idle_thread(Cpu * const cpu)
|
||||||
|
|
||||||
affinity(cpu);
|
affinity(cpu);
|
||||||
Thread::_pd = core_pd();
|
Thread::_pd = core_pd();
|
||||||
Thread::_pd->admit(*regs);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -169,7 +168,7 @@ Cpu_job & Cpu::schedule()
|
||||||
/* update scheduler */
|
/* update scheduler */
|
||||||
time_t quota = _timer.update_time();
|
time_t quota = _timer.update_time();
|
||||||
Job & old_job = scheduled_job();
|
Job & old_job = scheduled_job();
|
||||||
old_job.exception(id());
|
old_job.exception(*this);
|
||||||
_timer.process_timeouts();
|
_timer.process_timeouts();
|
||||||
_scheduler.update(quota);
|
_scheduler.update(quota);
|
||||||
|
|
||||||
|
@ -181,14 +180,20 @@ Cpu_job & Cpu::schedule()
|
||||||
|
|
||||||
_timer.schedule_timeout();
|
_timer.schedule_timeout();
|
||||||
|
|
||||||
/* switch to new job */
|
|
||||||
switch_to(new_job);
|
|
||||||
|
|
||||||
/* return new job */
|
/* return new job */
|
||||||
return new_job;
|
return new_job;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Genode::size_t kernel_stack_size = Cpu::KERNEL_STACK_SIZE;
|
||||||
|
Genode::uint8_t kernel_stack[NR_OF_CPUS][Cpu::KERNEL_STACK_SIZE]
|
||||||
|
__attribute__((aligned(Genode::get_page_size())));
|
||||||
|
|
||||||
|
|
||||||
|
addr_t Cpu::stack_start() {
|
||||||
|
return (addr_t)&kernel_stack + KERNEL_STACK_SIZE * (_id+1); }
|
||||||
|
|
||||||
|
|
||||||
Cpu::Cpu(unsigned const id)
|
Cpu::Cpu(unsigned const id)
|
||||||
:
|
:
|
||||||
_id(id), _timer(_id),
|
_id(id), _timer(_id),
|
||||||
|
@ -222,22 +227,3 @@ Cpu_pool::Cpu_pool()
|
||||||
|
|
||||||
Cpu_domain_update::Cpu_domain_update() {
|
Cpu_domain_update::Cpu_domain_update() {
|
||||||
for (unsigned i = 0; i < NR_OF_CPUS; i++) { _pending[i] = false; } }
|
for (unsigned i = 0; i < NR_OF_CPUS; i++) { _pending[i] = false; } }
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* FIXME THIS IS ONLY USED BY IDLE THREAD
|
|
||||||
* Enable kernel-entry assembly to get an exclusive stack for every CPU
|
|
||||||
*
|
|
||||||
* The stack alignment is determined as follows:
|
|
||||||
*
|
|
||||||
* 1) There is an architectural minimum alignment for stacks that originates
|
|
||||||
* from the assumptions that some instructions make.
|
|
||||||
* 2) Shared cache lines between yet uncached and already cached
|
|
||||||
* CPUs during multiprocessor bring-up must be avoided. Thus, the alignment
|
|
||||||
* must be at least the maximum line size of global caches.
|
|
||||||
* 3) The alignment that originates from 1) and 2) is assumed to be always
|
|
||||||
* less or equal to the minimum page size.
|
|
||||||
*/
|
|
||||||
Genode::size_t kernel_stack_size = Cpu::KERNEL_STACK_SIZE;
|
|
||||||
Genode::uint8_t kernel_stack[NR_OF_CPUS][Cpu::KERNEL_STACK_SIZE]
|
|
||||||
__attribute__((aligned(Genode::get_page_size())));
|
|
||||||
|
|
|
@ -142,9 +142,7 @@ class Kernel::Cpu : public Genode::Cpu, public Irq::Pool, private Timeout
|
||||||
|
|
||||||
time_t time() const { return _timer.time(); }
|
time_t time() const { return _timer.time(); }
|
||||||
|
|
||||||
/***************
|
addr_t stack_start();
|
||||||
** Accessors **
|
|
||||||
***************/
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the currently active job
|
* Returns the currently active job
|
||||||
|
|
|
@ -16,7 +16,6 @@
|
||||||
#define _CORE__KERNEL__CPU_CONTEXT_H_
|
#define _CORE__KERNEL__CPU_CONTEXT_H_
|
||||||
|
|
||||||
/* core includes */
|
/* core includes */
|
||||||
#include <cpu.h>
|
|
||||||
#include <kernel/cpu_scheduler.h>
|
#include <kernel/cpu_scheduler.h>
|
||||||
#include <kernel/timer.h>
|
#include <kernel/timer.h>
|
||||||
|
|
||||||
|
@ -69,7 +68,7 @@ class Kernel::Cpu_domain_update : public Double_list_item
|
||||||
virtual void _cpu_domain_update_unblocks() = 0;
|
virtual void _cpu_domain_update_unblocks() = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
class Kernel::Cpu_job : public Genode::Cpu::User_context, public Cpu_share
|
class Kernel::Cpu_job : public Cpu_share
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
|
@ -105,12 +104,12 @@ class Kernel::Cpu_job : public Genode::Cpu::User_context, public Cpu_share
|
||||||
/**
|
/**
|
||||||
* Handle exception that occured during execution on CPU 'id'
|
* Handle exception that occured during execution on CPU 'id'
|
||||||
*/
|
*/
|
||||||
virtual void exception(unsigned const id) = 0;
|
virtual void exception(Cpu & cpu) = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Continue execution on CPU 'id'
|
* Continue execution on CPU 'id'
|
||||||
*/
|
*/
|
||||||
virtual void proceed(unsigned const id) = 0;
|
virtual void proceed(Cpu & cpu) = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return which job currently uses our CPU-share
|
* Return which job currently uses our CPU-share
|
||||||
|
|
|
@ -21,7 +21,7 @@ extern "C" void kernel()
|
||||||
using namespace Kernel;
|
using namespace Kernel;
|
||||||
|
|
||||||
Cpu * const cpu = cpu_pool()->cpu(Cpu::executing_id());
|
Cpu * const cpu = cpu_pool()->cpu(Cpu::executing_id());
|
||||||
cpu->schedule().proceed(cpu->id());
|
cpu->schedule().proceed(*cpu);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
#define _CORE__KERNEL__PD_H_
|
#define _CORE__KERNEL__PD_H_
|
||||||
|
|
||||||
/* core includes */
|
/* core includes */
|
||||||
|
#include <hw/assert.h>
|
||||||
#include <cpu.h>
|
#include <cpu.h>
|
||||||
#include <kernel/core_interface.h>
|
#include <kernel/core_interface.h>
|
||||||
#include <kernel/object.h>
|
#include <kernel/object.h>
|
||||||
|
@ -34,8 +35,7 @@ namespace Kernel
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class Kernel::Pd : public Genode::Cpu::Pd,
|
class Kernel::Pd : public Kernel::Object
|
||||||
public Kernel::Object
|
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
@ -52,6 +52,8 @@ class Kernel::Pd : public Genode::Cpu::Pd,
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
Genode::Cpu::Mmu_context mmu_regs;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
*
|
*
|
||||||
|
@ -59,14 +61,19 @@ class Kernel::Pd : public Genode::Cpu::Pd,
|
||||||
* \param platform_pd core object of the PD
|
* \param platform_pd core object of the PD
|
||||||
*/
|
*/
|
||||||
Pd(Hw::Page_table * const table,
|
Pd(Hw::Page_table * const table,
|
||||||
Genode::Platform_pd * const platform_pd);
|
Genode::Platform_pd * const platform_pd)
|
||||||
|
: _table(table), _platform_pd(platform_pd),
|
||||||
|
mmu_regs((addr_t)table)
|
||||||
|
{
|
||||||
|
capid_t invalid = _capid_alloc.alloc();
|
||||||
|
assert(invalid == cap_id_invalid());
|
||||||
|
}
|
||||||
|
|
||||||
~Pd();
|
~Pd()
|
||||||
|
{
|
||||||
/**
|
while (Object_identity_reference *oir = _cap_tree.first())
|
||||||
* Let the CPU context 'c' join the PD
|
oir->~Object_identity_reference();
|
||||||
*/
|
}
|
||||||
void admit(Genode::Cpu::Context & c);
|
|
||||||
|
|
||||||
|
|
||||||
static capid_t syscall_create(void * const dst,
|
static capid_t syscall_create(void * const dst,
|
||||||
|
@ -80,6 +87,7 @@ class Kernel::Pd : public Genode::Cpu::Pd,
|
||||||
static void syscall_destroy(Pd * const pd) {
|
static void syscall_destroy(Pd * const pd) {
|
||||||
call(call_id_delete_pd(), (Call_arg)pd); }
|
call(call_id_delete_pd(), (Call_arg)pd); }
|
||||||
|
|
||||||
|
|
||||||
/***************
|
/***************
|
||||||
** Accessors **
|
** Accessors **
|
||||||
***************/
|
***************/
|
||||||
|
|
|
@ -201,7 +201,6 @@ void Thread::_call_start_thread()
|
||||||
|
|
||||||
/* join protection domain */
|
/* join protection domain */
|
||||||
thread->_pd = (Pd *) user_arg_3();
|
thread->_pd = (Pd *) user_arg_3();
|
||||||
thread->_pd->admit(*thread->regs);
|
|
||||||
thread->Ipc_node::_init((Native_utcb *)user_arg_4(), this);
|
thread->Ipc_node::_init((Native_utcb *)user_arg_4(), this);
|
||||||
thread->_become_active();
|
thread->_become_active();
|
||||||
}
|
}
|
||||||
|
@ -625,10 +624,7 @@ Thread::Thread(unsigned const priority, unsigned const quota,
|
||||||
:
|
:
|
||||||
Cpu_job(priority, quota), _fault_pd(0), _fault_addr(0),
|
Cpu_job(priority, quota), _fault_pd(0), _fault_addr(0),
|
||||||
_fault_writes(0), _state(AWAITS_START),
|
_fault_writes(0), _state(AWAITS_START),
|
||||||
_signal_receiver(0), _label(label), _core(core)
|
_signal_receiver(0), _label(label), _core(core), regs(core) { }
|
||||||
{
|
|
||||||
_init();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void Thread::print(Genode::Output &out) const
|
void Thread::print(Genode::Output &out) const
|
||||||
|
@ -670,7 +666,6 @@ Core_thread::Core_thread()
|
||||||
affinity(cpu_pool()->primary_cpu());
|
affinity(cpu_pool()->primary_cpu());
|
||||||
_utcb = utcb;
|
_utcb = utcb;
|
||||||
Thread::_pd = core_pd();
|
Thread::_pd = core_pd();
|
||||||
Thread::_pd->admit(*regs);
|
|
||||||
_become_active();
|
_become_active();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
#define _CORE__KERNEL__THREAD_H_
|
#define _CORE__KERNEL__THREAD_H_
|
||||||
|
|
||||||
/* core includes */
|
/* core includes */
|
||||||
|
#include <cpu.h>
|
||||||
#include <kernel/signal_receiver.h>
|
#include <kernel/signal_receiver.h>
|
||||||
#include <kernel/ipc_node.h>
|
#include <kernel/ipc_node.h>
|
||||||
#include <kernel/cpu_context.h>
|
#include <kernel/cpu_context.h>
|
||||||
|
@ -36,7 +37,7 @@ class Kernel::Thread
|
||||||
public Ipc_node, public Signal_context_killer, public Signal_handler,
|
public Ipc_node, public Signal_context_killer, public Signal_handler,
|
||||||
private Timeout
|
private Timeout
|
||||||
{
|
{
|
||||||
private:
|
protected:
|
||||||
|
|
||||||
enum { START_VERBOSE = 0 };
|
enum { START_VERBOSE = 0 };
|
||||||
|
|
||||||
|
@ -64,8 +65,6 @@ class Kernel::Thread
|
||||||
bool const _core = false;
|
bool const _core = false;
|
||||||
bool _fault_exec = false;
|
bool _fault_exec = false;
|
||||||
|
|
||||||
void _init();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Notice that another thread yielded the CPU to this thread
|
* Notice that another thread yielded the CPU to this thread
|
||||||
*/
|
*/
|
||||||
|
@ -83,15 +82,11 @@ class Kernel::Thread
|
||||||
int _route_event(unsigned const event_id,
|
int _route_event(unsigned const event_id,
|
||||||
Signal_context * const signal_context_id);
|
Signal_context * const signal_context_id);
|
||||||
|
|
||||||
protected:
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Switch from an inactive state to the active state
|
* Switch from an inactive state to the active state
|
||||||
*/
|
*/
|
||||||
void _become_active();
|
void _become_active();
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Switch from the active state to the inactive state 's'
|
* Switch from the active state to the inactive state 's'
|
||||||
*/
|
*/
|
||||||
|
@ -226,6 +221,8 @@ class Kernel::Thread
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
Genode::Align_at<Genode::Cpu::Context> regs;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
*
|
*
|
||||||
|
@ -245,6 +242,23 @@ class Kernel::Thread
|
||||||
Thread(char const * const label)
|
Thread(char const * const label)
|
||||||
: Thread(Cpu_priority::MIN, 0, label, true) { }
|
: Thread(Cpu_priority::MIN, 0, label, true) { }
|
||||||
|
|
||||||
|
|
||||||
|
/**************************
|
||||||
|
** Support for syscalls **
|
||||||
|
**************************/
|
||||||
|
|
||||||
|
void user_arg_0(Kernel::Call_arg const arg);
|
||||||
|
void user_arg_1(Kernel::Call_arg const arg);
|
||||||
|
void user_arg_2(Kernel::Call_arg const arg);
|
||||||
|
void user_arg_3(Kernel::Call_arg const arg);
|
||||||
|
void user_arg_4(Kernel::Call_arg const arg);
|
||||||
|
|
||||||
|
Kernel::Call_arg user_arg_0() const;
|
||||||
|
Kernel::Call_arg user_arg_1() const;
|
||||||
|
Kernel::Call_arg user_arg_2() const;
|
||||||
|
Kernel::Call_arg user_arg_3() const;
|
||||||
|
Kernel::Call_arg user_arg_4() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Syscall to create a thread
|
* Syscall to create a thread
|
||||||
*
|
*
|
||||||
|
@ -292,8 +306,8 @@ class Kernel::Thread
|
||||||
** Cpu_job **
|
** Cpu_job **
|
||||||
*************/
|
*************/
|
||||||
|
|
||||||
void exception(unsigned const cpu);
|
void exception(Cpu & cpu);
|
||||||
void proceed(unsigned const cpu);
|
void proceed(Cpu & cpu);
|
||||||
Cpu_job * helping_sink();
|
Cpu_job * helping_sink();
|
||||||
|
|
||||||
|
|
||||||
|
@ -319,15 +333,11 @@ class Kernel::Thread
|
||||||
/**
|
/**
|
||||||
* The first core thread in the system bootstrapped by the Kernel
|
* The first core thread in the system bootstrapped by the Kernel
|
||||||
*/
|
*/
|
||||||
class Kernel::Core_thread : public Core_object<Kernel::Thread>
|
struct Kernel::Core_thread : Core_object<Kernel::Thread>
|
||||||
{
|
{
|
||||||
private:
|
Core_thread();
|
||||||
|
|
||||||
Core_thread();
|
static Thread & singleton();
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
static Thread & singleton();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* _CORE__KERNEL__THREAD_H_ */
|
#endif /* _CORE__KERNEL__THREAD_H_ */
|
||||||
|
|
|
@ -118,8 +118,8 @@ class Kernel::Vm : public Cpu_job,
|
||||||
** Cpu_job **
|
** Cpu_job **
|
||||||
*************/
|
*************/
|
||||||
|
|
||||||
void exception(unsigned const cpu);
|
void exception(Cpu & cpu);
|
||||||
void proceed(unsigned const cpu);
|
void proceed(Cpu & cpu);
|
||||||
Cpu_job * helping_sink() { return this; }
|
Cpu_job * helping_sink() { return this; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -11,16 +11,39 @@
|
||||||
* under the terms of the GNU Affero General Public License version 3.
|
* under the terms of the GNU Affero General Public License version 3.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <util/bit_allocator.h>
|
||||||
|
#include <base/internal/unmanaged_singleton.h>
|
||||||
|
|
||||||
|
#include <kernel/cpu.h>
|
||||||
#include <spec/arm/cpu_support.h>
|
#include <spec/arm/cpu_support.h>
|
||||||
|
|
||||||
void Genode::Arm_cpu::User_context::init(bool privileged)
|
Genode::Arm_cpu::Context::Context(bool privileged)
|
||||||
{
|
{
|
||||||
using Psr = Arm_cpu::Psr;
|
using Psr = Arm_cpu::Psr;
|
||||||
|
|
||||||
Psr::access_t v = 0;
|
Psr::access_t v = 0;
|
||||||
Psr::M::set(v, privileged ? Psr::M::SYS : Psr::M::USR);
|
Psr::M::set(v, privileged ? Psr::M::SYS : Psr::M::USR);
|
||||||
Psr::F::set(v, 1);
|
if (Genode::Pic::fast_interrupts()) Psr::I::set(v, 1);
|
||||||
|
else Psr::F::set(v, 1);
|
||||||
Psr::A::set(v, 1);
|
Psr::A::set(v, 1);
|
||||||
regs->cpsr = v;
|
cpsr = v;
|
||||||
regs->cpu_exception = Genode::Arm_cpu::Context::RESET;
|
cpu_exception = RESET;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
using Asid_allocator = Genode::Bit_allocator<256>;
|
||||||
|
|
||||||
|
static Asid_allocator &alloc() {
|
||||||
|
return *unmanaged_singleton<Asid_allocator>(); }
|
||||||
|
|
||||||
|
|
||||||
|
Genode::Arm_cpu::Mmu_context::Mmu_context(addr_t table)
|
||||||
|
: cidr((Genode::uint8_t)alloc().alloc()), ttbr0(Ttbr0::init(table)) { }
|
||||||
|
|
||||||
|
|
||||||
|
Genode::Arm_cpu::Mmu_context::~Mmu_context()
|
||||||
|
{
|
||||||
|
/* flush TLB by ASID */
|
||||||
|
Cpu::Tlbiasid::write(id());
|
||||||
|
alloc().free(id());
|
||||||
}
|
}
|
||||||
|
|
|
@ -58,130 +58,23 @@ struct Genode::Arm_cpu : public Hw::Arm_cpu
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Dfsr : Hw::Arm_cpu::Dfsr
|
struct alignas(4) Context : Cpu_state
|
||||||
{
|
{
|
||||||
struct Wnr : Bitfield<11, 1> { }; /* write not read bit */
|
Context(bool privileged);
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Extend basic CPU state by members relevant for 'base-hw' only
|
|
||||||
*/
|
|
||||||
struct Context : Cpu_state
|
|
||||||
{
|
|
||||||
Cidr::access_t cidr;
|
|
||||||
Ttbr0::access_t ttbr0;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return base of assigned translation table
|
|
||||||
*/
|
|
||||||
addr_t translation_table() const {
|
|
||||||
return Ttbr::Ba::masked(ttbr0); }
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Assign translation-table base 'table'
|
|
||||||
*/
|
|
||||||
void translation_table(addr_t const table) {
|
|
||||||
ttbr0 = Ttbr0::init(table); }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Assign protection domain
|
|
||||||
*/
|
|
||||||
void protection_domain(Genode::uint8_t const id) { cidr = id; }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class comprises ARM specific protection domain attributes
|
* This class comprises ARM specific protection domain attributes
|
||||||
*/
|
*/
|
||||||
struct Pd
|
struct Mmu_context
|
||||||
{
|
{
|
||||||
Genode::uint8_t asid; /* address space id */
|
Cidr::access_t cidr;
|
||||||
|
Ttbr0::access_t ttbr0;
|
||||||
|
|
||||||
Pd(Genode::uint8_t id) : asid(id) {}
|
Mmu_context(addr_t page_table_base);
|
||||||
};
|
~Mmu_context();
|
||||||
|
|
||||||
/**
|
|
||||||
* An usermode execution state
|
|
||||||
*/
|
|
||||||
struct User_context
|
|
||||||
{
|
|
||||||
Align_at<Context, 4> regs;
|
|
||||||
|
|
||||||
void init(bool privileged);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Support for kernel calls
|
|
||||||
*/
|
|
||||||
void user_arg_0(Kernel::Call_arg const arg) { regs->r0 = arg; }
|
|
||||||
void user_arg_1(Kernel::Call_arg const arg) { regs->r1 = arg; }
|
|
||||||
void user_arg_2(Kernel::Call_arg const arg) { regs->r2 = arg; }
|
|
||||||
void user_arg_3(Kernel::Call_arg const arg) { regs->r3 = arg; }
|
|
||||||
void user_arg_4(Kernel::Call_arg const arg) { regs->r4 = arg; }
|
|
||||||
Kernel::Call_arg user_arg_0() const { return regs->r0; }
|
|
||||||
Kernel::Call_arg user_arg_1() const { return regs->r1; }
|
|
||||||
Kernel::Call_arg user_arg_2() const { return regs->r2; }
|
|
||||||
Kernel::Call_arg user_arg_3() const { return regs->r3; }
|
|
||||||
Kernel::Call_arg user_arg_4() const { return regs->r4; }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return if the context is in a page fault due to translation miss
|
|
||||||
*
|
|
||||||
* \param va holds the virtual fault-address if call returns 1
|
|
||||||
* \param w holds whether it's a write fault if call returns 1
|
|
||||||
* \param p holds whether it's a permission fault if call returns 1
|
|
||||||
*/
|
|
||||||
bool in_fault(addr_t & va, addr_t & w, bool & p) const
|
|
||||||
{
|
|
||||||
/* translation fault on section */
|
|
||||||
static constexpr Fsr::access_t section = 5;
|
|
||||||
/* translation fault on page */
|
|
||||||
static constexpr Fsr::access_t page = 7;
|
|
||||||
/* permission fault on page */
|
|
||||||
static constexpr Fsr::access_t permission = 0xf;
|
|
||||||
|
|
||||||
switch (regs->cpu_exception) {
|
|
||||||
|
|
||||||
case Context::PREFETCH_ABORT:
|
|
||||||
{
|
|
||||||
/* check if fault was caused by a translation miss */
|
|
||||||
Ifsr::access_t const fs = Fsr::Fs::get(Ifsr::read());
|
|
||||||
|
|
||||||
if (fs == permission) {
|
|
||||||
w = 0;
|
|
||||||
va = regs->ip;
|
|
||||||
p = true;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fs != section && fs != page)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
/* fetch fault data */
|
|
||||||
w = 0;
|
|
||||||
va = regs->ip;
|
|
||||||
p = false;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
case Context::DATA_ABORT:
|
|
||||||
{
|
|
||||||
/* check if fault is of known type */
|
|
||||||
Dfsr::access_t const fs = Fsr::Fs::get(Dfsr::read());
|
|
||||||
if (fs != permission && fs != section && fs != page)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
/* fetch fault data */
|
|
||||||
Dfsr::access_t const dfsr = Dfsr::read();
|
|
||||||
w = Dfsr::Wnr::get(dfsr);
|
|
||||||
va = Dfar::read();
|
|
||||||
p = false;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
|
uint8_t id() { return cidr; }
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -233,23 +126,65 @@ struct Genode::Arm_cpu : public Hw::Arm_cpu
|
||||||
for (; base < top; base += line_size) { Icimvau::write(base); }
|
for (; base < top; base += line_size) { Icimvau::write(base); }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void switch_to(Context&, Mmu_context & o)
|
||||||
|
{
|
||||||
|
if (o.cidr == 0) return;
|
||||||
|
|
||||||
|
Cidr::access_t cidr = Cidr::read();
|
||||||
|
if (cidr != o.cidr) {
|
||||||
|
Cidr::write(o.cidr);
|
||||||
|
Ttbr0::write(o.ttbr0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool in_fault(Context & c, addr_t & va, addr_t & w, bool & p)
|
||||||
|
{
|
||||||
|
/* translation fault on section */
|
||||||
|
static constexpr Fsr::access_t section = 5;
|
||||||
|
/* translation fault on page */
|
||||||
|
static constexpr Fsr::access_t page = 7;
|
||||||
|
/* permission fault on page */
|
||||||
|
static constexpr Fsr::access_t permission = 0xf;
|
||||||
|
|
||||||
|
if (c.cpu_exception == Context::PREFETCH_ABORT) {
|
||||||
|
/* check if fault was caused by a translation miss */
|
||||||
|
Ifsr::access_t const fs = Fsr::Fs::get(Ifsr::read());
|
||||||
|
|
||||||
|
if (fs == permission) {
|
||||||
|
w = 0;
|
||||||
|
va = Ifar::read();
|
||||||
|
p = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fs != section && fs != page)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* fetch fault data */
|
||||||
|
w = 0;
|
||||||
|
va = Ifar::read();
|
||||||
|
p = false;
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
/* check if fault is of known type */
|
||||||
|
Dfsr::access_t const fs = Fsr::Fs::get(Dfsr::read());
|
||||||
|
if (fs != permission && fs != section && fs != page)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* fetch fault data */
|
||||||
|
Dfsr::access_t const dfsr = Dfsr::read();
|
||||||
|
w = Dfsr::Wnr::get(dfsr);
|
||||||
|
va = Dfar::read();
|
||||||
|
p = false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*************
|
/*************
|
||||||
** Dummies **
|
** Dummies **
|
||||||
*************/
|
*************/
|
||||||
|
|
||||||
void switch_to(User_context & o)
|
bool retry_undefined_instr(Context&) { return false; }
|
||||||
{
|
|
||||||
if (o.regs->cidr == 0) return;
|
|
||||||
|
|
||||||
Cidr::access_t cidr = Cidr::read();
|
|
||||||
if (cidr != o.regs->cidr) {
|
|
||||||
Cidr::write(o.regs->cidr);
|
|
||||||
Ttbr0::write(o.regs->ttbr0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool retry_undefined_instr(User_context&) { return false; }
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return kernel name of the executing CPU
|
* Return kernel name of the executing CPU
|
||||||
|
|
|
@ -1,26 +0,0 @@
|
||||||
/*
|
|
||||||
* \brief ARM cpu context initialization when TrustZone is used
|
|
||||||
* \author Stefan Kalkowski
|
|
||||||
* \date 2017-04-12
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Copyright (C) 2017 Genode Labs GmbH
|
|
||||||
*
|
|
||||||
* This file is part of the Genode OS framework, which is distributed
|
|
||||||
* under the terms of the GNU Affero General Public License version 3.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <spec/arm/cpu_support.h>
|
|
||||||
|
|
||||||
void Genode::Arm_cpu::User_context::init(bool privileged)
|
|
||||||
{
|
|
||||||
using Psr = Genode::Arm_cpu::Psr;
|
|
||||||
|
|
||||||
Psr::access_t v = 0;
|
|
||||||
Psr::M::set(v, privileged ? Psr::M::SYS : Psr::M::USR);
|
|
||||||
Psr::I::set(v, 1);
|
|
||||||
Psr::A::set(v, 1);
|
|
||||||
regs->cpsr = v;
|
|
||||||
regs->cpu_exception = Cpu::Context::RESET;
|
|
||||||
}
|
|
|
@ -1,56 +0,0 @@
|
||||||
/*
|
|
||||||
* \brief Kernel backend for protection domains
|
|
||||||
* \author Stefan Kalkowski
|
|
||||||
* \date 2015-03-20
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Copyright (C) 2015-2017 Genode Labs GmbH
|
|
||||||
*
|
|
||||||
* This file is part of the Genode OS framework, which is distributed
|
|
||||||
* under the terms of the GNU Affero General Public License version 3.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* Genode includes */
|
|
||||||
#include <util/bit_allocator.h>
|
|
||||||
|
|
||||||
/* core includes */
|
|
||||||
#include <hw/assert.h>
|
|
||||||
#include <kernel/cpu.h>
|
|
||||||
#include <kernel/pd.h>
|
|
||||||
|
|
||||||
using Asid_allocator = Genode::Bit_allocator<256>;
|
|
||||||
|
|
||||||
static Asid_allocator &alloc() {
|
|
||||||
return *unmanaged_singleton<Asid_allocator>(); }
|
|
||||||
|
|
||||||
|
|
||||||
Kernel::Pd::Pd(Hw::Page_table * const table,
|
|
||||||
Genode::Platform_pd * const platform_pd)
|
|
||||||
: Kernel::Cpu::Pd((Genode::uint8_t)alloc().alloc()),
|
|
||||||
_table(table), _platform_pd(platform_pd)
|
|
||||||
{
|
|
||||||
capid_t invalid = _capid_alloc.alloc();
|
|
||||||
assert(invalid == cap_id_invalid());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Kernel::Pd::~Pd() {
|
|
||||||
|
|
||||||
while (Object_identity_reference *oir = _cap_tree.first())
|
|
||||||
oir->~Object_identity_reference();
|
|
||||||
|
|
||||||
/* clean up buffers of memory management */
|
|
||||||
Cpu * const cpu = cpu_pool()->cpu(Cpu::executing_id());
|
|
||||||
cpu->clean_invalidate_data_cache();
|
|
||||||
cpu->invalidate_instr_cache();
|
|
||||||
Cpu::Tlbiasid::write(asid); /* flush TLB by ASID */
|
|
||||||
alloc().free(asid);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void Kernel::Pd::admit(Kernel::Cpu::Context & c)
|
|
||||||
{
|
|
||||||
c.protection_domain(asid);
|
|
||||||
c.translation_table((addr_t)translation_table());
|
|
||||||
}
|
|
|
@ -19,13 +19,7 @@
|
||||||
|
|
||||||
using namespace Kernel;
|
using namespace Kernel;
|
||||||
|
|
||||||
void Kernel::Thread::_init()
|
void Thread::exception(Cpu & cpu)
|
||||||
{
|
|
||||||
init(_core);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void Thread::exception(unsigned const cpu)
|
|
||||||
{
|
{
|
||||||
switch (regs->cpu_exception) {
|
switch (regs->cpu_exception) {
|
||||||
case Cpu::Context::SUPERVISOR_CALL:
|
case Cpu::Context::SUPERVISOR_CALL:
|
||||||
|
@ -37,10 +31,10 @@ void Thread::exception(unsigned const cpu)
|
||||||
return;
|
return;
|
||||||
case Cpu::Context::INTERRUPT_REQUEST:
|
case Cpu::Context::INTERRUPT_REQUEST:
|
||||||
case Cpu::Context::FAST_INTERRUPT_REQUEST:
|
case Cpu::Context::FAST_INTERRUPT_REQUEST:
|
||||||
_interrupt(cpu);
|
_interrupt(cpu.id());
|
||||||
return;
|
return;
|
||||||
case Cpu::Context::UNDEFINED_INSTRUCTION:
|
case Cpu::Context::UNDEFINED_INSTRUCTION:
|
||||||
if (_cpu->retry_undefined_instr(*this)) { return; }
|
if (_cpu->retry_undefined_instr(*regs)) { return; }
|
||||||
Genode::warning(*this, ": undefined instruction at ip=",
|
Genode::warning(*this, ": undefined instruction at ip=",
|
||||||
Genode::Hex(regs->ip));
|
Genode::Hex(regs->ip));
|
||||||
_die();
|
_die();
|
||||||
|
@ -59,14 +53,14 @@ void Thread::exception(unsigned const cpu)
|
||||||
void Thread::_mmu_exception()
|
void Thread::_mmu_exception()
|
||||||
{
|
{
|
||||||
_become_inactive(AWAITS_RESTART);
|
_become_inactive(AWAITS_RESTART);
|
||||||
if (in_fault(_fault_addr, _fault_writes, _fault_exec)) {
|
if (Cpu::in_fault(*regs, _fault_addr, _fault_writes, _fault_exec)) {
|
||||||
_fault_pd = (addr_t)_pd->platform_pd();
|
_fault_pd = (addr_t)_pd->platform_pd();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Core should never raise a page-fault. If this happens, print out an
|
* Core should never raise a page-fault. If this happens, print out an
|
||||||
* error message with debug information.
|
* error message with debug information.
|
||||||
*/
|
*/
|
||||||
if (_pd == Kernel::core_pd())
|
if (_core)
|
||||||
Genode::error("page fault in core thread (", label(), "): "
|
Genode::error("page fault in core thread (", label(), "): "
|
||||||
"ip=", Genode::Hex(regs->ip), " fault=", Genode::Hex(_fault_addr));
|
"ip=", Genode::Hex(regs->ip), " fault=", Genode::Hex(_fault_addr));
|
||||||
|
|
||||||
|
@ -142,9 +136,11 @@ void Kernel::Thread::_call_update_instr_region()
|
||||||
|
|
||||||
extern void * kernel_stack;
|
extern void * kernel_stack;
|
||||||
|
|
||||||
void Thread::proceed(unsigned const cpu)
|
void Thread::proceed(Cpu & cpu)
|
||||||
{
|
{
|
||||||
regs->cpu_exception = (addr_t)&kernel_stack + Cpu::KERNEL_STACK_SIZE * (cpu+1);
|
cpu.switch_to(*regs, pd()->mmu_regs);
|
||||||
|
|
||||||
|
regs->cpu_exception = cpu.stack_start();
|
||||||
|
|
||||||
asm volatile("mov sp, %0 \n"
|
asm volatile("mov sp, %0 \n"
|
||||||
"msr spsr_cxsf, %1 \n"
|
"msr spsr_cxsf, %1 \n"
|
||||||
|
@ -154,3 +150,16 @@ void Thread::proceed(unsigned const cpu)
|
||||||
:: "r" (static_cast<Cpu::Context*>(&*regs)),
|
:: "r" (static_cast<Cpu::Context*>(&*regs)),
|
||||||
"r" (regs->cpsr), "r" (regs->ip));
|
"r" (regs->cpsr), "r" (regs->ip));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Thread::user_arg_0(Kernel::Call_arg const arg) { regs->r0 = arg; }
|
||||||
|
void Thread::user_arg_1(Kernel::Call_arg const arg) { regs->r1 = arg; }
|
||||||
|
void Thread::user_arg_2(Kernel::Call_arg const arg) { regs->r2 = arg; }
|
||||||
|
void Thread::user_arg_3(Kernel::Call_arg const arg) { regs->r3 = arg; }
|
||||||
|
void Thread::user_arg_4(Kernel::Call_arg const arg) { regs->r4 = arg; }
|
||||||
|
|
||||||
|
Kernel::Call_arg Thread::user_arg_0() const { return regs->r0; }
|
||||||
|
Kernel::Call_arg Thread::user_arg_1() const { return regs->r1; }
|
||||||
|
Kernel::Call_arg Thread::user_arg_2() const { return regs->r2; }
|
||||||
|
Kernel::Call_arg Thread::user_arg_3() const { return regs->r3; }
|
||||||
|
Kernel::Call_arg Thread::user_arg_4() const { return regs->r4; }
|
||||||
|
|
|
@ -21,8 +21,8 @@ void Kernel::Thread::_call_update_pd()
|
||||||
Cpu * const cpu = cpu_pool()->cpu(Cpu::executing_id());
|
Cpu * const cpu = cpu_pool()->cpu(Cpu::executing_id());
|
||||||
cpu->invalidate_instr_cache();
|
cpu->invalidate_instr_cache();
|
||||||
cpu->clean_invalidate_data_cache();
|
cpu->clean_invalidate_data_cache();
|
||||||
if (pd->asid)
|
if (pd->mmu_regs.id())
|
||||||
Cpu::Tlbiasid::write(pd->asid); /* flush TLB by ASID */
|
Cpu::Tlbiasid::write(pd->mmu_regs.id()); /* flush TLB by ASID */
|
||||||
else
|
else
|
||||||
Cpu::Tlbiall::write(0);
|
Cpu::Tlbiall::write(0);
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,6 @@
|
||||||
void Kernel::Thread::_call_update_pd()
|
void Kernel::Thread::_call_update_pd()
|
||||||
{
|
{
|
||||||
Pd * const pd = (Pd *) user_arg_1();
|
Pd * const pd = (Pd *) user_arg_1();
|
||||||
if (Cpu_domain_update::_do_global(pd->asid)) {
|
if (Cpu_domain_update::_do_global(pd->mmu_regs.id())) {
|
||||||
_become_inactive(AWAITS_RESTART); }
|
_become_inactive(AWAITS_RESTART); }
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,6 +50,8 @@ class Genode::Pic : public Hw::Pic
|
||||||
Sgir::Target_list_filter::ALL_OTHER);
|
Sgir::Target_list_filter::ALL_OTHER);
|
||||||
_distr.write<Sgir>(sgir);
|
_distr.write<Sgir>(sgir);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static constexpr bool fast_interrupts() { return false; }
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* _CORE__SPEC__ARM_GIC__PIC_H_ */
|
#endif /* _CORE__SPEC__ARM_GIC__PIC_H_ */
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* core includes */
|
/* core includes */
|
||||||
|
#include <kernel/cpu.h>
|
||||||
#include <kernel/vm.h>
|
#include <kernel/vm.h>
|
||||||
|
|
||||||
using namespace Kernel;
|
using namespace Kernel;
|
||||||
|
@ -30,12 +31,12 @@ Kernel::Vm::Vm(void * const state,
|
||||||
Kernel::Vm::~Vm() {}
|
Kernel::Vm::~Vm() {}
|
||||||
|
|
||||||
|
|
||||||
void Vm::exception(unsigned const cpu)
|
void Vm::exception(Cpu & cpu)
|
||||||
{
|
{
|
||||||
switch(_state->cpu_exception) {
|
switch(_state->cpu_exception) {
|
||||||
case Genode::Cpu_state::INTERRUPT_REQUEST:
|
case Genode::Cpu_state::INTERRUPT_REQUEST:
|
||||||
case Genode::Cpu_state::FAST_INTERRUPT_REQUEST:
|
case Genode::Cpu_state::FAST_INTERRUPT_REQUEST:
|
||||||
_interrupt(cpu);
|
_interrupt(cpu.id());
|
||||||
return;
|
return;
|
||||||
case Genode::Cpu_state::DATA_ABORT:
|
case Genode::Cpu_state::DATA_ABORT:
|
||||||
_state->dfar = Cpu::Dfar::read();
|
_state->dfar = Cpu::Dfar::read();
|
||||||
|
@ -53,7 +54,7 @@ extern "C" void monitor_mode_enter_normal_world(Cpu::Context*, void*);
|
||||||
extern void * kernel_stack;
|
extern void * kernel_stack;
|
||||||
|
|
||||||
|
|
||||||
void Vm::proceed(unsigned const cpu)
|
void Vm::proceed(Cpu & cpu)
|
||||||
{
|
{
|
||||||
unsigned const irq = _state->irq_injection;
|
unsigned const irq = _state->irq_injection;
|
||||||
if (irq) {
|
if (irq) {
|
||||||
|
@ -65,6 +66,6 @@ void Vm::proceed(unsigned const cpu)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void * stack = (void*)((addr_t)&kernel_stack + Cpu::KERNEL_STACK_SIZE * (cpu+1));
|
monitor_mode_enter_normal_world(reinterpret_cast<Cpu::Context*>(_state),
|
||||||
monitor_mode_enter_normal_world(reinterpret_cast<Cpu::Context*>(_state), stack);
|
(void*) cpu.stack_start());
|
||||||
}
|
}
|
||||||
|
|
|
@ -172,7 +172,7 @@ struct Kernel::Virtual_timer
|
||||||
/**
|
/**
|
||||||
* Load the virtual timer state from VM state
|
* Load the virtual timer state from VM state
|
||||||
*/
|
*/
|
||||||
static void load(Genode::Vm_state *s, unsigned const cpu_id)
|
static void load(Genode::Vm_state *s)
|
||||||
{
|
{
|
||||||
if (s->timer_irq) timer().irq.enable();
|
if (s->timer_irq) timer().irq.enable();
|
||||||
|
|
||||||
|
@ -213,7 +213,7 @@ Kernel::Vm::Vm(void * const state,
|
||||||
affinity(cpu_pool()->primary_cpu());
|
affinity(cpu_pool()->primary_cpu());
|
||||||
Virtual_pic::pic().irq.enable();
|
Virtual_pic::pic().irq.enable();
|
||||||
|
|
||||||
vt_host_context.sp = (addr_t)&kernel_stack + Cpu::KERNEL_STACK_SIZE;
|
vt_host_context.sp = _cpu->stack_start();
|
||||||
vt_host_context.ttbr0 = Cpu::Ttbr0_64bit::read();
|
vt_host_context.ttbr0 = Cpu::Ttbr0_64bit::read();
|
||||||
vt_host_context.ttbr1 = Cpu::Ttbr1_64bit::read();
|
vt_host_context.ttbr1 = Cpu::Ttbr1_64bit::read();
|
||||||
vt_host_context.sctlr = Cpu::Sctlr::read();
|
vt_host_context.sctlr = Cpu::Sctlr::read();
|
||||||
|
@ -227,7 +227,7 @@ Kernel::Vm::Vm(void * const state,
|
||||||
Kernel::Vm::~Vm() { alloc().free(_id); }
|
Kernel::Vm::~Vm() { alloc().free(_id); }
|
||||||
|
|
||||||
|
|
||||||
void Kernel::Vm::exception(unsigned const cpu_id)
|
void Kernel::Vm::exception(Cpu & cpu)
|
||||||
{
|
{
|
||||||
Virtual_timer::save(_state);
|
Virtual_timer::save(_state);
|
||||||
|
|
||||||
|
@ -235,7 +235,7 @@ void Kernel::Vm::exception(unsigned const cpu_id)
|
||||||
case Genode::Cpu_state::INTERRUPT_REQUEST:
|
case Genode::Cpu_state::INTERRUPT_REQUEST:
|
||||||
case Genode::Cpu_state::FAST_INTERRUPT_REQUEST:
|
case Genode::Cpu_state::FAST_INTERRUPT_REQUEST:
|
||||||
_state->gic_irq = Board::VT_MAINTAINANCE_IRQ;
|
_state->gic_irq = Board::VT_MAINTAINANCE_IRQ;
|
||||||
_interrupt(cpu_id);
|
_interrupt(cpu.id());
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
pause();
|
pause();
|
||||||
|
@ -247,12 +247,13 @@ void Kernel::Vm::exception(unsigned const cpu_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Kernel::Vm::proceed(unsigned const cpu_id)
|
void Kernel::Vm::proceed(Cpu &)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* the following values have to be enforced by the hypervisor
|
* the following values have to be enforced by the hypervisor
|
||||||
*/
|
*/
|
||||||
_state->vttbr = Cpu::Ttbr0::init((Genode::addr_t)_table, _id);
|
_state->vttbr = Cpu::Ttbr_64bit::Ba::masked((Cpu::Ttbr_64bit::access_t)_table);
|
||||||
|
Cpu::Ttbr_64bit::Asid::set(_state->vttbr, _id);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* use the following report fields not needed for loading the context
|
* use the following report fields not needed for loading the context
|
||||||
|
@ -263,7 +264,7 @@ void Kernel::Vm::proceed(unsigned const cpu_id)
|
||||||
_state->hpfar = Cpu::Hcr::init();
|
_state->hpfar = Cpu::Hcr::init();
|
||||||
|
|
||||||
Virtual_pic::load(_state);
|
Virtual_pic::load(_state);
|
||||||
Virtual_timer::load(_state, cpu_id);
|
Virtual_timer::load(_state);
|
||||||
|
|
||||||
hypervisor_enter_vm(reinterpret_cast<Cpu::Context*>(_state));
|
hypervisor_enter_vm(reinterpret_cast<Cpu::Context*>(_state));
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,35 @@
|
||||||
|
/*
|
||||||
|
* \brief Cortex A15 specific MMU context initialization
|
||||||
|
* \author Stefan Kalkowski
|
||||||
|
* \date 2017-10-17
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2017 Genode Labs GmbH
|
||||||
|
*
|
||||||
|
* This file is part of the Genode OS framework, which is distributed
|
||||||
|
* under the terms of the GNU Affero General Public License version 3.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <util/bit_allocator.h>
|
||||||
|
#include <base/internal/unmanaged_singleton.h>
|
||||||
|
|
||||||
|
#include <spec/cortex_a15/cpu.h>
|
||||||
|
|
||||||
|
using Asid_allocator = Genode::Bit_allocator<256>;
|
||||||
|
|
||||||
|
static Asid_allocator &alloc() {
|
||||||
|
return *unmanaged_singleton<Asid_allocator>(); }
|
||||||
|
|
||||||
|
|
||||||
|
Genode::Cpu::Mmu_context::Mmu_context(addr_t table)
|
||||||
|
: ttbr0(Ttbr_64bit::Ba::masked((Ttbr_64bit::access_t)table)) {
|
||||||
|
Ttbr_64bit::Asid::set(ttbr0, (Genode::uint8_t)alloc().alloc()); }
|
||||||
|
|
||||||
|
|
||||||
|
Genode::Cpu::Mmu_context::~Mmu_context()
|
||||||
|
{
|
||||||
|
/* flush TLB by ASID */
|
||||||
|
Cpu::Tlbiasid::write(id());
|
||||||
|
alloc().free(id());
|
||||||
|
}
|
|
@ -25,30 +25,6 @@ class Genode::Cpu : public Arm_v7_cpu
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/**
|
|
||||||
* Translation table base register 0 (64-bit format)
|
|
||||||
*/
|
|
||||||
struct Ttbr0 : Ttbr0_64bit
|
|
||||||
{
|
|
||||||
enum Memory_region { NON_CACHEABLE = 0, CACHEABLE = 1 };
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return initialized value
|
|
||||||
*
|
|
||||||
* \param table base of targeted translation table
|
|
||||||
*/
|
|
||||||
static access_t init(addr_t const table, unsigned const id)
|
|
||||||
{
|
|
||||||
access_t v = Ttbr_64bit::Ba::masked((access_t)table);
|
|
||||||
Ttbr_64bit::Asid::set(v, id);
|
|
||||||
return v;
|
|
||||||
}
|
|
||||||
|
|
||||||
static Genode::uint32_t init(addr_t const table) {
|
|
||||||
return table; }
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/*********************************
|
/*********************************
|
||||||
** Virtualization extensions **
|
** Virtualization extensions **
|
||||||
*********************************/
|
*********************************/
|
||||||
|
@ -115,124 +91,73 @@ class Genode::Cpu : public Arm_v7_cpu
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extend basic CPU state by members relevant for 'base-hw' only
|
* An usermode execution state
|
||||||
*
|
|
||||||
* Note: this class redefines Genode::Arm::Context
|
|
||||||
*/
|
*/
|
||||||
struct Context : Genode::Cpu_state
|
struct Mmu_context
|
||||||
{
|
{
|
||||||
Ttbr0::access_t ttbr0 = 0;
|
Ttbr_64bit::access_t ttbr0;
|
||||||
addr_t sctlr = 0;
|
|
||||||
addr_t ttbrc = 0;
|
|
||||||
addr_t mair0 = 0;
|
|
||||||
|
|
||||||
/**
|
Mmu_context(addr_t const table);
|
||||||
* Return base of assigned translation table
|
~Mmu_context();
|
||||||
*/
|
|
||||||
addr_t translation_table() const {
|
|
||||||
return Ttbr_64bit::Ba::masked(ttbr0); }
|
|
||||||
|
|
||||||
/**
|
Genode::uint8_t id() const { return Ttbr_64bit::Asid::get(ttbr0); }
|
||||||
* Assign translation-table base 'table'
|
|
||||||
*/
|
|
||||||
void translation_table(addr_t const table) {
|
|
||||||
Ttbr_64bit::Ba::set(ttbr0, Ttbr_64bit::Ba::get(table)); }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Assign protection domain
|
|
||||||
*/
|
|
||||||
void protection_domain(Genode::uint8_t const id) {
|
|
||||||
Ttbr_64bit::Asid::set(ttbr0, id); }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An usermode execution state
|
* Return if the context is in a page fault due to translation miss
|
||||||
*
|
*
|
||||||
* FIXME: this class largely overlaps with Genode::Arm::User_context
|
* \param va holds the virtual fault-address if call returns 1
|
||||||
|
* \param w holds wether it's a write fault if call returns 1
|
||||||
|
* \param p holds whether it's a permission fault if call returns 1
|
||||||
*/
|
*/
|
||||||
struct User_context
|
static bool in_fault(Context & c, addr_t & va, addr_t & w, bool & p)
|
||||||
{
|
{
|
||||||
Align_at<Context, 8> regs;
|
/* permission fault on page, 2nd level */
|
||||||
|
static constexpr Fsr::access_t permission = 0b1111;
|
||||||
|
|
||||||
void init(bool privileged)
|
switch (c.cpu_exception) {
|
||||||
{
|
|
||||||
Psr::access_t v = 0;
|
|
||||||
Psr::M::set(v, privileged ? Psr::M::SYS : Psr::M::USR);
|
|
||||||
Psr::F::set(v, 1);
|
|
||||||
Psr::A::set(v, 1);
|
|
||||||
regs->cpsr = v;
|
|
||||||
regs->cpu_exception = Cpu::Context::RESET;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
case Context::PREFETCH_ABORT:
|
||||||
* Support for kernel calls
|
{
|
||||||
*/
|
/* check if fault was caused by a translation miss */
|
||||||
void user_arg_0(Kernel::Call_arg const arg) { regs->r0 = arg; }
|
Fsr::access_t const fs = Fsr::Fs::get(Ifsr::read());
|
||||||
void user_arg_1(Kernel::Call_arg const arg) { regs->r1 = arg; }
|
if (fs == permission) {
|
||||||
void user_arg_2(Kernel::Call_arg const arg) { regs->r2 = arg; }
|
|
||||||
void user_arg_3(Kernel::Call_arg const arg) { regs->r3 = arg; }
|
|
||||||
void user_arg_4(Kernel::Call_arg const arg) { regs->r4 = arg; }
|
|
||||||
Kernel::Call_arg user_arg_0() const { return regs->r0; }
|
|
||||||
Kernel::Call_arg user_arg_1() const { return regs->r1; }
|
|
||||||
Kernel::Call_arg user_arg_2() const { return regs->r2; }
|
|
||||||
Kernel::Call_arg user_arg_3() const { return regs->r3; }
|
|
||||||
Kernel::Call_arg user_arg_4() const { return regs->r4; }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return if the context is in a page fault due to translation miss
|
|
||||||
*
|
|
||||||
* \param va holds the virtual fault-address if call returns 1
|
|
||||||
* \param w holds whether it's a write fault if call returns 1
|
|
||||||
* \param p holds whether it's a permission fault if call returns 1
|
|
||||||
*/
|
|
||||||
bool in_fault(addr_t & va, addr_t & w, bool &p) const
|
|
||||||
{
|
|
||||||
/* permission fault on page, 2nd level */
|
|
||||||
static constexpr Fsr::access_t permission = 0b1111;
|
|
||||||
|
|
||||||
switch (regs->cpu_exception) {
|
|
||||||
|
|
||||||
case Context::PREFETCH_ABORT:
|
|
||||||
{
|
|
||||||
/* check if fault was caused by a translation miss */
|
|
||||||
Fsr::access_t const fs = Fsr::Fs::get(Ifsr::read());
|
|
||||||
if (fs == permission) {
|
|
||||||
w = 0;
|
|
||||||
va = regs->ip;
|
|
||||||
p = true;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((fs & 0b11100) != 0b100) return false;
|
|
||||||
|
|
||||||
/* fetch fault data */
|
|
||||||
w = 0;
|
w = 0;
|
||||||
va = regs->ip;
|
va = Ifar::read();
|
||||||
p = false;
|
p = true;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
case Context::DATA_ABORT:
|
if ((fs & 0b11100) != 0b100) return false;
|
||||||
{
|
|
||||||
/* check if fault was caused by translation miss */
|
|
||||||
Fsr::access_t const fs = Fsr::Fs::get(Dfsr::read());
|
|
||||||
if ((fs != permission) && (fs & 0b11100) != 0b100)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
/* fetch fault data */
|
/* fetch fault data */
|
||||||
Dfsr::access_t const dfsr = Dfsr::read();
|
w = 0;
|
||||||
w = Dfsr::Wnr::get(dfsr);
|
va = Ifar::read();
|
||||||
va = Dfar::read();
|
p = false;
|
||||||
p = false;
|
return true;
|
||||||
return true;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
case Context::DATA_ABORT:
|
||||||
return false;
|
{
|
||||||
};
|
/* check if fault was caused by translation miss */
|
||||||
}
|
Fsr::access_t const fs = Fsr::Fs::get(Dfsr::read());
|
||||||
|
if ((fs != permission) && (fs & 0b11100) != 0b100)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* fetch fault data */
|
||||||
|
Dfsr::access_t const dfsr = Dfsr::read();
|
||||||
|
w = Dfsr::Wnr::get(dfsr);
|
||||||
|
va = Dfar::read();
|
||||||
|
p = false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -258,11 +183,10 @@ class Genode::Cpu : public Arm_v7_cpu
|
||||||
void invalidate_data_cache() {
|
void invalidate_data_cache() {
|
||||||
invalidate_inner_data_cache(); }
|
invalidate_inner_data_cache(); }
|
||||||
|
|
||||||
void switch_to(User_context& o)
|
void switch_to(Context &, Mmu_context & mmu_context)
|
||||||
{
|
{
|
||||||
if (Ttbr_64bit::Asid::get(o.regs->ttbr0) &&
|
if (mmu_context.id() && (Ttbr0_64bit::read() != mmu_context.ttbr0))
|
||||||
(Ttbr0_64bit::read() != o.regs->ttbr0))
|
Ttbr0_64bit::write(mmu_context.ttbr0);
|
||||||
Ttbr0_64bit::write(o.regs->ttbr0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -270,7 +194,7 @@ class Genode::Cpu : public Arm_v7_cpu
|
||||||
** Dummies **
|
** Dummies **
|
||||||
*************/
|
*************/
|
||||||
|
|
||||||
bool retry_undefined_instr(User_context&) { return false; }
|
bool retry_undefined_instr(Context&) { return false; }
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* _CORE__SPEC__CORTEX_A15__CPU_H_ */
|
#endif /* _CORE__SPEC__CORTEX_A15__CPU_H_ */
|
||||||
|
|
|
@ -14,31 +14,20 @@
|
||||||
/* core includes */
|
/* core includes */
|
||||||
#include <kernel/cpu.h>
|
#include <kernel/cpu.h>
|
||||||
#include <kernel/lock.h>
|
#include <kernel/lock.h>
|
||||||
#include <kernel/pd.h>
|
|
||||||
#include <pic.h>
|
#include <pic.h>
|
||||||
#include <board.h>
|
|
||||||
|
|
||||||
/* base-hw includes */
|
/* base-hw includes */
|
||||||
#include <kernel/perf_counter.h>
|
#include <kernel/perf_counter.h>
|
||||||
|
|
||||||
using namespace Kernel;
|
using namespace Kernel;
|
||||||
|
|
||||||
/* entrypoint for non-boot CPUs */
|
|
||||||
extern "C" void * _start_secondary_cpus;
|
|
||||||
|
|
||||||
/* indicates boot cpu status */
|
|
||||||
static volatile bool primary_cpu = true;
|
|
||||||
|
|
||||||
|
|
||||||
void Kernel::Cpu::init(Kernel::Pic &pic)
|
void Kernel::Cpu::init(Kernel::Pic &pic)
|
||||||
{
|
{
|
||||||
{
|
Lock::Guard guard(data_lock());
|
||||||
Lock::Guard guard(data_lock());
|
|
||||||
|
|
||||||
/* enable performance counter */
|
/* enable performance counter */
|
||||||
perf_counter()->enable();
|
perf_counter()->enable();
|
||||||
|
|
||||||
/* enable timer interrupt */
|
/* enable timer interrupt */
|
||||||
pic.unmask(_timer.interrupt_id(), id());
|
pic.unmask(_timer.interrupt_id(), id());
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,43 +30,20 @@ class Genode::Cpu : public Arm_v7_cpu
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/**
|
struct Context : Arm_cpu::Context, Fpu::Context
|
||||||
* Coprocessor Access Control Register
|
|
||||||
*/
|
|
||||||
struct Cpacr : Register<32>
|
|
||||||
{
|
{
|
||||||
struct Cp10 : Bitfield<20, 2> { };
|
Context(bool privileged)
|
||||||
struct Cp11 : Bitfield<22, 2> { };
|
: Arm_cpu::Context(privileged) {}
|
||||||
|
|
||||||
/**
|
|
||||||
* Read register value
|
|
||||||
*/
|
|
||||||
static access_t read()
|
|
||||||
{
|
|
||||||
access_t v;
|
|
||||||
asm volatile ("mrc p15, 0, %[v], c1, c0, 2" : [v]"=r"(v) ::);
|
|
||||||
return v;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Override register value
|
|
||||||
*
|
|
||||||
* \param v write value
|
|
||||||
*/
|
|
||||||
static void write(access_t const v) {
|
|
||||||
asm volatile ("mcr p15, 0, %[v], c1, c0, 2" :: [v]"r"(v) :); }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct User_context : Arm_cpu::User_context, Fpu::Context { };
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Next cpu context to switch to
|
* Next cpu context to switch to
|
||||||
*
|
*
|
||||||
* \param context context to switch to
|
* \param context context to switch to
|
||||||
*/
|
*/
|
||||||
void switch_to(User_context & context)
|
void switch_to(Context & context, Mmu_context & mmu_context)
|
||||||
{
|
{
|
||||||
Arm_cpu::switch_to(context);
|
Arm_cpu::switch_to(context, mmu_context);
|
||||||
_fpu.switch_to(context);
|
_fpu.switch_to(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -75,7 +52,7 @@ class Genode::Cpu : public Arm_v7_cpu
|
||||||
*
|
*
|
||||||
* \param state CPU state of the user
|
* \param state CPU state of the user
|
||||||
*/
|
*/
|
||||||
bool retry_undefined_instr(User_context & context) {
|
bool retry_undefined_instr(Context & context) {
|
||||||
return _fpu.fault(context); }
|
return _fpu.fault(context); }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -41,6 +41,8 @@ class Genode::Pic : public Hw::Pic
|
||||||
|
|
||||||
bool secure(unsigned i) {
|
bool secure(unsigned i) {
|
||||||
return !read<Intsec::Nonsecure>(i); }
|
return !read<Intsec::Nonsecure>(i); }
|
||||||
|
|
||||||
|
static constexpr bool fast_interrupts() { return true; }
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace Kernel { using Pic = Genode::Pic; }
|
namespace Kernel { using Pic = Genode::Pic; }
|
||||||
|
|
|
@ -0,0 +1,69 @@
|
||||||
|
/*
|
||||||
|
* \brief CPU driver
|
||||||
|
* \author Stefan Kalkowski
|
||||||
|
* \date 2017-10-06
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2017 Genode Labs GmbH
|
||||||
|
*
|
||||||
|
* This file is part of the Genode OS framework, which is distributed
|
||||||
|
* under the terms of the GNU Affero General Public License version 3.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <base/internal/unmanaged_singleton.h>
|
||||||
|
|
||||||
|
#include <hw/assert.h>
|
||||||
|
#include <platform_pd.h>
|
||||||
|
#include <kernel/cpu.h>
|
||||||
|
#include <kernel/pd.h>
|
||||||
|
|
||||||
|
using Mmu_context = Genode::Cpu::Mmu_context;
|
||||||
|
using Asid_allocator = Genode::Bit_allocator<256>;
|
||||||
|
|
||||||
|
|
||||||
|
Genode::Cpu::Context::Context(bool)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* initialize cpu_exception with something that gets ignored in
|
||||||
|
* Thread::exception
|
||||||
|
*/
|
||||||
|
cpu_exception = IRQ_FLAG;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static Asid_allocator & alloc() {
|
||||||
|
return *unmanaged_singleton<Asid_allocator>(); }
|
||||||
|
|
||||||
|
|
||||||
|
Mmu_context::Mmu_context(addr_t page_table_base)
|
||||||
|
{
|
||||||
|
Sptbr::Asid::set(sptbr, (Genode::uint8_t)alloc().alloc());
|
||||||
|
Sptbr::Ppn::set(sptbr, page_table_base >> 12);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Mmu_context::~Mmu_context()
|
||||||
|
{
|
||||||
|
unsigned asid = Sptbr::Asid::get(sptbr);
|
||||||
|
Cpu::invalidate_tlb_by_pid(asid);
|
||||||
|
alloc().free(asid);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Genode::Cpu::switch_to(Mmu_context & context)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* The sstatus register defines to which privilege level
|
||||||
|
* the machin returns when doing an exception return
|
||||||
|
*/
|
||||||
|
bool user = Sptbr::Asid::get(context.sptbr);
|
||||||
|
Sstatus::access_t v = Sstatus::read();
|
||||||
|
Sstatus::Spp::set(v, user ? 0 : 1);
|
||||||
|
Sstatus::write(v);
|
||||||
|
|
||||||
|
/* change the translation table when necessary */
|
||||||
|
//Sptbr::access_t sptbr = Sptbr::read();
|
||||||
|
if (user /*&& sptbr != context.sptbr*/)
|
||||||
|
Sptbr::write(context.sptbr);
|
||||||
|
}
|
|
@ -40,69 +40,19 @@ class Genode::Cpu : public Hw::Riscv_cpu
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/**
|
struct alignas(8) Context : Cpu_state
|
||||||
* Extend basic CPU state by members relevant for 'base-hw' only
|
{
|
||||||
*/
|
Context(bool);
|
||||||
struct Context : Cpu_state
|
};
|
||||||
|
|
||||||
|
struct Mmu_context
|
||||||
{
|
{
|
||||||
Sptbr::access_t sptbr;
|
Sptbr::access_t sptbr;
|
||||||
|
|
||||||
/**
|
Mmu_context(addr_t page_table_base);
|
||||||
* Return base of assigned translation table
|
~Mmu_context();
|
||||||
*/
|
|
||||||
addr_t translation_table() const {
|
|
||||||
return Sptbr::Ppn::get(sptbr) << 12; }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Assign translation-table base 'table'
|
|
||||||
*/
|
|
||||||
void translation_table(addr_t const table) {
|
|
||||||
Sptbr::Ppn::set(sptbr, table >> 12); }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Assign protection domain
|
|
||||||
*/
|
|
||||||
void protection_domain(Genode::uint8_t const id) {
|
|
||||||
Sptbr::Asid::set(sptbr, id); }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Pd
|
|
||||||
{
|
|
||||||
Genode::uint8_t asid; /* address space id */
|
|
||||||
|
|
||||||
Pd(Genode::uint8_t id) : asid(id) {}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A usermode execution state
|
|
||||||
*/
|
|
||||||
struct User_context
|
|
||||||
{
|
|
||||||
Align_at<Context, 8> regs;
|
|
||||||
|
|
||||||
User_context()
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* initialize cpu_exception with something that gets ignored in
|
|
||||||
* Thread::exception
|
|
||||||
*/
|
|
||||||
regs->cpu_exception = IRQ_FLAG;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Support for kernel calls
|
|
||||||
*/
|
|
||||||
void user_arg_0(Kernel::Call_arg const arg) { regs->a0 = arg; }
|
|
||||||
void user_arg_1(Kernel::Call_arg const arg) { regs->a1 = arg; }
|
|
||||||
void user_arg_2(Kernel::Call_arg const arg) { regs->a2 = arg; }
|
|
||||||
void user_arg_3(Kernel::Call_arg const arg) { regs->a3 = arg; }
|
|
||||||
void user_arg_4(Kernel::Call_arg const arg) { regs->a4 = arg; }
|
|
||||||
Kernel::Call_arg user_arg_0() const { return regs->a0; }
|
|
||||||
Kernel::Call_arg user_arg_1() const { return regs->a1; }
|
|
||||||
Kernel::Call_arg user_arg_2() const { return regs->a2; }
|
|
||||||
Kernel::Call_arg user_arg_3() const { return regs->a3; }
|
|
||||||
Kernel::Call_arg user_arg_4() const { return regs->a4; }
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* From the manual
|
* From the manual
|
||||||
|
@ -123,38 +73,12 @@ class Genode::Cpu : public Hw::Riscv_cpu
|
||||||
asm volatile ("sfence.vm\n");
|
asm volatile ("sfence.vm\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Post processing after a translation was added to a translation table
|
|
||||||
*
|
|
||||||
* \param addr virtual address of the translation
|
|
||||||
* \param size size of the translation
|
|
||||||
*/
|
|
||||||
static void translation_added(addr_t const addr, size_t const size);
|
|
||||||
|
|
||||||
static void invalidate_tlb_by_pid(unsigned const pid) { sfence(); }
|
static void invalidate_tlb_by_pid(unsigned const pid) { sfence(); }
|
||||||
|
|
||||||
/**
|
void switch_to(Mmu_context & context);
|
||||||
* Return kernel name of the executing CPU
|
|
||||||
*/
|
|
||||||
static unsigned executing_id() { return primary_id(); }
|
|
||||||
|
|
||||||
/**
|
static unsigned executing_id() { return 0; }
|
||||||
* Return kernel name of the primary CPU
|
static unsigned primary_id() { return 0; }
|
||||||
*/
|
|
||||||
static unsigned primary_id() { return 0; }
|
|
||||||
|
|
||||||
/*************
|
|
||||||
** Dummies **
|
|
||||||
*************/
|
|
||||||
|
|
||||||
void switch_to(User_context& context)
|
|
||||||
{
|
|
||||||
bool user = Sptbr::Asid::get(context.regs->sptbr);
|
|
||||||
Sstatus::access_t v = Sstatus::read();
|
|
||||||
Sstatus::Spp::set(v, user ? 0 : 1);
|
|
||||||
Sstatus::write(v);
|
|
||||||
if (user) Sptbr::write(context.regs->sptbr);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* _CORE__SPEC__RISCV__CPU_H_ */
|
#endif /* _CORE__SPEC__RISCV__CPU_H_ */
|
||||||
|
|
|
@ -1,52 +0,0 @@
|
||||||
/*
|
|
||||||
* \brief Kernel backend for protection domains
|
|
||||||
* \author Seastian Sumpf
|
|
||||||
* \date 2015-06-02
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Copyright (C) 2015-2017 Genode Labs GmbH
|
|
||||||
*
|
|
||||||
* This file is part of the Genode OS framework, which is distributed
|
|
||||||
* under the terms of the GNU Affero General Public License version 3.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <base/internal/unmanaged_singleton.h>
|
|
||||||
|
|
||||||
#include <hw/assert.h>
|
|
||||||
#include <platform_pd.h>
|
|
||||||
#include <kernel/cpu.h>
|
|
||||||
#include <kernel/pd.h>
|
|
||||||
|
|
||||||
using Asid_allocator = Genode::Bit_allocator<256>;
|
|
||||||
|
|
||||||
static Asid_allocator & alloc() {
|
|
||||||
return *unmanaged_singleton<Asid_allocator>(); }
|
|
||||||
|
|
||||||
|
|
||||||
Kernel::Pd::Pd(Hw::Page_table * const table,
|
|
||||||
Genode::Platform_pd * const platform_pd)
|
|
||||||
: Kernel::Cpu::Pd((Genode::uint8_t)alloc().alloc()),
|
|
||||||
_table(table), _platform_pd(platform_pd)
|
|
||||||
{
|
|
||||||
capid_t invalid = _capid_alloc.alloc();
|
|
||||||
assert(invalid == cap_id_invalid());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Kernel::Pd::~Pd()
|
|
||||||
{
|
|
||||||
while (Object_identity_reference *oir = _cap_tree.first())
|
|
||||||
oir->~Object_identity_reference();
|
|
||||||
|
|
||||||
/* clean up buffers of memory management */
|
|
||||||
Cpu::invalidate_tlb_by_pid(asid);
|
|
||||||
alloc().free(asid);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void Kernel::Pd::admit(Kernel::Cpu::Context & c)
|
|
||||||
{
|
|
||||||
c.protection_domain(asid);
|
|
||||||
c.translation_table((addr_t)translation_table());
|
|
||||||
}
|
|
|
@ -12,14 +12,13 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* core includes */
|
/* core includes */
|
||||||
|
#include <kernel/cpu.h>
|
||||||
#include <kernel/pd.h>
|
#include <kernel/pd.h>
|
||||||
#include <kernel/thread.h>
|
#include <kernel/thread.h>
|
||||||
|
|
||||||
using namespace Kernel;
|
using namespace Kernel;
|
||||||
|
|
||||||
void Kernel::Thread::_init() { }
|
void Thread::exception(Cpu&)
|
||||||
|
|
||||||
void Thread::exception(unsigned const cpu)
|
|
||||||
{
|
{
|
||||||
using Context = Genode::Cpu::Context;
|
using Context = Genode::Cpu::Context;
|
||||||
|
|
||||||
|
@ -71,8 +70,10 @@ void Thread::_call_update_data_region()
|
||||||
void Thread::_call_update_instr_region() { }
|
void Thread::_call_update_instr_region() { }
|
||||||
|
|
||||||
|
|
||||||
void Kernel::Thread::proceed(unsigned const)
|
void Kernel::Thread::proceed(Cpu & cpu)
|
||||||
{
|
{
|
||||||
|
cpu.switch_to(_pd->mmu_regs);
|
||||||
|
|
||||||
asm volatile("csrw sscratch, %1 \n"
|
asm volatile("csrw sscratch, %1 \n"
|
||||||
"mv x31, %0 \n"
|
"mv x31, %0 \n"
|
||||||
"ld x30, (x31) \n"
|
"ld x30, (x31) \n"
|
||||||
|
@ -85,3 +86,15 @@ void Kernel::Thread::proceed(unsigned const)
|
||||||
"sret \n"
|
"sret \n"
|
||||||
:: "r" (&*regs), "r" (regs->t6) : "x30", "x31");
|
:: "r" (&*regs), "r" (regs->t6) : "x30", "x31");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Thread::user_arg_0(Kernel::Call_arg const arg) { regs->a0 = arg; }
|
||||||
|
void Thread::user_arg_1(Kernel::Call_arg const arg) { regs->a1 = arg; }
|
||||||
|
void Thread::user_arg_2(Kernel::Call_arg const arg) { regs->a2 = arg; }
|
||||||
|
void Thread::user_arg_3(Kernel::Call_arg const arg) { regs->a3 = arg; }
|
||||||
|
void Thread::user_arg_4(Kernel::Call_arg const arg) { regs->a4 = arg; }
|
||||||
|
Kernel::Call_arg Thread::user_arg_0() const { return regs->a0; }
|
||||||
|
Kernel::Call_arg Thread::user_arg_1() const { return regs->a1; }
|
||||||
|
Kernel::Call_arg Thread::user_arg_2() const { return regs->a2; }
|
||||||
|
Kernel::Call_arg Thread::user_arg_3() const { return regs->a3; }
|
||||||
|
Kernel::Call_arg Thread::user_arg_4() const { return regs->a4; }
|
||||||
|
|
|
@ -127,6 +127,8 @@ class Genode::Pic : Mmio
|
||||||
void mask();
|
void mask();
|
||||||
void unmask(unsigned const i, unsigned);
|
void unmask(unsigned const i, unsigned);
|
||||||
void mask(unsigned const i);
|
void mask(unsigned const i);
|
||||||
|
|
||||||
|
static constexpr bool fast_interrupts() { return false; }
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace Kernel { using Genode::Pic; }
|
namespace Kernel { using Genode::Pic; }
|
||||||
|
|
|
@ -22,15 +22,14 @@ extern "C" void kernel()
|
||||||
using namespace Kernel;
|
using namespace Kernel;
|
||||||
|
|
||||||
Cpu_job * new_job;
|
Cpu_job * new_job;
|
||||||
unsigned cpu_id;
|
Cpu * cpu;
|
||||||
|
|
||||||
{
|
{
|
||||||
Lock::Guard guard(data_lock());
|
Lock::Guard guard(data_lock());
|
||||||
|
|
||||||
cpu_id = Cpu::executing_id();
|
cpu = cpu_pool()->cpu(Cpu::executing_id());
|
||||||
Cpu * const cpu = cpu_pool()->cpu(cpu_id);
|
|
||||||
new_job = &cpu->schedule();
|
new_job = &cpu->schedule();
|
||||||
}
|
}
|
||||||
|
|
||||||
new_job->proceed(cpu_id);
|
new_job->proceed(*cpu);
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,23 +21,18 @@ extern int __gdt_start;
|
||||||
extern int __gdt_end;
|
extern int __gdt_end;
|
||||||
|
|
||||||
|
|
||||||
void Genode::Cpu::Context::init(addr_t const table, bool core)
|
Genode::Cpu::Context::Context(bool core)
|
||||||
{
|
{
|
||||||
/* Constants to handle IF, IOPL values */
|
|
||||||
enum {
|
|
||||||
EFLAGS_IF_SET = 1 << 9,
|
|
||||||
EFLAGS_IOPL_3 = 3 << 12,
|
|
||||||
};
|
|
||||||
|
|
||||||
cr3 = Cr3::init(table);
|
|
||||||
|
|
||||||
/* enable interrupts for all threads */
|
|
||||||
eflags = EFLAGS_IF_SET;
|
eflags = EFLAGS_IF_SET;
|
||||||
cs = core ? 0x8 : 0x1b;
|
cs = core ? 0x8 : 0x1b;
|
||||||
ss = core ? 0x10 : 0x23;
|
ss = core ? 0x10 : 0x23;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Genode::Cpu::Mmu_context::Mmu_context(addr_t const table)
|
||||||
|
: cr3(Cr3::Pdb::masked(table)) {}
|
||||||
|
|
||||||
|
|
||||||
void Genode::Cpu::Tss::init()
|
void Genode::Cpu::Tss::init()
|
||||||
{
|
{
|
||||||
enum { TSS_SELECTOR = 0x28, };
|
enum { TSS_SELECTOR = 0x28, };
|
||||||
|
|
|
@ -75,51 +75,25 @@ class Genode::Cpu
|
||||||
/**
|
/**
|
||||||
* Extend basic CPU state by members relevant for 'base-hw' only
|
* Extend basic CPU state by members relevant for 'base-hw' only
|
||||||
*/
|
*/
|
||||||
struct alignas(16) Context : Cpu_state
|
struct alignas(16) Context : Cpu_state, Fpu::Context
|
||||||
|
{
|
||||||
|
enum Eflags {
|
||||||
|
EFLAGS_IF_SET = 1 << 9,
|
||||||
|
EFLAGS_IOPL_3 = 3 << 12,
|
||||||
|
};
|
||||||
|
|
||||||
|
Context(bool privileged);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct Mmu_context
|
||||||
{
|
{
|
||||||
/**
|
|
||||||
* Address of top-level paging structure.
|
|
||||||
*/
|
|
||||||
addr_t cr3;
|
addr_t cr3;
|
||||||
|
|
||||||
/**
|
Mmu_context(addr_t page_table_base);
|
||||||
* Return base of assigned translation table
|
|
||||||
*/
|
|
||||||
addr_t translation_table() const { return cr3; }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialize context
|
|
||||||
*
|
|
||||||
* \param table physical base of appropriate translation table
|
|
||||||
* \param core whether it is a core thread or not
|
|
||||||
*/
|
|
||||||
void init(addr_t const table, bool core);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An usermode execution state
|
|
||||||
*/
|
|
||||||
struct User_context
|
|
||||||
{
|
|
||||||
Align_at<Context, 16> regs;
|
|
||||||
Fpu::Context fpu_regs;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Support for kernel calls
|
|
||||||
*/
|
|
||||||
void user_arg_0(Kernel::Call_arg const arg) { regs->rdi = arg; }
|
|
||||||
void user_arg_1(Kernel::Call_arg const arg) { regs->rsi = arg; }
|
|
||||||
void user_arg_2(Kernel::Call_arg const arg) { regs->rdx = arg; }
|
|
||||||
void user_arg_3(Kernel::Call_arg const arg) { regs->rcx = arg; }
|
|
||||||
void user_arg_4(Kernel::Call_arg const arg) { regs->r8 = arg; }
|
|
||||||
Kernel::Call_arg user_arg_0() const { return regs->rdi; }
|
|
||||||
Kernel::Call_arg user_arg_1() const { return regs->rsi; }
|
|
||||||
Kernel::Call_arg user_arg_2() const { return regs->rdx; }
|
|
||||||
Kernel::Call_arg user_arg_3() const { return regs->rcx; }
|
|
||||||
Kernel::Call_arg user_arg_4() const { return regs->r8; }
|
|
||||||
};
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
Fpu _fpu;
|
Fpu _fpu;
|
||||||
|
@ -149,7 +123,7 @@ class Genode::Cpu
|
||||||
*
|
*
|
||||||
* \param context next CPU context
|
* \param context next CPU context
|
||||||
*/
|
*/
|
||||||
inline void switch_to(User_context &context);
|
inline void switch_to(Context & context, Mmu_context &);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -279,12 +253,12 @@ struct Genode::Cpu::Cr4 : Register<64>
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
void Genode::Cpu::switch_to(User_context &context)
|
void Genode::Cpu::switch_to(Context & context, Mmu_context & mmu_context)
|
||||||
{
|
{
|
||||||
_fpu.switch_to(context.fpu_regs);
|
_fpu.switch_to(context);
|
||||||
|
|
||||||
if ((context.regs->cs != 0x8) && (context.regs->cr3 != Cr3::read()))
|
if ((context.cs != 0x8) && (mmu_context.cr3 != Cr3::read()))
|
||||||
Cr3::write(context.regs->cr3);
|
Cr3::write(mmu_context.cr3);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* _CORE__SPEC__X86_64__CPU_H_ */
|
#endif /* _CORE__SPEC__X86_64__CPU_H_ */
|
||||||
|
|
|
@ -1,36 +0,0 @@
|
||||||
/*
|
|
||||||
* \brief Kernel backend for protection domains
|
|
||||||
* \author Stefan Kalkowski
|
|
||||||
* \date 2015-03-20
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Copyright (C) 2015-2017 Genode Labs GmbH
|
|
||||||
*
|
|
||||||
* This file is part of the Genode OS framework, which is distributed
|
|
||||||
* under the terms of the GNU Affero General Public License version 3.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* core includes */
|
|
||||||
#include <hw/assert.h>
|
|
||||||
#include <platform_pd.h>
|
|
||||||
#include <kernel/pd.h>
|
|
||||||
|
|
||||||
Kernel::Pd::Pd(Hw::Page_table * const table,
|
|
||||||
Genode::Platform_pd * const platform_pd)
|
|
||||||
: _table(table), _platform_pd(platform_pd)
|
|
||||||
{
|
|
||||||
capid_t invalid = _capid_alloc.alloc();
|
|
||||||
assert(invalid == cap_id_invalid());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Kernel::Pd::~Pd()
|
|
||||||
{
|
|
||||||
while (Object_identity_reference *oir = _cap_tree.first())
|
|
||||||
oir->~Object_identity_reference();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void Kernel::Pd::admit(Genode::Cpu::Context & c) {
|
|
||||||
c.init((addr_t)translation_table(), this == Kernel::core_pd()); }
|
|
|
@ -14,6 +14,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* core includes */
|
/* core includes */
|
||||||
|
#include <kernel/cpu.h>
|
||||||
#include <kernel/thread.h>
|
#include <kernel/thread.h>
|
||||||
#include <kernel/pd.h>
|
#include <kernel/pd.h>
|
||||||
|
|
||||||
|
@ -58,18 +59,17 @@ void Kernel::Thread::_mmu_exception()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Kernel::Thread::_init() { }
|
|
||||||
|
|
||||||
|
|
||||||
void Kernel::Thread::_call_update_pd() { }
|
void Kernel::Thread::_call_update_pd() { }
|
||||||
|
|
||||||
|
|
||||||
extern void * __tss_client_context_ptr;
|
extern void * __tss_client_context_ptr;
|
||||||
|
|
||||||
void Kernel::Thread::proceed(unsigned const)
|
void Kernel::Thread::proceed(Cpu & cpu)
|
||||||
{
|
{
|
||||||
void * * tss_stack_ptr = (&__tss_client_context_ptr);
|
void * * tss_stack_ptr = (&__tss_client_context_ptr);
|
||||||
*tss_stack_ptr = ®s->cr3;
|
*tss_stack_ptr = (void*)((addr_t)&*regs + sizeof(Genode::Cpu_state));
|
||||||
|
|
||||||
|
cpu.switch_to(*regs, pd()->mmu_regs);
|
||||||
|
|
||||||
asm volatile("mov %0, %%rsp \n"
|
asm volatile("mov %0, %%rsp \n"
|
||||||
"popq %%r8 \n"
|
"popq %%r8 \n"
|
||||||
|
@ -90,3 +90,16 @@ void Kernel::Thread::proceed(unsigned const)
|
||||||
"add $16, %%rsp \n"
|
"add $16, %%rsp \n"
|
||||||
"iretq \n" :: "r" (®s->r8));
|
"iretq \n" :: "r" (®s->r8));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Kernel::Thread::user_arg_0(Kernel::Call_arg const arg) { regs->rdi = arg; }
|
||||||
|
void Kernel::Thread::user_arg_1(Kernel::Call_arg const arg) { regs->rsi = arg; }
|
||||||
|
void Kernel::Thread::user_arg_2(Kernel::Call_arg const arg) { regs->rdx = arg; }
|
||||||
|
void Kernel::Thread::user_arg_3(Kernel::Call_arg const arg) { regs->rcx = arg; }
|
||||||
|
void Kernel::Thread::user_arg_4(Kernel::Call_arg const arg) { regs->r8 = arg; }
|
||||||
|
|
||||||
|
Kernel::Call_arg Kernel::Thread::user_arg_0() const { return regs->rdi; }
|
||||||
|
Kernel::Call_arg Kernel::Thread::user_arg_1() const { return regs->rsi; }
|
||||||
|
Kernel::Call_arg Kernel::Thread::user_arg_2() const { return regs->rdx; }
|
||||||
|
Kernel::Call_arg Kernel::Thread::user_arg_3() const { return regs->rcx; }
|
||||||
|
Kernel::Call_arg Kernel::Thread::user_arg_4() const { return regs->r8; }
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
|
|
||||||
using namespace Kernel;
|
using namespace Kernel;
|
||||||
|
|
||||||
void Thread::exception(unsigned const cpu)
|
void Thread::exception(Cpu & cpu)
|
||||||
{
|
{
|
||||||
using Genode::Cpu_state;
|
using Genode::Cpu_state;
|
||||||
|
|
||||||
|
@ -28,7 +28,7 @@ void Thread::exception(unsigned const cpu)
|
||||||
_mmu_exception();
|
_mmu_exception();
|
||||||
return;
|
return;
|
||||||
case Cpu_state::NO_MATH_COPROC:
|
case Cpu_state::NO_MATH_COPROC:
|
||||||
if (_cpu->fpu().fault(fpu_regs)) { return; }
|
if (_cpu->fpu().fault(*regs)) { return; }
|
||||||
Genode::warning(*this, ": FPU error");
|
Genode::warning(*this, ": FPU error");
|
||||||
_die();
|
_die();
|
||||||
return;
|
return;
|
||||||
|
@ -42,7 +42,7 @@ void Thread::exception(unsigned const cpu)
|
||||||
}
|
}
|
||||||
if (regs->trapno >= Cpu_state::INTERRUPTS_START &&
|
if (regs->trapno >= Cpu_state::INTERRUPTS_START &&
|
||||||
regs->trapno <= Cpu_state::INTERRUPTS_END) {
|
regs->trapno <= Cpu_state::INTERRUPTS_END) {
|
||||||
_interrupt(cpu);
|
_interrupt(cpu.id());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Genode::warning(*this, ": triggered unknown exception ", regs->trapno,
|
Genode::warning(*this, ": triggered unknown exception ", regs->trapno,
|
||||||
|
|
|
@ -13,19 +13,20 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* core includes */
|
/* core includes */
|
||||||
|
#include <kernel/cpu.h>
|
||||||
#include <kernel/thread.h>
|
#include <kernel/thread.h>
|
||||||
#include <pic.h>
|
#include <pic.h>
|
||||||
|
|
||||||
using namespace Kernel;
|
using namespace Kernel;
|
||||||
|
|
||||||
void Thread::exception(unsigned const cpu)
|
void Thread::exception(Cpu & cpu)
|
||||||
{
|
{
|
||||||
switch (regs->trapno) {
|
switch (regs->trapno) {
|
||||||
case Cpu::Context::PAGE_FAULT:
|
case Cpu::Context::PAGE_FAULT:
|
||||||
_mmu_exception();
|
_mmu_exception();
|
||||||
return;
|
return;
|
||||||
case Cpu::Context::NO_MATH_COPROC:
|
case Cpu::Context::NO_MATH_COPROC:
|
||||||
if (_cpu->fpu().fault(fpu_regs)) { return; }
|
if (_cpu->fpu().fault(*regs)) { return; }
|
||||||
Genode::warning(*this, ": FPU error");
|
Genode::warning(*this, ": FPU error");
|
||||||
_die();
|
_die();
|
||||||
return;
|
return;
|
||||||
|
@ -40,7 +41,7 @@ void Thread::exception(unsigned const cpu)
|
||||||
if (regs->trapno >= Cpu::Context::INTERRUPTS_START &&
|
if (regs->trapno >= Cpu::Context::INTERRUPTS_START &&
|
||||||
regs->trapno <= Cpu::Context::INTERRUPTS_END) {
|
regs->trapno <= Cpu::Context::INTERRUPTS_END) {
|
||||||
pic()->irq_occurred(regs->trapno);
|
pic()->irq_occurred(regs->trapno);
|
||||||
_interrupt(cpu);
|
_interrupt(cpu.id());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Genode::warning(*this, ": triggered unknown exception ", regs->trapno,
|
Genode::warning(*this, ": triggered unknown exception ", regs->trapno,
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
|
|
||||||
#include <assertion.h>
|
#include <assertion.h>
|
||||||
#include <platform_pd.h>
|
#include <platform_pd.h>
|
||||||
|
#include <kernel/cpu.h>
|
||||||
#include <kernel/vm.h>
|
#include <kernel/vm.h>
|
||||||
#include <cpu/cpu_state.h>
|
#include <cpu/cpu_state.h>
|
||||||
#include <pic.h>
|
#include <pic.h>
|
||||||
|
@ -27,35 +28,29 @@ Kernel::Vm::Vm(void * const state, Kernel::Signal_context * const context,
|
||||||
_table(nullptr)
|
_table(nullptr)
|
||||||
{
|
{
|
||||||
affinity(cpu_pool()->primary_cpu());
|
affinity(cpu_pool()->primary_cpu());
|
||||||
|
|
||||||
/*
|
|
||||||
* Initialize VM context as a core/kernel context to prevent
|
|
||||||
* page-table switching before doing the world switch
|
|
||||||
*/
|
|
||||||
regs->init((addr_t)core_pd()->translation_table(), true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Kernel::Vm::~Vm() { }
|
Kernel::Vm::~Vm() { }
|
||||||
|
|
||||||
|
|
||||||
void Kernel::Vm::exception(unsigned const cpu_id)
|
void Kernel::Vm::exception(Cpu & cpu)
|
||||||
{
|
{
|
||||||
pause();
|
pause();
|
||||||
if (regs->trapno == 200) {
|
if (_state->trapno == 200) {
|
||||||
_context->submit(1);
|
_context->submit(1);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (regs->trapno >= Genode::Cpu_state::INTERRUPTS_START &&
|
if (_state->trapno >= Genode::Cpu_state::INTERRUPTS_START &&
|
||||||
regs->trapno <= Genode::Cpu_state::INTERRUPTS_END) {
|
_state->trapno <= Genode::Cpu_state::INTERRUPTS_END) {
|
||||||
pic()->irq_occurred(regs->trapno);
|
pic()->irq_occurred(_state->trapno);
|
||||||
_interrupt(cpu_id);
|
_interrupt(cpu.id());
|
||||||
_context->submit(1);
|
_context->submit(1);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Genode::warning("VM: triggered unknown exception ", regs->trapno,
|
Genode::warning("VM: triggered unknown exception ", _state->trapno,
|
||||||
" with error code ", regs->errcode);
|
" with error code ", _state->errcode);
|
||||||
|
|
||||||
ASSERT_NEVER_CALLED;
|
ASSERT_NEVER_CALLED;
|
||||||
}
|
}
|
||||||
|
@ -63,10 +58,10 @@ void Kernel::Vm::exception(unsigned const cpu_id)
|
||||||
|
|
||||||
extern void * __tss_client_context_ptr;
|
extern void * __tss_client_context_ptr;
|
||||||
|
|
||||||
void Kernel::Vm::proceed(unsigned const cpu_id)
|
void Kernel::Vm::proceed(Cpu &)
|
||||||
{
|
{
|
||||||
void * * tss_stack_ptr = (&__tss_client_context_ptr);
|
void * * tss_stack_ptr = (&__tss_client_context_ptr);
|
||||||
*tss_stack_ptr = ®s->cr3;
|
*tss_stack_ptr = (void*)((addr_t)_state + sizeof(Genode::Cpu_state));
|
||||||
|
|
||||||
asm volatile("sti \n"
|
asm volatile("sti \n"
|
||||||
"mov $1, %rax \n"
|
"mov $1, %rax \n"
|
||||||
|
|
|
@ -18,15 +18,17 @@
|
||||||
#include <base/stdint.h>
|
#include <base/stdint.h>
|
||||||
|
|
||||||
namespace Genode {
|
namespace Genode {
|
||||||
template<typename, size_t> class Align_at;
|
template<typename> class Align_at;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
template <typename T, Genode::size_t ALIGN>
|
template <typename T>
|
||||||
class Genode::Align_at
|
class Genode::Align_at
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
static constexpr Genode::size_t ALIGN = alignof(T);
|
||||||
|
|
||||||
char _space[sizeof(T) + ALIGN - 1];
|
char _space[sizeof(T) + ALIGN - 1];
|
||||||
T & _obj;
|
T & _obj;
|
||||||
|
|
||||||
|
|
|
@ -167,7 +167,9 @@ struct Hw::Arm_cpu
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Data Fault Status Register */
|
/* Data Fault Status Register */
|
||||||
ARM_CP15_REGISTER_32BIT(Dfsr, c5, c0, 0, 0);
|
ARM_CP15_REGISTER_32BIT(Dfsr, c5, c0, 0, 0,
|
||||||
|
struct Wnr : Bitfield<11, 1> { }; /* write not read bit */
|
||||||
|
);
|
||||||
|
|
||||||
/* Instruction Fault Status Register */
|
/* Instruction Fault Status Register */
|
||||||
ARM_CP15_REGISTER_32BIT(Ifsr, c5, c0, 0, 1);
|
ARM_CP15_REGISTER_32BIT(Ifsr, c5, c0, 0, 1);
|
||||||
|
|
Loading…
Reference in New Issue