mirror of
https://github.com/genodelabs/genode.git
synced 2025-04-11 13:22:33 +00:00
parent
0635d5fffb
commit
d6a05245f2
@ -9,8 +9,8 @@ INC_DIR += $(BASE_DIR)/../base-hw/src/core/spec/arm
|
||||
|
||||
# add C++ sources
|
||||
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/pd.cc
|
||||
SRC_CC += spec/arm/platform_support.cc
|
||||
|
||||
# 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
|
||||
|
||||
# add C++ sources
|
||||
SRC_CC += spec/cortex_a15/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/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/board.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/cpu.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/timer.cc
|
||||
SRC_CC += spec/arm/cpu_trustzone.cc
|
||||
|
||||
ifneq ($(filter-out $(SPECS),trustzone),)
|
||||
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
|
||||
|
||||
# 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/platform_support.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/fpu.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/platform_support_common.cc
|
||||
|
@ -5,8 +5,8 @@ CC_OPT += -fno-delete-null-pointer-checks
|
||||
# add C++ sources
|
||||
SRC_CC += platform_services.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/pd.cc
|
||||
SRC_CC += spec/riscv/kernel/cpu.cc
|
||||
SRC_CC += spec/riscv/platform_support.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/fpu.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/platform_support_common.cc
|
||||
|
@ -133,7 +133,6 @@ Cpu::Idle_thread::Idle_thread(Cpu * const cpu)
|
||||
|
||||
affinity(cpu);
|
||||
Thread::_pd = core_pd();
|
||||
Thread::_pd->admit(*regs);
|
||||
}
|
||||
|
||||
|
||||
@ -169,7 +168,7 @@ Cpu_job & Cpu::schedule()
|
||||
/* update scheduler */
|
||||
time_t quota = _timer.update_time();
|
||||
Job & old_job = scheduled_job();
|
||||
old_job.exception(id());
|
||||
old_job.exception(*this);
|
||||
_timer.process_timeouts();
|
||||
_scheduler.update(quota);
|
||||
|
||||
@ -181,14 +180,20 @@ Cpu_job & Cpu::schedule()
|
||||
|
||||
_timer.schedule_timeout();
|
||||
|
||||
/* switch to new job */
|
||||
switch_to(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)
|
||||
:
|
||||
_id(id), _timer(_id),
|
||||
@ -222,22 +227,3 @@ Cpu_pool::Cpu_pool()
|
||||
|
||||
Cpu_domain_update::Cpu_domain_update() {
|
||||
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(); }
|
||||
|
||||
/***************
|
||||
** Accessors **
|
||||
***************/
|
||||
addr_t stack_start();
|
||||
|
||||
/**
|
||||
* Returns the currently active job
|
||||
|
@ -16,7 +16,6 @@
|
||||
#define _CORE__KERNEL__CPU_CONTEXT_H_
|
||||
|
||||
/* core includes */
|
||||
#include <cpu.h>
|
||||
#include <kernel/cpu_scheduler.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;
|
||||
};
|
||||
|
||||
class Kernel::Cpu_job : public Genode::Cpu::User_context, public Cpu_share
|
||||
class Kernel::Cpu_job : public Cpu_share
|
||||
{
|
||||
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'
|
||||
*/
|
||||
virtual void exception(unsigned const id) = 0;
|
||||
virtual void exception(Cpu & cpu) = 0;
|
||||
|
||||
/**
|
||||
* 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
|
||||
|
@ -21,7 +21,7 @@ extern "C" void kernel()
|
||||
using namespace Kernel;
|
||||
|
||||
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_
|
||||
|
||||
/* core includes */
|
||||
#include <hw/assert.h>
|
||||
#include <cpu.h>
|
||||
#include <kernel/core_interface.h>
|
||||
#include <kernel/object.h>
|
||||
@ -34,8 +35,7 @@ namespace Kernel
|
||||
}
|
||||
|
||||
|
||||
class Kernel::Pd : public Genode::Cpu::Pd,
|
||||
public Kernel::Object
|
||||
class Kernel::Pd : public Kernel::Object
|
||||
{
|
||||
public:
|
||||
|
||||
@ -52,6 +52,8 @@ class Kernel::Pd : public Genode::Cpu::Pd,
|
||||
|
||||
public:
|
||||
|
||||
Genode::Cpu::Mmu_context mmu_regs;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
@ -59,14 +61,19 @@ class Kernel::Pd : public Genode::Cpu::Pd,
|
||||
* \param platform_pd core object of the PD
|
||||
*/
|
||||
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();
|
||||
|
||||
/**
|
||||
* Let the CPU context 'c' join the PD
|
||||
*/
|
||||
void admit(Genode::Cpu::Context & c);
|
||||
~Pd()
|
||||
{
|
||||
while (Object_identity_reference *oir = _cap_tree.first())
|
||||
oir->~Object_identity_reference();
|
||||
}
|
||||
|
||||
|
||||
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) {
|
||||
call(call_id_delete_pd(), (Call_arg)pd); }
|
||||
|
||||
|
||||
/***************
|
||||
** Accessors **
|
||||
***************/
|
||||
|
@ -201,7 +201,6 @@ void Thread::_call_start_thread()
|
||||
|
||||
/* join protection domain */
|
||||
thread->_pd = (Pd *) user_arg_3();
|
||||
thread->_pd->admit(*thread->regs);
|
||||
thread->Ipc_node::_init((Native_utcb *)user_arg_4(), this);
|
||||
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),
|
||||
_fault_writes(0), _state(AWAITS_START),
|
||||
_signal_receiver(0), _label(label), _core(core)
|
||||
{
|
||||
_init();
|
||||
}
|
||||
_signal_receiver(0), _label(label), _core(core), regs(core) { }
|
||||
|
||||
|
||||
void Thread::print(Genode::Output &out) const
|
||||
@ -670,7 +666,6 @@ Core_thread::Core_thread()
|
||||
affinity(cpu_pool()->primary_cpu());
|
||||
_utcb = utcb;
|
||||
Thread::_pd = core_pd();
|
||||
Thread::_pd->admit(*regs);
|
||||
_become_active();
|
||||
}
|
||||
|
||||
|
@ -15,6 +15,7 @@
|
||||
#define _CORE__KERNEL__THREAD_H_
|
||||
|
||||
/* core includes */
|
||||
#include <cpu.h>
|
||||
#include <kernel/signal_receiver.h>
|
||||
#include <kernel/ipc_node.h>
|
||||
#include <kernel/cpu_context.h>
|
||||
@ -36,7 +37,7 @@ class Kernel::Thread
|
||||
public Ipc_node, public Signal_context_killer, public Signal_handler,
|
||||
private Timeout
|
||||
{
|
||||
private:
|
||||
protected:
|
||||
|
||||
enum { START_VERBOSE = 0 };
|
||||
|
||||
@ -64,8 +65,6 @@ class Kernel::Thread
|
||||
bool const _core = false;
|
||||
bool _fault_exec = false;
|
||||
|
||||
void _init();
|
||||
|
||||
/**
|
||||
* Notice that another thread yielded the CPU to this thread
|
||||
*/
|
||||
@ -83,15 +82,11 @@ class Kernel::Thread
|
||||
int _route_event(unsigned const event_id,
|
||||
Signal_context * const signal_context_id);
|
||||
|
||||
protected:
|
||||
|
||||
/**
|
||||
* Switch from an inactive state to the active state
|
||||
*/
|
||||
void _become_active();
|
||||
|
||||
private:
|
||||
|
||||
/**
|
||||
* Switch from the active state to the inactive state 's'
|
||||
*/
|
||||
@ -226,6 +221,8 @@ class Kernel::Thread
|
||||
|
||||
public:
|
||||
|
||||
Genode::Align_at<Genode::Cpu::Context> regs;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
@ -245,6 +242,23 @@ class Kernel::Thread
|
||||
Thread(char const * const label)
|
||||
: 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
|
||||
*
|
||||
@ -292,8 +306,8 @@ class Kernel::Thread
|
||||
** Cpu_job **
|
||||
*************/
|
||||
|
||||
void exception(unsigned const cpu);
|
||||
void proceed(unsigned const cpu);
|
||||
void exception(Cpu & cpu);
|
||||
void proceed(Cpu & cpu);
|
||||
Cpu_job * helping_sink();
|
||||
|
||||
|
||||
@ -319,15 +333,11 @@ class Kernel::Thread
|
||||
/**
|
||||
* 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();
|
||||
|
||||
public:
|
||||
|
||||
static Thread & singleton();
|
||||
static Thread & singleton();
|
||||
};
|
||||
|
||||
#endif /* _CORE__KERNEL__THREAD_H_ */
|
||||
|
@ -118,8 +118,8 @@ class Kernel::Vm : public Cpu_job,
|
||||
** Cpu_job **
|
||||
*************/
|
||||
|
||||
void exception(unsigned const cpu);
|
||||
void proceed(unsigned const cpu);
|
||||
void exception(Cpu & cpu);
|
||||
void proceed(Cpu & cpu);
|
||||
Cpu_job * helping_sink() { return this; }
|
||||
};
|
||||
|
||||
|
@ -11,16 +11,39 @@
|
||||
* 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>
|
||||
|
||||
void Genode::Arm_cpu::User_context::init(bool privileged)
|
||||
Genode::Arm_cpu::Context::Context(bool privileged)
|
||||
{
|
||||
using Psr = Arm_cpu::Psr;
|
||||
|
||||
Psr::access_t v = 0;
|
||||
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);
|
||||
regs->cpsr = v;
|
||||
regs->cpu_exception = Genode::Arm_cpu::Context::RESET;
|
||||
cpsr = v;
|
||||
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 */
|
||||
};
|
||||
|
||||
/**
|
||||
* 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; }
|
||||
Context(bool privileged);
|
||||
};
|
||||
|
||||
/**
|
||||
* 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) {}
|
||||
};
|
||||
|
||||
/**
|
||||
* 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;
|
||||
};
|
||||
}
|
||||
Mmu_context(addr_t page_table_base);
|
||||
~Mmu_context();
|
||||
|
||||
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); }
|
||||
}
|
||||
|
||||
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 **
|
||||
*************/
|
||||
|
||||
void switch_to(User_context & o)
|
||||
{
|
||||
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; }
|
||||
bool retry_undefined_instr(Context&) { return false; }
|
||||
|
||||
/**
|
||||
* 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;
|
||||
|
||||
void Kernel::Thread::_init()
|
||||
{
|
||||
init(_core);
|
||||
}
|
||||
|
||||
|
||||
void Thread::exception(unsigned const cpu)
|
||||
void Thread::exception(Cpu & cpu)
|
||||
{
|
||||
switch (regs->cpu_exception) {
|
||||
case Cpu::Context::SUPERVISOR_CALL:
|
||||
@ -37,10 +31,10 @@ void Thread::exception(unsigned const cpu)
|
||||
return;
|
||||
case Cpu::Context::INTERRUPT_REQUEST:
|
||||
case Cpu::Context::FAST_INTERRUPT_REQUEST:
|
||||
_interrupt(cpu);
|
||||
_interrupt(cpu.id());
|
||||
return;
|
||||
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::Hex(regs->ip));
|
||||
_die();
|
||||
@ -59,14 +53,14 @@ void Thread::exception(unsigned const cpu)
|
||||
void Thread::_mmu_exception()
|
||||
{
|
||||
_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();
|
||||
|
||||
/*
|
||||
* Core should never raise a page-fault. If this happens, print out an
|
||||
* error message with debug information.
|
||||
*/
|
||||
if (_pd == Kernel::core_pd())
|
||||
if (_core)
|
||||
Genode::error("page fault in core thread (", label(), "): "
|
||||
"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;
|
||||
|
||||
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"
|
||||
"msr spsr_cxsf, %1 \n"
|
||||
@ -154,3 +150,16 @@ void Thread::proceed(unsigned const cpu)
|
||||
:: "r" (static_cast<Cpu::Context*>(&*regs)),
|
||||
"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->invalidate_instr_cache();
|
||||
cpu->clean_invalidate_data_cache();
|
||||
if (pd->asid)
|
||||
Cpu::Tlbiasid::write(pd->asid); /* flush TLB by ASID */
|
||||
if (pd->mmu_regs.id())
|
||||
Cpu::Tlbiasid::write(pd->mmu_regs.id()); /* flush TLB by ASID */
|
||||
else
|
||||
Cpu::Tlbiall::write(0);
|
||||
}
|
||||
|
@ -18,6 +18,6 @@
|
||||
void Kernel::Thread::_call_update_pd()
|
||||
{
|
||||
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); }
|
||||
}
|
||||
|
@ -50,6 +50,8 @@ class Genode::Pic : public Hw::Pic
|
||||
Sgir::Target_list_filter::ALL_OTHER);
|
||||
_distr.write<Sgir>(sgir);
|
||||
}
|
||||
|
||||
static constexpr bool fast_interrupts() { return false; }
|
||||
};
|
||||
|
||||
#endif /* _CORE__SPEC__ARM_GIC__PIC_H_ */
|
||||
|
@ -13,6 +13,7 @@
|
||||
*/
|
||||
|
||||
/* core includes */
|
||||
#include <kernel/cpu.h>
|
||||
#include <kernel/vm.h>
|
||||
|
||||
using namespace Kernel;
|
||||
@ -30,12 +31,12 @@ Kernel::Vm::Vm(void * const state,
|
||||
Kernel::Vm::~Vm() {}
|
||||
|
||||
|
||||
void Vm::exception(unsigned const cpu)
|
||||
void Vm::exception(Cpu & cpu)
|
||||
{
|
||||
switch(_state->cpu_exception) {
|
||||
case Genode::Cpu_state::INTERRUPT_REQUEST:
|
||||
case Genode::Cpu_state::FAST_INTERRUPT_REQUEST:
|
||||
_interrupt(cpu);
|
||||
_interrupt(cpu.id());
|
||||
return;
|
||||
case Genode::Cpu_state::DATA_ABORT:
|
||||
_state->dfar = Cpu::Dfar::read();
|
||||
@ -53,7 +54,7 @@ extern "C" void monitor_mode_enter_normal_world(Cpu::Context*, void*);
|
||||
extern void * kernel_stack;
|
||||
|
||||
|
||||
void Vm::proceed(unsigned const cpu)
|
||||
void Vm::proceed(Cpu & cpu)
|
||||
{
|
||||
unsigned const irq = _state->irq_injection;
|
||||
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), stack);
|
||||
monitor_mode_enter_normal_world(reinterpret_cast<Cpu::Context*>(_state),
|
||||
(void*) cpu.stack_start());
|
||||
}
|
||||
|
@ -172,7 +172,7 @@ struct Kernel::Virtual_timer
|
||||
/**
|
||||
* 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();
|
||||
|
||||
@ -213,7 +213,7 @@ Kernel::Vm::Vm(void * const state,
|
||||
affinity(cpu_pool()->primary_cpu());
|
||||
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.ttbr1 = Cpu::Ttbr1_64bit::read();
|
||||
vt_host_context.sctlr = Cpu::Sctlr::read();
|
||||
@ -227,7 +227,7 @@ Kernel::Vm::Vm(void * const state,
|
||||
Kernel::Vm::~Vm() { alloc().free(_id); }
|
||||
|
||||
|
||||
void Kernel::Vm::exception(unsigned const cpu_id)
|
||||
void Kernel::Vm::exception(Cpu & cpu)
|
||||
{
|
||||
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::FAST_INTERRUPT_REQUEST:
|
||||
_state->gic_irq = Board::VT_MAINTAINANCE_IRQ;
|
||||
_interrupt(cpu_id);
|
||||
_interrupt(cpu.id());
|
||||
break;
|
||||
default:
|
||||
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
|
||||
*/
|
||||
_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
|
||||
@ -263,7 +264,7 @@ void Kernel::Vm::proceed(unsigned const cpu_id)
|
||||
_state->hpfar = Cpu::Hcr::init();
|
||||
|
||||
Virtual_pic::load(_state);
|
||||
Virtual_timer::load(_state, cpu_id);
|
||||
Virtual_timer::load(_state);
|
||||
|
||||
hypervisor_enter_vm(reinterpret_cast<Cpu::Context*>(_state));
|
||||
}
|
||||
|
35
repos/base-hw/src/core/spec/cortex_a15/cpu.cc
Normal file
35
repos/base-hw/src/core/spec/cortex_a15/cpu.cc
Normal file
@ -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:
|
||||
|
||||
/**
|
||||
* 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 **
|
||||
*********************************/
|
||||
@ -115,124 +91,73 @@ class Genode::Cpu : public Arm_v7_cpu
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Extend basic CPU state by members relevant for 'base-hw' only
|
||||
*
|
||||
* Note: this class redefines Genode::Arm::Context
|
||||
* An usermode execution state
|
||||
*/
|
||||
struct Context : Genode::Cpu_state
|
||||
struct Mmu_context
|
||||
{
|
||||
Ttbr0::access_t ttbr0 = 0;
|
||||
addr_t sctlr = 0;
|
||||
addr_t ttbrc = 0;
|
||||
addr_t mair0 = 0;
|
||||
Ttbr_64bit::access_t ttbr0;
|
||||
|
||||
/**
|
||||
* Return base of assigned translation table
|
||||
*/
|
||||
addr_t translation_table() const {
|
||||
return Ttbr_64bit::Ba::masked(ttbr0); }
|
||||
Mmu_context(addr_t const table);
|
||||
~Mmu_context();
|
||||
|
||||
/**
|
||||
* 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); }
|
||||
Genode::uint8_t id() const { return Ttbr_64bit::Asid::get(ttbr0); }
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* 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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
switch (c.cpu_exception) {
|
||||
|
||||
/**
|
||||
* 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
|
||||
{
|
||||
/* 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 */
|
||||
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 = false;
|
||||
va = Ifar::read();
|
||||
p = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
case Context::DATA_ABORT:
|
||||
{
|
||||
/* 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;
|
||||
if ((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;
|
||||
}
|
||||
/* fetch fault data */
|
||||
w = 0;
|
||||
va = Ifar::read();
|
||||
p = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
default:
|
||||
return false;
|
||||
};
|
||||
}
|
||||
case Context::DATA_ABORT:
|
||||
{
|
||||
/* 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() {
|
||||
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) &&
|
||||
(Ttbr0_64bit::read() != o.regs->ttbr0))
|
||||
Ttbr0_64bit::write(o.regs->ttbr0);
|
||||
if (mmu_context.id() && (Ttbr0_64bit::read() != mmu_context.ttbr0))
|
||||
Ttbr0_64bit::write(mmu_context.ttbr0);
|
||||
}
|
||||
|
||||
|
||||
@ -270,7 +194,7 @@ class Genode::Cpu : public Arm_v7_cpu
|
||||
** Dummies **
|
||||
*************/
|
||||
|
||||
bool retry_undefined_instr(User_context&) { return false; }
|
||||
bool retry_undefined_instr(Context&) { return false; }
|
||||
};
|
||||
|
||||
#endif /* _CORE__SPEC__CORTEX_A15__CPU_H_ */
|
||||
|
@ -14,31 +14,20 @@
|
||||
/* core includes */
|
||||
#include <kernel/cpu.h>
|
||||
#include <kernel/lock.h>
|
||||
#include <kernel/pd.h>
|
||||
#include <pic.h>
|
||||
#include <board.h>
|
||||
|
||||
/* base-hw includes */
|
||||
#include <kernel/perf_counter.h>
|
||||
|
||||
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)
|
||||
{
|
||||
{
|
||||
Lock::Guard guard(data_lock());
|
||||
Lock::Guard guard(data_lock());
|
||||
|
||||
/* enable performance counter */
|
||||
perf_counter()->enable();
|
||||
/* enable performance counter */
|
||||
perf_counter()->enable();
|
||||
|
||||
/* enable timer interrupt */
|
||||
pic.unmask(_timer.interrupt_id(), id());
|
||||
}
|
||||
/* enable timer interrupt */
|
||||
pic.unmask(_timer.interrupt_id(), id());
|
||||
}
|
||||
|
@ -30,43 +30,20 @@ class Genode::Cpu : public Arm_v7_cpu
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Coprocessor Access Control Register
|
||||
*/
|
||||
struct Cpacr : Register<32>
|
||||
struct Context : Arm_cpu::Context, Fpu::Context
|
||||
{
|
||||
struct Cp10 : Bitfield<20, 2> { };
|
||||
struct Cp11 : Bitfield<22, 2> { };
|
||||
|
||||
/**
|
||||
* 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) :); }
|
||||
Context(bool privileged)
|
||||
: Arm_cpu::Context(privileged) {}
|
||||
};
|
||||
|
||||
struct User_context : Arm_cpu::User_context, Fpu::Context { };
|
||||
|
||||
/**
|
||||
* Next cpu 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);
|
||||
}
|
||||
|
||||
@ -75,7 +52,7 @@ class Genode::Cpu : public Arm_v7_cpu
|
||||
*
|
||||
* \param state CPU state of the user
|
||||
*/
|
||||
bool retry_undefined_instr(User_context & context) {
|
||||
bool retry_undefined_instr(Context & context) {
|
||||
return _fpu.fault(context); }
|
||||
|
||||
/**
|
||||
|
@ -41,6 +41,8 @@ class Genode::Pic : public Hw::Pic
|
||||
|
||||
bool secure(unsigned i) {
|
||||
return !read<Intsec::Nonsecure>(i); }
|
||||
|
||||
static constexpr bool fast_interrupts() { return true; }
|
||||
};
|
||||
|
||||
namespace Kernel { using Pic = Genode::Pic; }
|
||||
|
69
repos/base-hw/src/core/spec/riscv/cpu.cc
Normal file
69
repos/base-hw/src/core/spec/riscv/cpu.cc
Normal file
@ -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:
|
||||
|
||||
/**
|
||||
* Extend basic CPU state by members relevant for 'base-hw' only
|
||||
*/
|
||||
struct Context : Cpu_state
|
||||
struct alignas(8) Context : Cpu_state
|
||||
{
|
||||
Context(bool);
|
||||
};
|
||||
|
||||
struct Mmu_context
|
||||
{
|
||||
Sptbr::access_t sptbr;
|
||||
|
||||
/**
|
||||
* Return base of assigned translation table
|
||||
*/
|
||||
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); }
|
||||
Mmu_context(addr_t page_table_base);
|
||||
~Mmu_context();
|
||||
};
|
||||
|
||||
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
|
||||
@ -123,38 +73,12 @@ class Genode::Cpu : public Hw::Riscv_cpu
|
||||
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(); }
|
||||
|
||||
/**
|
||||
* Return kernel name of the executing CPU
|
||||
*/
|
||||
static unsigned executing_id() { return primary_id(); }
|
||||
void switch_to(Mmu_context & context);
|
||||
|
||||
/**
|
||||
* Return kernel name of the primary CPU
|
||||
*/
|
||||
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);
|
||||
}
|
||||
static unsigned executing_id() { return 0; }
|
||||
static unsigned primary_id() { return 0; }
|
||||
};
|
||||
|
||||
#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 */
|
||||
#include <kernel/cpu.h>
|
||||
#include <kernel/pd.h>
|
||||
#include <kernel/thread.h>
|
||||
|
||||
using namespace Kernel;
|
||||
|
||||
void Kernel::Thread::_init() { }
|
||||
|
||||
void Thread::exception(unsigned const cpu)
|
||||
void Thread::exception(Cpu&)
|
||||
{
|
||||
using Context = Genode::Cpu::Context;
|
||||
|
||||
@ -71,8 +70,10 @@ void Thread::_call_update_data_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"
|
||||
"mv x31, %0 \n"
|
||||
"ld x30, (x31) \n"
|
||||
@ -85,3 +86,15 @@ void Kernel::Thread::proceed(unsigned const)
|
||||
"sret \n"
|
||||
:: "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 unmask(unsigned const i, unsigned);
|
||||
void mask(unsigned const i);
|
||||
|
||||
static constexpr bool fast_interrupts() { return false; }
|
||||
};
|
||||
|
||||
namespace Kernel { using Genode::Pic; }
|
||||
|
@ -22,15 +22,14 @@ extern "C" void kernel()
|
||||
using namespace Kernel;
|
||||
|
||||
Cpu_job * new_job;
|
||||
unsigned cpu_id;
|
||||
Cpu * cpu;
|
||||
|
||||
{
|
||||
Lock::Guard guard(data_lock());
|
||||
|
||||
cpu_id = Cpu::executing_id();
|
||||
Cpu * const cpu = cpu_pool()->cpu(cpu_id);
|
||||
cpu = cpu_pool()->cpu(Cpu::executing_id());
|
||||
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;
|
||||
|
||||
|
||||
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;
|
||||
cs = core ? 0x8 : 0x1b;
|
||||
ss = core ? 0x10 : 0x23;
|
||||
cs = core ? 0x8 : 0x1b;
|
||||
ss = core ? 0x10 : 0x23;
|
||||
}
|
||||
|
||||
|
||||
Genode::Cpu::Mmu_context::Mmu_context(addr_t const table)
|
||||
: cr3(Cr3::Pdb::masked(table)) {}
|
||||
|
||||
|
||||
void Genode::Cpu::Tss::init()
|
||||
{
|
||||
enum { TSS_SELECTOR = 0x28, };
|
||||
|
@ -75,51 +75,25 @@ class Genode::Cpu
|
||||
/**
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* 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);
|
||||
Mmu_context(addr_t page_table_base);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* 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:
|
||||
|
||||
Fpu _fpu;
|
||||
@ -149,7 +123,7 @@ class Genode::Cpu
|
||||
*
|
||||
* \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()))
|
||||
Cr3::write(context.regs->cr3);
|
||||
if ((context.cs != 0x8) && (mmu_context.cr3 != Cr3::read()))
|
||||
Cr3::write(mmu_context.cr3);
|
||||
};
|
||||
|
||||
#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 */
|
||||
#include <kernel/cpu.h>
|
||||
#include <kernel/thread.h>
|
||||
#include <kernel/pd.h>
|
||||
|
||||
@ -58,18 +59,17 @@ void Kernel::Thread::_mmu_exception()
|
||||
}
|
||||
|
||||
|
||||
void Kernel::Thread::_init() { }
|
||||
|
||||
|
||||
void Kernel::Thread::_call_update_pd() { }
|
||||
|
||||
|
||||
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);
|
||||
*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"
|
||||
"popq %%r8 \n"
|
||||
@ -90,3 +90,16 @@ void Kernel::Thread::proceed(unsigned const)
|
||||
"add $16, %%rsp \n"
|
||||
"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;
|
||||
|
||||
void Thread::exception(unsigned const cpu)
|
||||
void Thread::exception(Cpu & cpu)
|
||||
{
|
||||
using Genode::Cpu_state;
|
||||
|
||||
@ -28,7 +28,7 @@ void Thread::exception(unsigned const cpu)
|
||||
_mmu_exception();
|
||||
return;
|
||||
case Cpu_state::NO_MATH_COPROC:
|
||||
if (_cpu->fpu().fault(fpu_regs)) { return; }
|
||||
if (_cpu->fpu().fault(*regs)) { return; }
|
||||
Genode::warning(*this, ": FPU error");
|
||||
_die();
|
||||
return;
|
||||
@ -42,7 +42,7 @@ void Thread::exception(unsigned const cpu)
|
||||
}
|
||||
if (regs->trapno >= Cpu_state::INTERRUPTS_START &&
|
||||
regs->trapno <= Cpu_state::INTERRUPTS_END) {
|
||||
_interrupt(cpu);
|
||||
_interrupt(cpu.id());
|
||||
return;
|
||||
}
|
||||
Genode::warning(*this, ": triggered unknown exception ", regs->trapno,
|
||||
|
@ -13,19 +13,20 @@
|
||||
*/
|
||||
|
||||
/* core includes */
|
||||
#include <kernel/cpu.h>
|
||||
#include <kernel/thread.h>
|
||||
#include <pic.h>
|
||||
|
||||
using namespace Kernel;
|
||||
|
||||
void Thread::exception(unsigned const cpu)
|
||||
void Thread::exception(Cpu & cpu)
|
||||
{
|
||||
switch (regs->trapno) {
|
||||
case Cpu::Context::PAGE_FAULT:
|
||||
_mmu_exception();
|
||||
return;
|
||||
case Cpu::Context::NO_MATH_COPROC:
|
||||
if (_cpu->fpu().fault(fpu_regs)) { return; }
|
||||
if (_cpu->fpu().fault(*regs)) { return; }
|
||||
Genode::warning(*this, ": FPU error");
|
||||
_die();
|
||||
return;
|
||||
@ -40,7 +41,7 @@ void Thread::exception(unsigned const cpu)
|
||||
if (regs->trapno >= Cpu::Context::INTERRUPTS_START &&
|
||||
regs->trapno <= Cpu::Context::INTERRUPTS_END) {
|
||||
pic()->irq_occurred(regs->trapno);
|
||||
_interrupt(cpu);
|
||||
_interrupt(cpu.id());
|
||||
return;
|
||||
}
|
||||
Genode::warning(*this, ": triggered unknown exception ", regs->trapno,
|
||||
|
@ -15,6 +15,7 @@
|
||||
|
||||
#include <assertion.h>
|
||||
#include <platform_pd.h>
|
||||
#include <kernel/cpu.h>
|
||||
#include <kernel/vm.h>
|
||||
#include <cpu/cpu_state.h>
|
||||
#include <pic.h>
|
||||
@ -27,35 +28,29 @@ Kernel::Vm::Vm(void * const state, Kernel::Signal_context * const context,
|
||||
_table(nullptr)
|
||||
{
|
||||
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() { }
|
||||
|
||||
|
||||
void Kernel::Vm::exception(unsigned const cpu_id)
|
||||
void Kernel::Vm::exception(Cpu & cpu)
|
||||
{
|
||||
pause();
|
||||
if (regs->trapno == 200) {
|
||||
if (_state->trapno == 200) {
|
||||
_context->submit(1);
|
||||
return;
|
||||
}
|
||||
|
||||
if (regs->trapno >= Genode::Cpu_state::INTERRUPTS_START &&
|
||||
regs->trapno <= Genode::Cpu_state::INTERRUPTS_END) {
|
||||
pic()->irq_occurred(regs->trapno);
|
||||
_interrupt(cpu_id);
|
||||
if (_state->trapno >= Genode::Cpu_state::INTERRUPTS_START &&
|
||||
_state->trapno <= Genode::Cpu_state::INTERRUPTS_END) {
|
||||
pic()->irq_occurred(_state->trapno);
|
||||
_interrupt(cpu.id());
|
||||
_context->submit(1);
|
||||
return;
|
||||
}
|
||||
Genode::warning("VM: triggered unknown exception ", regs->trapno,
|
||||
" with error code ", regs->errcode);
|
||||
Genode::warning("VM: triggered unknown exception ", _state->trapno,
|
||||
" with error code ", _state->errcode);
|
||||
|
||||
ASSERT_NEVER_CALLED;
|
||||
}
|
||||
@ -63,10 +58,10 @@ void Kernel::Vm::exception(unsigned const cpu_id)
|
||||
|
||||
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);
|
||||
*tss_stack_ptr = ®s->cr3;
|
||||
*tss_stack_ptr = (void*)((addr_t)_state + sizeof(Genode::Cpu_state));
|
||||
|
||||
asm volatile("sti \n"
|
||||
"mov $1, %rax \n"
|
||||
|
@ -18,15 +18,17 @@
|
||||
#include <base/stdint.h>
|
||||
|
||||
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
|
||||
{
|
||||
private:
|
||||
|
||||
static constexpr Genode::size_t ALIGN = alignof(T);
|
||||
|
||||
char _space[sizeof(T) + ALIGN - 1];
|
||||
T & _obj;
|
||||
|
||||
|
@ -167,7 +167,9 @@ struct Hw::Arm_cpu
|
||||
};
|
||||
|
||||
/* 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 */
|
||||
ARM_CP15_REGISTER_32BIT(Ifsr, c5, c0, 0, 1);
|
||||
|
Loading…
x
Reference in New Issue
Block a user