hw: remove User_context

Fix #2540
This commit is contained in:
Stefan Kalkowski 2017-10-06 12:02:36 +02:00 committed by Christian Helmuth
parent 0635d5fffb
commit d6a05245f2
45 changed files with 463 additions and 754 deletions

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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())));

View File

@ -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

View File

@ -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

View File

@ -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);
}

View File

@ -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 **
***************/

View File

@ -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();
}

View File

@ -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_ */

View File

@ -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; }
};

View File

@ -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());
}

View File

@ -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

View File

@ -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;
}

View File

@ -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());
}

View File

@ -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; }

View File

@ -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);
}

View File

@ -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); }
}

View File

@ -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_ */

View File

@ -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());
}

View File

@ -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));
}

View 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());
}

View File

@ -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_ */

View File

@ -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());
}

View File

@ -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); }
/**

View File

@ -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; }

View 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);
}

View File

@ -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_ */

View File

@ -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());
}

View File

@ -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; }

View File

@ -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; }

View File

@ -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);
}

View File

@ -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, };

View File

@ -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_ */

View File

@ -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()); }

View File

@ -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 = &regs->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" (&regs->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; }

View File

@ -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,

View File

@ -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,

View File

@ -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 = &regs->cr3;
*tss_stack_ptr = (void*)((addr_t)_state + sizeof(Genode::Cpu_state));
asm volatile("sti \n"
"mov $1, %rax \n"

View File

@ -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;

View File

@ -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);