hw_arndale: enable ARM virtualization extensions

* enables world-switch using ARM virtualization extensions
* split TrustZone and virtualization extensions hardly from platforms,
  where it is not used
* extend 'Vm_session' interface to enable configuration of guest-physical memory
* introduce VM destruction syscall
* add virtual machine monitor for hw_arndale that emulates a simplified version
  of ARM's Versatile Express Cortex A15 board for a Linux guest OS

Fixes #1405
This commit is contained in:
Stefan Kalkowski 2015-02-19 14:50:27 +01:00 committed by Christian Helmuth
parent 07c8d1652e
commit 7582396e9c
73 changed files with 3460 additions and 738 deletions

View File

@ -0,0 +1,80 @@
/*
* \brief CPU, PIC, and timer context of a virtual machine
* \author Stefan Kalkowski
* \date 2015-02-10
*/
/*
* Copyright (C) 2015 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#ifndef _INCLUDE__PLATFORM__ARNDALE__VM_STATE_H_
#define _INCLUDE__PLATFORM__ARNDALE__VM_STATE_H_
/* Genode includes */
#include <cpu/cpu_state.h>
namespace Genode
{
/**
* CPU context of a virtual machine
*/
struct Vm_state;
}
struct Genode::Vm_state : Genode::Cpu_state_modes
{
Genode::uint64_t vttbr;
Genode::uint32_t sctrl;
Genode::uint32_t hsr;
Genode::uint32_t hpfar;
Genode::uint32_t hdfar;
Genode::uint32_t hifar;
Genode::uint32_t ttbcr;
Genode::uint32_t ttbr0;
Genode::uint32_t ttbr1;
Genode::uint32_t prrr;
Genode::uint32_t nmrr;
Genode::uint32_t dacr;
Genode::uint32_t dfsr;
Genode::uint32_t ifsr;
Genode::uint32_t adfsr;
Genode::uint32_t aifsr;
Genode::uint32_t dfar;
Genode::uint32_t ifar;
Genode::uint32_t cidr;
Genode::uint32_t tls1;
Genode::uint32_t tls2;
Genode::uint32_t tls3;
Genode::uint32_t cpacr;
/**
* Timer related registers
*/
Genode::uint32_t timer_ctrl;
Genode::uint32_t timer_val;
bool timer_irq;
/**
* PIC related registers
*/
enum { NR_IRQ = 4 };
Genode::uint32_t gic_hcr;
Genode::uint32_t gic_vmcr;
Genode::uint32_t gic_misr;
Genode::uint32_t gic_apr;
Genode::uint32_t gic_eisr;
Genode::uint32_t gic_elrsr0;
Genode::uint32_t gic_lr[4];
unsigned gic_irq;
};
#endif /* _INCLUDE__PLATFORM__ARNDALE__VM_STATE_H_ */

View File

@ -1,5 +1,5 @@
/*
* \brief CPU context of a virtual machine
* \brief CPU context of a virtual machine for TrustZone
* \author Stefan Kalkowski
* \author Martin Stein
* \date 2013-10-30
@ -12,18 +12,25 @@
* under the terms of the GNU General Public License version 2.
*/
#ifndef _KERNEL__VM_STATE_H_
#define _KERNEL__VM_STATE_H_
#ifndef _INCLUDE__PLATFORM__IMX53__VM_STATE_H_
#define _INCLUDE__PLATFORM__IMX53__VM_STATE_H_
/* Genode includes */
#include <cpu/cpu_state.h>
namespace Kernel
namespace Genode
{
/**
* CPU context of a virtual machine
*/
struct Vm_state : Genode::Cpu_state_modes { Genode::addr_t dfar; };
struct Vm_state;
}
#endif /* _KERNEL__VM_STATE_H_ */
struct Genode::Vm_state : Genode::Cpu_state_modes
{
Genode::addr_t dfar;
Genode::addr_t ttbr[2];
Genode::addr_t ttbrc;
};
#endif /* _INCLUDE__PLATFORM__IMX53__VM_STATE_H_ */

View File

@ -31,6 +31,7 @@ namespace Genode
explicit Vm_session_client(Vm_session_capability session)
: Rpc_client<Vm_session>(session) { }
/**************************
** Vm_session interface **
**************************/
@ -43,6 +44,15 @@ namespace Genode
void run() { call<Rpc_run>(); }
void pause() { call<Rpc_pause>(); }
void attach(Dataspace_capability ds,addr_t vm_addr) {
call<Rpc_attach>(ds, vm_addr); }
void detach(addr_t vm_addr, size_t size) {
call<Rpc_detach>(vm_addr, size); }
void attach_pic(addr_t vm_addr) {
call<Rpc_attach_pic>(vm_addr); }
};
}

View File

@ -26,6 +26,8 @@ namespace Genode {
{
static const char *service_name() { return "VM"; }
class Invalid_dataspace : Exception { };
/**
* Destructor
*/
@ -51,6 +53,33 @@ namespace Genode {
*/
virtual void pause(void) {}
/**
* Attach dataspace to the guest-physical memory address space
*
* \param ds dataspace to be attached
* \param vm_addr address in guest-physical memory address space
*/
virtual void attach(Dataspace_capability ds, addr_t vm_addr) = 0;
/**
* Invalidate region of the guest-physical memory address space
*
* \param vm_addr address in guest-physical memory address space
* \param size size of the region to invalidate
*/
virtual void detach(addr_t vm_addr, size_t size) = 0;
/**
* Attach cpu-local interrupt-controller's interface to
* guest-physical memory address space.
*
* \param vm_addr address in guest-physical memory address space
*
* Note: this is currently only support for ARM interrupt-controller
* hardware virtualization
*/
virtual void attach_pic(addr_t vm_addr) = 0;
/*********************
** RPC declaration **
@ -61,8 +90,14 @@ namespace Genode {
Signal_context_capability);
GENODE_RPC(Rpc_run, void, run);
GENODE_RPC(Rpc_pause, void, pause);
GENODE_RPC_THROW(Rpc_attach, void, attach,
GENODE_TYPE_LIST(Invalid_dataspace),
Dataspace_capability, addr_t);
GENODE_RPC(Rpc_detach, void, detach, addr_t, size_t);
GENODE_RPC(Rpc_attach_pic, void, attach_pic, addr_t);
GENODE_RPC_INTERFACE(Rpc_cpu_state, Rpc_exception_handler,
Rpc_run, Rpc_pause);
Rpc_run, Rpc_pause, Rpc_attach, Rpc_detach,
Rpc_attach_pic);
};
}

View File

@ -11,7 +11,6 @@ INC_DIR += $(REP_DIR)/src/core/include/spec/arm
SRC_CC += spec/arm/kernel/thread_base.cc
SRC_CC += spec/arm/kernel/thread.cc
SRC_CC += spec/arm/kernel/cpu.cc
SRC_CC += spec/arm/kernel/vm.cc
# add assembly sources
SRC_S += spec/arm/crt0.s

View File

@ -9,6 +9,8 @@ INC_DIR += $(REP_DIR)/src/core/include/spec/arm_v6
# add C++ sources
SRC_CC += spec/arm/cpu.cc
SRC_CC += spec/arm/kernel/cpu_context.cc
SRC_CC += kernel/vm_thread.cc
# add assembly sources
SRC_S += spec/arm_v6/mode_transition.s

View File

@ -50,7 +50,6 @@ SRC_CC += pager.cc
SRC_CC += _main.cc
SRC_CC += kernel/kernel.cc
SRC_CC += kernel/thread.cc
SRC_CC += kernel/vm.cc
SRC_CC += kernel/signal_receiver.cc
SRC_CC += kernel/irq.cc
SRC_CC += kernel/pd.cc

View File

@ -9,6 +9,7 @@ INC_DIR += $(REP_DIR)/src/core/include/spec/cortex_a8
# add C++ sources
SRC_CC += spec/arm/cpu.cc
SRC_CC += spec/arm/kernel/cpu_context.cc
# include less specific configuration
include $(REP_DIR)/lib/mk/arm_v7/core.inc

View File

@ -11,6 +11,8 @@ INC_DIR += $(REP_DIR)/src/core/include/spec/arm_gic
# add C++ sources
SRC_CC += spec/arm/cpu.cc
SRC_CC += spec/arm_gic/pic.cc
SRC_CC += spec/arm/kernel/cpu_context.cc
SRC_CC += kernel/vm_thread.cc
# include less specific configuration
include $(REP_DIR)/lib/mk/arm_v7/core.inc

View File

@ -10,7 +10,6 @@ INC_DIR += $(REP_DIR)/src/core/include/spec/exynos5
# add C++ sources
SRC_CC += spec/exynos5/platform_support.cc
SRC_CC += spec/exynos5/cpu.cc
SRC_CC += platform_services.cc
# include less specific configuration
include $(REP_DIR)/lib/mk/cortex_a15/core.inc

View File

@ -4,9 +4,22 @@
# \date 2015-02-09
#
# add include paths
INC_DIR += $(REP_DIR)/src/core/include/spec/arm_v7/virtualization
# add C++ sources
SRC_CC += spec/arndale/board.cc
SRC_CC += spec/arndale/pic.cc
SRC_CC += spec/arndale/platform_services.cc
SRC_CC += spec/arm_v7/kernel/vm_thread.cc
SRC_CC += spec/arm_v7/virtualization/kernel/vm.cc
SRC_CC += spec/arm_v7/virtualization/kernel/vm_thread.cc
SRC_CC += spec/arm_v7/virtualization/kernel/cpu_context.cc
SRC_CC += spec/arm_v7/vm_session_component.cc
SRC_CC += spec/arm_v7/virtualization/vm_session_component.cc
# add assembly sources
SRC_S += spec/arm_v7/virtualization/mode_transition.s
# include less specific configuration
include $(REP_DIR)/lib/mk/exynos5/core.inc

View File

@ -0,0 +1,13 @@
#
# \brief Build config for Genodes core process
# \author Stefan Kalkowski
# \author Martin Stein
# \date 2012-10-24
#
# add include paths
INC_DIR += $(REP_DIR)/src/core/include/spec/imx53
INC_DIR += $(REP_DIR)/src/core/include/spec/imx
# include less specific configuration
include $(REP_DIR)/lib/mk/cortex_a8/core.inc

View File

@ -5,14 +5,12 @@
# \date 2012-10-24
#
# add include paths
INC_DIR += $(REP_DIR)/src/core/include/spec/imx53
INC_DIR += $(REP_DIR)/src/core/include/spec/cortex_a8
# add C++ sources
SRC_CC += kernel/vm_thread.cc
SRC_CC += spec/imx53/platform_support.cc
SRC_CC += spec/imx53/pic.cc
SRC_CC += platform_services.cc
# include less specific configuration
include $(REP_DIR)/lib/mk/platform_imx53/core-trustzone.inc
include $(REP_DIR)/lib/mk/core-trustzone.inc

View File

@ -6,15 +6,22 @@
#
# add include paths
INC_DIR += $(REP_DIR)/src/core/include/spec/arm_v7/trustzone
INC_DIR += $(REP_DIR)/src/core/include/spec/imx53/trustzone
INC_DIR += $(REP_DIR)/src/core/include/spec/imx53
INC_DIR += $(REP_DIR)/src/core/include/spec/cortex_a8
# add C++ sources
SRC_CC += spec/imx53/trustzone/platform_support.cc
SRC_CC += spec/imx53/trustzone/platform_services.cc
SRC_CC += spec/imx53/trustzone/pic.cc
SRC_CC += vm_session_component.cc
SRC_CC += spec/arm_v7/kernel/vm_thread.cc
SRC_CC += spec/arm_v7/trustzone/kernel/vm.cc
SRC_CC += spec/arm_v7/trustzone/kernel/vm_thread.cc
SRC_CC += spec/arm_v7/vm_session_component.cc
SRC_CC += spec/arm_v7/trustzone/vm_session_component.cc
# add assembly sources
SRC_S += spec/arm_v7/trustzone/mode_transition.s
# include less specific configuration
include $(REP_DIR)/lib/mk/platform_imx53/core-trustzone.inc
include $(REP_DIR)/lib/mk/core-trustzone.inc

View File

@ -7,11 +7,3 @@
# add library dependencies
LIBS += core-trustzone
# add include paths
INC_DIR += $(REP_DIR)/src/core/include/spec/imx53
INC_DIR += $(REP_DIR)/src/core/include/spec/imx
INC_DIR += $(REP_DIR)/src/core/include/spec/cortex_a8
# include less specific configuration
include $(REP_DIR)/lib/mk/cortex_a8/core.inc

View File

@ -7,6 +7,9 @@
# add C++ sources
SRC_CC += spec/exynos5/board.cc
SRC_CC += spec/arm_gic/pic.cc
SRC_CC += platform_services.cc
SRC_CC += kernel/vm_thread.cc
SRC_CC += spec/arm/kernel/cpu_context.cc
# include less specific configuration
include $(REP_DIR)/lib/mk/exynos5/core.inc

View File

@ -26,7 +26,6 @@ namespace Kernel
unsigned pd_alignment_log2();
size_t signal_context_size();
size_t signal_receiver_size();
size_t vm_size();
/**
* Kernel names of the kernel calls
@ -48,6 +47,7 @@ namespace Kernel
constexpr Call_arg call_id_run_vm() { return 28; }
constexpr Call_arg call_id_pause_vm() { return 29; }
constexpr Call_arg call_id_pause_thread() { return 30; }
constexpr Call_arg call_id_bin_vm() { return 31; }
/**
* Create a domain
@ -293,6 +293,8 @@ namespace Kernel
* \param dst memory donation for the VM object
* \param state location of the CPU state of the VM
* \param signal_context_id kernel name of the signal context for VM events
* \param table guest-physical to host-physical translation
* table pointer
*
* \retval >0 kernel name of the new VM
* \retval 0 failed
@ -300,10 +302,11 @@ namespace Kernel
* Regaining of the supplied memory is not supported by now.
*/
inline unsigned new_vm(void * const dst, void * const state,
unsigned const signal_context_id)
unsigned const signal_context_id,
void * const table)
{
return call(call_id_new_vm(), (Call_arg)dst, (Call_arg)state,
signal_context_id);
(Call_arg)table, signal_context_id);
}
@ -311,10 +314,27 @@ namespace Kernel
* Execute a virtual-machine (again)
*
* \param vm_id kernel name of the targeted VM
*
* \retval 0 suceeded
* \retval -1 failed
*/
inline void run_vm(unsigned const vm_id)
inline int run_vm(unsigned const vm_id)
{
call(call_id_run_vm(), vm_id);
return call(call_id_run_vm(), vm_id);
}
/**
* Destruct a virtual-machine
*
* \param vm_id kernel name of the targeted VM
*
* \retval 0 suceeded
* \retval -1 failed
*/
inline int bin_vm(unsigned const vm_id)
{
return call(call_id_bin_vm(), vm_id);
}
@ -322,10 +342,13 @@ namespace Kernel
* Stop execution of a virtual-machine
*
* \param vm_id kernel name of the targeted VM
*
* \retval 0 suceeded
* \retval -1 failed
*/
inline void pause_vm(unsigned const vm_id)
inline int pause_vm(unsigned const vm_id)
{
call(call_id_pause_vm(), vm_id);
return call(call_id_pause_vm(), vm_id);
}
}

View File

@ -49,16 +49,6 @@ class Kernel::Irq : public Object_pool<Irq>::Item
{
protected:
/**
* Prevent interrupt from occurring
*/
void _disable() const;
/**
* Allow interrupt to occur
*/
void _enable() const;
/**
* Get kernel name of the interrupt
*/
@ -96,6 +86,16 @@ class Kernel::Irq : public Object_pool<Irq>::Item
* Handle occurence of the interrupt
*/
virtual void occurred() { }
/**
* Prevent interrupt from occurring
*/
void disable() const;
/**
* Allow interrupt to occur
*/
void enable() const;
};
@ -128,7 +128,7 @@ class Kernel::User_irq
** Signal_ack_handler **
************************/
void _signal_acknowledged() { _enable(); }
void _signal_acknowledged() { enable(); }
public:
@ -141,7 +141,7 @@ class Kernel::User_irq
: Irq(irq_id), Signal_context(this, 0)
{
_pool()->insert(this);
_disable();
disable();
Signal_context::ack_handler(this);
}
@ -151,7 +151,7 @@ class Kernel::User_irq
void occurred()
{
Signal_context::submit(1);
_disable();
disable();
}
/**

View File

@ -15,11 +15,13 @@
#ifndef _KERNEL__KERNEL_H_
#define _KERNEL__KERNEL_H_
#include <pic.h>
#include <kernel/pd.h>
namespace Kernel {
Pd * core_pd();
Mode_transition_control * mtc();
Pic * pic();
}
#endif /* _KERNEL__KERNEL_H_ */

View File

@ -24,14 +24,14 @@
#include <kernel/configuration.h>
#include <kernel/object.h>
#include <kernel/cpu.h>
#include <kernel/vm_state.h>
#include <assert.h>
#include <page_slab.h>
#include <board.h>
/* structure of the mode transition */
extern int _mt_begin;
extern int _mt_end;
extern int _mt_user_entry_pic;
extern int _mt_vm_entry_pic;
extern Genode::addr_t _mt_client_context_ptr;
extern Genode::addr_t _mt_master_context_begin;
extern Genode::addr_t _mt_master_context_end;
@ -148,31 +148,6 @@ class Kernel::Mode_transition_control
return VIRT_BASE + (phys - phys_base);
}
/**
* Continue execution of client context
*
* \param context targeted CPU context
* \param cpu kernel name of targeted CPU
* \param entry_raw raw pointer to assembly entry-code
*/
void _continue_client(void * const context, unsigned const cpu,
addr_t const entry_raw)
{
/* override client-context pointer of the executing CPU */
addr_t const context_ptr_base = (addr_t)&_mt_client_context_ptr;
size_t const context_ptr_offset = cpu * sizeof(context);
addr_t const context_ptr = context_ptr_base + context_ptr_offset;
*(void * *)context_ptr = context;
/* unlock kernel data */
data_lock().unlock();
/* call assembly code that applies the virtual-machine context */
typedef void (* Entry)();
Entry __attribute__((noreturn)) const entry = (Entry)entry_raw;
entry();
}
public:
enum {
@ -208,17 +183,44 @@ class Kernel::Mode_transition_control
}
/**
* Continue execution of 'user' at 'cpu'
* Continue execution of client context
*
* \param context targeted CPU context
* \param cpu kernel name of targeted CPU
* \param entry_raw raw pointer to assembly entry-code
* \param context_ptr_base base address of client-context pointer region
*/
void continue_user(Cpu::Context * const user, unsigned const cpu) {
_continue_client(user, cpu, _virt_user_entry()); }
void switch_to(Cpu::Context * const context,
unsigned const cpu,
addr_t const entry_raw,
addr_t const context_ptr_base)
{
/* override client-context pointer of the executing CPU */
size_t const context_ptr_offset = cpu * sizeof(context);
addr_t const context_ptr = context_ptr_base + context_ptr_offset;
*(void * *)context_ptr = context;
/* unlock kernel data */
data_lock().unlock();
/* call assembly code that applies the virtual-machine context */
typedef void (* Entry)();
Entry __attribute__((noreturn)) const entry = (Entry)entry_raw;
entry();
}
/**
* Continue execution of 'vm' at 'cpu'
* Continue execution of user context
*
* \param context targeted CPU context
* \param cpu kernel name of targeted CPU
*/
void continue_vm(Vm_state * const vm, unsigned const cpu) {
_continue_client(vm, cpu, (addr_t)&_mt_vm_entry_pic); }
void switch_to_user(Cpu::Context * const context,
unsigned const cpu)
{
switch_to(context, cpu, _virt_user_entry(),
(addr_t)&_mt_client_context_ptr);
}
} __attribute__((aligned(Mode_transition_control::ALIGN)));
class Kernel::Pd : public Object<Pd, MAX_PDS, Pd_ids, pd_ids, pd_pool>

View File

@ -235,6 +235,7 @@ class Kernel::Thread
void _call_bin_signal_context();
void _call_bin_signal_receiver();
void _call_new_vm();
void _call_bin_vm();
void _call_run_vm();
void _call_pause_vm();
void _call_access_thread_regs();

View File

@ -14,8 +14,9 @@
#ifndef _KERNEL__VM_H_
#define _KERNEL__VM_H_
#include <vm_state.h>
/* core includes */
#include <kernel/vm_state.h>
#include <kernel/kernel.h>
#include <kernel/pd.h>
#include <kernel/signal_receiver.h>
@ -34,13 +35,18 @@ namespace Kernel
Vm_pool * vm_pool();
}
class Kernel::Vm : public Object<Vm, MAX_VMS, Vm_ids, vm_ids, vm_pool>,
public Cpu_job
{
private:
Vm_state * const _state;
Signal_context * const _context;
enum State { ACTIVE, INACTIVE };
Genode::Vm_state * const _state;
Signal_context * const _context;
void * const _table;
State _scheduled = INACTIVE;
public:
@ -49,20 +55,35 @@ class Kernel::Vm : public Object<Vm, MAX_VMS, Vm_ids, vm_ids, vm_pool>,
*
* \param state initial CPU state
* \param context signal for VM exceptions other than interrupts
* \param table translation table for guest to host physical memory
*/
Vm(void * const state, Signal_context * const context)
:
Cpu_job(Cpu_priority::min, 0), _state((Vm_state * const)state),
_context(context)
{ affinity(cpu_pool()->primary_cpu()); }
Vm(void * const state,
Signal_context * const context,
void * const table);
/**
* Inject an interrupt to this VM
*
* \param irq interrupt number to inject
*/
void inject_irq(unsigned irq);
/****************
** Vm_session **
****************/
void run() { Cpu_job::_activate_own_share(); }
void pause() { Cpu_job::_deactivate_own_share(); }
void run()
{
if (_scheduled != ACTIVE) Cpu_job::_activate_own_share();
_scheduled = ACTIVE;
}
void pause()
{
if (_scheduled != INACTIVE) Cpu_job::_deactivate_own_share();
_scheduled = INACTIVE;
}
/*************
@ -70,7 +91,7 @@ class Kernel::Vm : public Object<Vm, MAX_VMS, Vm_ids, vm_ids, vm_pool>,
*************/
void exception(unsigned const cpu);
void proceed(unsigned const cpu) { mtc()->continue_vm(_state, cpu); }
void proceed(unsigned const cpu);
Cpu_job * helping_sink() { return this; }
};

View File

@ -345,27 +345,21 @@ class Genode::Arm
*/
struct Context : Cpu_state
{
/**
* TODO: currently all non-Cortex A15 platforms use the
* short translation table format and thereby the Context ID
* register to store the ASID, and the TTBR0 for the table
* address. Cortex A15 uses the long translation format and
* a 64-bit wide TTBR0 that holds all information.
* The current Cortex A15 implementation stores TTBR0 in both
* members stated below.
*/
uint32_t cidr;
uint32_t ttbr0;
Cidr::access_t cidr;
Ttbr0::access_t ttbr0;
/**
* Return base of assigned translation table
*/
addr_t translation_table() const;
addr_t translation_table() const {
return Ttbr0::Ba::masked(ttbr0); }
/**
* Assign translation-table base 'table'
*/
void translation_table(addr_t const table);
void translation_table(addr_t const table) {
ttbr0 = Arm::Ttbr0::init(table); }
/**
* Assign protection domain
@ -421,7 +415,41 @@ class Genode::Arm
* \param va holds the virtual fault-address if call returns 1
* \param w holds wether it's a write fault if call returns 1
*/
bool in_fault(addr_t & va, addr_t & w) const;
bool in_fault(addr_t & va, addr_t & w) const
{
switch (cpu_exception) {
case PREFETCH_ABORT:
{
/* check if fault was caused by a translation miss */
Ifsr::access_t const fs = Ifsr::Fs::get(Ifsr::read());
if (fs != Ifsr::section && fs != Ifsr::page)
return false;
/* fetch fault data */
w = 0;
va = ip;
return true;
}
case DATA_ABORT:
{
/* check if fault was caused by translation miss */
Dfsr::access_t const fs = Dfsr::Fs::get(Dfsr::read());
if (fs != Dfsr::section && fs != Dfsr::page)
return false;
/* fetch fault data */
Dfsr::access_t const dfsr = Dfsr::read();
w = Dfsr::Wnr::get(dfsr);
va = Dfar::read();
return true;
}
default:
return false;
};
}
};
/**

View File

@ -86,6 +86,8 @@
.set TRANSIT_TTBR0_OFFSET, 17 * 4
.set CIDR_OFFSET, 18 * 4
.set TTBR0_OFFSET, 19 * 4
.set TTBCR_OFFSET, 20 * 4
.set MAIR0_OFFSET, 21 * 4
/* size of local variables */
.set CONTEXT_PTR_SIZE, 1 * 4

View File

@ -238,6 +238,22 @@ class Genode::Arm_v7 : public Arm
}
};
/**
* Memory attribute indirection register 0
*/
struct Mair0 : Register<32>
{
struct Attr0 : Bitfield<0, 8> { };
struct Attr1 : Bitfield<8, 8> { };
struct Attr2 : Bitfield<16, 8> { };
struct Attr3 : Bitfield<24, 8> { };
static void write(access_t v) {
asm volatile ("mcr p15, 0, %[v], c10, c2, 0" :: [v]"r"(v) : ); }
};
/**
* Invalidate all branch predictions
*/

View File

@ -25,3 +25,62 @@
/* get the affinity-0 bitfield from the read register value */
and \r, \r, #0xff
.endm
/**
* Determine the base of the client context of the executing CPU
*
* \param target_reg register that shall receive the base pointer
* \param buf_reg register that can be polluted by the macro
* \param client_context_ptr label of the client context pointer base
*/
.macro _get_client_context_ptr target_reg, buf_reg, client_context_ptr
/* get kernel name of CPU */
_get_cpu_id \buf_reg
/* multiply CPU name with pointer size to get offset of pointer */
mov \target_reg, #CONTEXT_PTR_SIZE
mul \buf_reg, \buf_reg, \target_reg
/* get base of the pointer array */
adr \target_reg, \client_context_ptr
/* add offset and base to get CPU-local pointer */
add \target_reg, \target_reg, \buf_reg
ldr \target_reg, [\target_reg]
.endm
/**
* Save sp, lr and spsr register banks of specified exception mode
*/
.macro _save_bank mode
cps #\mode /* switch to given mode */
mrs r1, spsr /* store mode-specific spsr */
stmia r0!, {r1,sp,lr} /* store mode-specific sp and lr */
.endm /* _save_bank mode */
/**
* Restore sp, lr and spsr register banks of specified exception mode
*/
.macro _restore_bank mode
cps #\mode /* switch to given mode */
ldmia r0!, {r1,sp,lr} /* load mode-specific sp, lr, and spsr into r1 */
msr spsr_cxfs, r1 /* load mode-specific spsr */
.endm
/***************
** Constants **
***************/
/* hardware names of CPU modes */
.set USR_MODE, 16
.set FIQ_MODE, 17
.set IRQ_MODE, 18
.set SVC_MODE, 19
.set ABT_MODE, 23
.set UND_MODE, 27

View File

@ -0,0 +1,76 @@
/*
* \brief Core-specific instance of the VM session interface
* \author Stefan Kalkowski
* \date 2012-10-08
*/
/*
* Copyright (C) 2012-2013 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#ifndef _CORE__INCLUDE__VM_SESSION_COMPONENT_H_
#define _CORE__INCLUDE__VM_SESSION_COMPONENT_H_
/* Genode includes */
#include <base/allocator.h>
#include <base/rpc_server.h>
#include <vm_session/vm_session.h>
#include <dataspace/capability.h>
/* Core includes */
#include <dataspace_component.h>
#include <kernel/vm.h>
namespace Genode {
class Vm_session_component;
}
class Genode::Vm_session_component :
public Genode::Rpc_object<Genode::Vm_session>
{
private:
Rpc_entrypoint *_ds_ep;
Range_allocator *_ram_alloc;
unsigned _vm_id;
char _vm[sizeof(Kernel::Vm)];
Dataspace_component _ds;
Dataspace_capability _ds_cap;
addr_t _ds_addr;
static size_t _ds_size() {
return align_addr(sizeof(Cpu_state_modes),
get_page_size_log2()); }
addr_t _alloc_ds(size_t &ram_quota);
public:
Vm_session_component(Rpc_entrypoint *ds_ep,
size_t ram_quota);
~Vm_session_component();
/**************************
** Vm session interface **
**************************/
Dataspace_capability cpu_state(void) { return _ds_cap; }
void exception_handler(Signal_context_capability handler);
void run(void);
void pause(void);
void attach(Dataspace_capability ds_cap, addr_t vm_addr) {
PWRN("Not implemented for TrustZone case"); }
void attach_pic(addr_t vm_addr) {
PWRN("Not implemented for TrustZone case"); }
void detach(addr_t vm_addr, size_t size) {
PWRN("Not implemented for TrustZone case"); }
};
#endif /* _CORE__INCLUDE__VM_SESSION_COMPONENT_H_ */

View File

@ -0,0 +1,77 @@
/*
* \brief Core-specific instance of the VM session interface
* \author Stefan Kalkowski
* \date 2012-10-08
*/
/*
* Copyright (C) 2012-2013 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#ifndef _CORE__INCLUDE__VM_SESSION_COMPONENT_H_
#define _CORE__INCLUDE__VM_SESSION_COMPONENT_H_
/* Genode includes */
#include <base/allocator.h>
#include <base/rpc_server.h>
#include <vm_session/vm_session.h>
#include <dataspace/capability.h>
#include <long_translation_table.h>
/* Core includes */
#include <dataspace_component.h>
#include <kernel/vm.h>
namespace Genode {
class Vm_session_component;
}
class Genode::Vm_session_component :
public Genode::Rpc_object<Genode::Vm_session>
{
private:
using Translation_table =
Genode::Level_1_stage_2_translation_table;
Rpc_entrypoint *_ds_ep;
Range_allocator *_ram_alloc;
unsigned _vm_id;
char _vm[sizeof(Kernel::Vm)];
Dataspace_component _ds;
Dataspace_capability _ds_cap;
addr_t _ds_addr;
Translation_table *_table;
Page_slab *_pslab;
static size_t _ds_size() {
return align_addr(sizeof(Cpu_state_modes),
get_page_size_log2()); }
addr_t _alloc_ds(size_t &ram_quota);
void _attach(addr_t phys_addr, addr_t vm_addr, size_t size);
public:
Vm_session_component(Rpc_entrypoint *ds_ep,
size_t ram_quota);
~Vm_session_component();
/**************************
** Vm session interface **
**************************/
Dataspace_capability cpu_state(void) { return _ds_cap; }
void exception_handler(Signal_context_capability handler);
void run(void);
void pause(void);
void attach(Dataspace_capability ds_cap, addr_t vm_addr);
void attach_pic(addr_t vm_addr);
void detach(addr_t vm_addr, size_t size);
};
#endif /* _CORE__INCLUDE__VM_SESSION_COMPONENT_H_ */

View File

@ -57,12 +57,25 @@ class Genode::Cpu : public Arm_v7
}
};
struct Mair0 : Register<32>
/**
* Memory attribute indirection register 0
*/
struct Mair0 : Arm_v7::Mair0
{
static void init()
enum Attr {
DEVICE_MEMORY = 0x04,
NORMAL_MEMORY_UNCACHED = 0x44,
NORMAL_MEMORY_CACHED = 0xff,
};
static access_t init_virt_kernel()
{
access_t v = 0xff0044;
asm volatile ("mcr p15, 0, %[v], c10, c2, 0" :: [v]"r"(v) : );
access_t v = 0;
Attr0::set(v, NORMAL_MEMORY_UNCACHED);
Attr1::set(v, DEVICE_MEMORY);
Attr2::set(v, NORMAL_MEMORY_CACHED);
Attr3::set(v, DEVICE_MEMORY);
return v;
}
};
@ -112,7 +125,285 @@ class Genode::Cpu : public Arm_v7
static Genode::uint32_t init(addr_t const table) {
return table; }
};
/*********************************
** Virtualization extensions **
*********************************/
/**
* Hypervisor translation table base register
*/
struct Httbr : Register<64>
{
static void translation_table(addr_t const table)
{
asm volatile ("mcrr p15, 4, %[v0], %[v1], c2"
:: [v0]"r"(table), [v1]"r"(0));
}
};
/**
* Hypervisor translation control register
*/
struct Htcr : Register<32>
{
static void write(access_t const v) {
asm volatile ("mcr p15, 4, %[v], c2, c0, 2" :: [v] "r" (v)); }
};
/**
* Hypervisor coprocessor trap register
*/
struct Hcptr : Register<32>
{
/* Coprocessor access trap */
template <unsigned COPROC>
struct Tcp : Bitfield<COPROC, 1> {};
struct Tase : Bitfield<15, 1> { };
struct Tta : Bitfield<20, 1> { };
struct Tcpac : Bitfield<31, 1> { };
static access_t init()
{
/* don't trap on cporocessor 10 + 11, but all others */
access_t v = 0;
Tcp<0>::set(v, 1);
Tcp<1>::set(v, 1);
Tcp<2>::set(v, 1);
Tcp<3>::set(v, 1);
Tcp<4>::set(v, 1);
Tcp<5>::set(v, 1);
Tcp<6>::set(v, 1);
Tcp<7>::set(v, 1);
Tcp<8>::set(v, 1);
Tcp<9>::set(v, 1);
Tcp<12>::set(v, 1);
Tcp<13>::set(v, 1);
Tta::set(v, 1);
Tcpac::set(v, 1);
return v;
}
static void write(access_t const v) {
asm volatile ("mcr p15, 4, %[v], c1, c1, 2" :: [v] "r" (v)); }
};
/**
* Hypervisor Memory attribute indirection register 0
*/
struct Hmair0 : Register<32>
{
static void write(access_t const v) {
asm volatile ("mcr p15, 4, %[v], c10, c2, 0" :: [v] "r" (v)); }
};
/**
* Hypervisor system control register
*/
struct Hsctlr : Arm_v7::Sctlr
{
static void write(access_t const v) {
asm volatile ("mcr p15, 4, %[v], c1, c0, 0" :: [v] "r" (v)); }
};
/**
* Hypervisor system trap register
*/
struct Hstr : Register<32>
{
/* System coprocessor primary register access trap */
template <unsigned R>
struct T : Bitfield<R, 1> {};
static access_t init()
{
/*
* allow cache (7), TLB (8) maintenance, and performance
* monitor (9), process/thread ID register (13) and timer (14)
* access.
*/
access_t v = 0;
T<0>::set(v, 1);
T<1>::set(v, 1);
T<2>::set(v, 1);
T<3>::set(v, 1);
T<5>::set(v, 1);
T<6>::set(v, 1);
T<10>::set(v, 1);
T<11>::set(v, 1);
T<12>::set(v, 1);
T<15>::set(v, 1);
return v;
};
};
/**
* Hypervisor control register
*/
struct Hcr : Register<32>
{
struct Vm : Bitfield<0, 1> {}; /* VT MMU enabled */
struct Fmo : Bitfield<3, 1> {}; /* FIQ cannot been masked */
struct Imo : Bitfield<4, 1> {}; /* IRQ cannot been masked */
struct Amo : Bitfield<5, 1> {}; /* A bit cannot been masked */
struct Twi : Bitfield<13, 1> {}; /* trap on WFI instruction */
struct Twe : Bitfield<14, 1> {}; /* trap on WFE instruction */
struct Tidcp : Bitfield<20, 1> {}; /* trap lockdown */
struct Tac : Bitfield<21, 1> {}; /* trap ACTLR accesses */
struct Tvm : Bitfield<26, 1> {}; /* trap virtual memory ctrls */
static access_t init()
{
access_t v = 0;
Vm::set(v, 1);
Fmo::set(v, 1);
Imo::set(v, 1);
Amo::set(v, 1);
Twi::set(v, 1);
Twe::set(v, 1);
Tidcp::set(v, 1);
Tac::set(v, 1);
Tvm::set(v, 1);
return v;
};
};
/**
* Virtualization translation control register
*/
struct Vtcr : Ttbcr
{
struct Sl0 : Bitfield<6,2> {};
static access_t init()
{
access_t v = Ttbcr::init_virt_kernel();
Sl0::set(v, 1); /* set to starting level 1 */
return v;
}
static void write(access_t const v) {
asm volatile ("mcr p15, 4, %[v], c2, c1, 2" :: [v] "r" (v)); }
};
/**
* Extend basic CPU state by members relevant for 'base-hw' only
*
* Note: this class redefines Genode::Arm::Context
*/
struct Context : Genode::Cpu_state
{
Ttbr0::access_t ttbr0 = 0;
Sctlr::access_t sctlr = 0;
Ttbcr::access_t ttbrc = 0;
Mair0::access_t mair0 = 0;
/**
* Return base of assigned translation table
*/
addr_t translation_table() const {
return Ttbr0::Ba::masked(ttbr0); }
/**
* Assign translation-table base 'table'
*/
void translation_table(addr_t const table) {
Ttbr0::Ba::set(ttbr0, (Ttbr0::access_t)(table >> 5)); }
/**
* Assign protection domain
*/
void protection_domain(unsigned const id) {
Ttbr0::Asid::set(ttbr0, id); }
};
/**
* An usermode execution state
*
* FIXME: this class largely overlaps with Genode::Arm::User_context
*/
struct User_context : Context
{
/**
* Constructor
*/
User_context() { cpsr = Psr::init_user(); }
/**
* Support for kernel calls
*/
void user_arg_0(unsigned const arg) { r0 = arg; }
void user_arg_1(unsigned const arg) { r1 = arg; }
void user_arg_2(unsigned const arg) { r2 = arg; }
void user_arg_3(unsigned const arg) { r3 = arg; }
void user_arg_4(unsigned const arg) { r4 = arg; }
void user_arg_5(unsigned const arg) { r5 = arg; }
void user_arg_6(unsigned const arg) { r6 = arg; }
void user_arg_7(unsigned const arg) { r7 = arg; }
unsigned user_arg_0() const { return r0; }
unsigned user_arg_1() const { return r1; }
unsigned user_arg_2() const { return r2; }
unsigned user_arg_3() const { return r3; }
unsigned user_arg_4() const { return r4; }
unsigned user_arg_5() const { return r5; }
unsigned user_arg_6() const { return r6; }
unsigned user_arg_7() const { return r7; }
/**
* Initialize thread context
*
* \param table physical base of appropriate translation table
* \param pd_id kernel name of appropriate protection domain
*/
void init_thread(addr_t const table, unsigned const pd_id)
{
protection_domain(pd_id);
translation_table(table);
}
/**
* 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 wether it's a write fault if call returns 1
*/
bool in_fault(addr_t & va, addr_t & w) const
{
switch (cpu_exception) {
case PREFETCH_ABORT:
{
/* check if fault was caused by a translation miss */
Ifsr::access_t const fs = Ifsr::Fs::get(Ifsr::read());
if ((fs & 0b11100) != 0b100) return false;
/* fetch fault data */
w = 0;
va = ip;
return true;
}
case DATA_ABORT:
{
/* check if fault was caused by translation miss */
Dfsr::access_t const fs = Dfsr::Fs::get(Dfsr::read());
if ((fs & 0b11100) != 0b100) return false;
/* fetch fault data */
Dfsr::access_t const dfsr = Dfsr::read();
w = Dfsr::Wnr::get(dfsr);
va = Dfar::read();
return true;
}
default:
return false;
};
}
};
@ -140,7 +431,7 @@ class Genode::Cpu : public Arm_v7
static void
init_virt_kernel(addr_t const table, unsigned const process_id)
{
Mair0::init();
Mair0::write(Mair0::init_virt_kernel());
Cidr::write(process_id);
Dacr::write(Dacr::init_virt_kernel());
Ttbr0::write(Ttbr0::init(table, 1));

View File

@ -22,15 +22,14 @@
* base address in the one 64-bit TTBR0 register, like in Armv7 cpus without
* LPAE extensions. Therefore, we don't have to use a transition table.
*
* \param transit_ttbr0 ignored parameter
* \param new_cidr new CIDR value, read reg
* \param new_ttbr0 new TTBR0 value, read/write reg
* \param ignored ignored parameter
* \param ttbr0_low low word of TTBR0 64-bit register
* \param ttbr0_high high word of TTBR0 64-bit register
*/
.macro _switch_protection_domain transit_ttbr0, new_cidr, new_ttbr0
.macro _switch_protection_domain ignored, ttbr0_low, ttbr0_high
/* write translation-table-base register 0 */
lsl \new_cidr, \new_cidr, #16
mcrr p15, 0, \new_ttbr0, \new_cidr, c2
mcrr p15, 0, \ttbr0_low, \ttbr0_high, c2
/* instruction and data synchronization barrier */
isb

View File

@ -1,64 +0,0 @@
/*
* \brief Core-specific instance of the VM session interface
* \author Stefan Kalkowski
* \date 2012-10-08
*/
/*
* Copyright (C) 2012-2013 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#ifndef _CORE__INCLUDE__VM_SESSION_COMPONENT_H_
#define _CORE__INCLUDE__VM_SESSION_COMPONENT_H_
/* Genode includes */
#include <base/allocator.h>
#include <base/rpc_server.h>
#include <vm_session/vm_session.h>
#include <dataspace/capability.h>
/* Core includes */
#include <dataspace_component.h>
namespace Genode {
class Vm_session_component : public Rpc_object<Vm_session>
{
private:
Rpc_entrypoint *_ds_ep;
Range_allocator *_ram_alloc;
unsigned _vm_id;
void *_vm;
Dataspace_component _ds;
Dataspace_capability _ds_cap;
addr_t _ds_addr;
static size_t _ds_size() {
return align_addr(sizeof(Cpu_state_modes),
get_page_size_log2()); }
addr_t _alloc_ds(size_t &ram_quota);
public:
Vm_session_component(Rpc_entrypoint *ds_ep,
size_t ram_quota);
~Vm_session_component();
/**************************
** Vm session interface **
**************************/
Dataspace_capability cpu_state(void) { return _ds_cap; }
void exception_handler(Signal_context_capability handler);
void run(void);
void pause(void);
};
}
#endif /* _CORE__INCLUDE__VM_SESSION_COMPONENT_H_ */

View File

@ -32,7 +32,6 @@ namespace Kernel
*/
class Cpu_domain_update_list;
Pic * pic();
Timer * timer();
Cpu_pool * cpu_pool() { return unmanaged_singleton<Cpu_pool>(); }
@ -119,7 +118,7 @@ void Cpu_job::affinity(Cpu * const cpu)
** Cpu_idle **
**************/
void Cpu_idle::proceed(unsigned const cpu) { mtc()->continue_user(this, cpu); }
void Cpu_idle::proceed(unsigned const cpu) { mtc()->switch_to_user(this, cpu); }
/*********

View File

@ -12,19 +12,19 @@
*/
/* core includes */
#include <kernel/kernel.h>
#include <kernel/cpu.h>
#include <kernel/irq.h>
#include <pic.h>
using namespace Kernel;
namespace Kernel { Pic * pic(); }
void Kernel::Irq::disable() const { pic()->mask(_id()); }
void Irq::_disable() const { pic()->mask(_id()); }
void Irq::_enable() const { pic()->unmask(_id(), Cpu::executing_id()); }
void Kernel::Irq::enable() const { pic()->unmask(_id(), Cpu::executing_id()); }
Irq::Pool * User_irq::_pool()
Kernel::Irq::Pool * Kernel::User_irq::_pool()
{
static Irq::Pool p;
return &p;

View File

@ -25,7 +25,6 @@
/* core includes */
#include <kernel/pd.h>
#include <kernel/vm.h>
#include <platform_pd.h>
#include <trustzone.h>
#include <timer.h>
@ -51,18 +50,9 @@ Genode::Native_utcb * _main_thread_utcb;
namespace Kernel
{
/**
* Return interrupt-controller singleton
*/
Pic * pic() { return unmanaged_singleton<Pic>(); }
/* import Genode types */
typedef Genode::umword_t umword_t;
typedef Genode::Core_thread_id Core_thread_id;
}
namespace Kernel
{
Pd_ids * pd_ids() { return unmanaged_singleton<Pd_ids>(); }
Thread_ids * thread_ids() { return unmanaged_singleton<Thread_ids>(); }
Signal_context_ids * signal_context_ids() { return unmanaged_singleton<Signal_context_ids>(); }
@ -166,11 +156,8 @@ namespace Kernel
if (irq == Pic::IPI) return true;
return false;
}
}
namespace Kernel
{
/**
* Get attributes of the mode transition region in every PD
*/
@ -183,7 +170,6 @@ namespace Kernel
size_t thread_size() { return sizeof(Thread); }
size_t signal_context_size() { return sizeof(Signal_context); }
size_t signal_receiver_size() { return sizeof(Signal_receiver); }
size_t vm_size() { return sizeof(Vm); }
unsigned pd_alignm_log2() { return Genode::Translation_table::ALIGNM_LOG2; }
size_t pd_size() { return sizeof(Genode::Translation_table) + sizeof(Pd); }
@ -203,6 +189,9 @@ namespace Kernel
}
Pic * Kernel::pic() { return unmanaged_singleton<Pic>(); }
/**
* Enable kernel-entry assembly to get an exclusive stack for every CPU
*/

View File

@ -19,7 +19,6 @@
/* core includes */
#include <kernel/kernel.h>
#include <kernel/thread.h>
#include <kernel/vm.h>
#include <kernel/irq.h>
#include <platform_pd.h>
#include <pic.h>
@ -198,7 +197,7 @@ void Thread::_receive_yielded_cpu()
}
void Thread::proceed(unsigned const cpu) { mtc()->continue_user(this, cpu); }
void Thread::proceed(unsigned const cpu) { mtc()->switch_to_user(this, cpu); }
char const * Kernel::Thread::pd_label() const
@ -524,6 +523,7 @@ void Thread::_call_update_data_region()
auto base = (addr_t)user_arg_1();
auto const size = (size_t)user_arg_2();
Cpu::flush_data_caches_by_virt_region(base, size);
Cpu::invalidate_instr_caches();
}
@ -781,32 +781,6 @@ void Thread::_call_bin_signal_receiver()
}
void Thread::_call_run_vm()
{
/* lookup virtual machine */
Vm * const vm = Vm::pool()->object(user_arg_1());
if (!vm) {
PWRN("failed to lookup virtual machine");
return;
}
/* run virtual machine */
vm->run();
}
void Thread::_call_pause_vm()
{
/* lookup virtual machine */
Vm * const vm = Vm::pool()->object(user_arg_1());
if (!vm) {
PWRN("failed to lookup virtual machine");
return;
}
/* pause virtual machine */
vm->pause();
}
int Thread::_read_reg(addr_t const id, addr_t & value) const
{
addr_t Thread::* const reg = _reg(id);
@ -874,6 +848,7 @@ void Thread::_call()
case call_id_bin_signal_context(): _call_bin_signal_context(); return;
case call_id_bin_signal_receiver(): _call_bin_signal_receiver(); return;
case call_id_new_vm(): _call_new_vm(); return;
case call_id_bin_vm(): _call_bin_vm(); return;
case call_id_run_vm(): _call_run_vm(); return;
case call_id_pause_vm(): _call_pause_vm(); return;
case call_id_pause_thread(): _call_pause_thread(); return;

View File

@ -1,21 +0,0 @@
/*
* \brief Kernel backend for virtual machines
* \author Martin Stein
* \date 2013-09-15
*/
/*
* Copyright (C) 2013 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
/* core includes */
#include <kernel/vm.h>
namespace Kernel
{
Vm_ids * vm_ids() { return unmanaged_singleton<Vm_ids>(); }
Vm_pool * vm_pool() { return unmanaged_singleton<Vm_pool>(); }
}

View File

@ -0,0 +1,20 @@
/*
* \brief Kernel backend for VMs when having no virtualization
* \author Martin Stein
* \date 2013-09-15
*/
/*
* Copyright (C) 2013 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
/* core includes */
#include <kernel/thread.h>
void Kernel::Thread::_call_new_vm() { user_arg_0(0); }
void Kernel::Thread::_call_bin_vm() { user_arg_0(-1); }
void Kernel::Thread::_call_run_vm() { user_arg_0(-1); }
void Kernel::Thread::_call_pause_vm() { user_arg_0(-1); }

View File

@ -20,47 +20,3 @@ unsigned Cpu::primary_id() { return 0; }
unsigned Cpu::executing_id() { return primary_id(); }
addr_t Cpu::Context::translation_table() const {
return Ttbr0::Ba::masked(ttbr0); }
void Cpu::Context::translation_table(addr_t const t) {
ttbr0 = Arm::Ttbr0::init(t); }
bool Cpu::User_context::in_fault(addr_t & va, addr_t & w) const
{
switch (cpu_exception) {
case PREFETCH_ABORT:
{
/* check if fault was caused by a translation miss */
Ifsr::access_t const fs = Ifsr::Fs::get(Ifsr::read());
if (fs != Ifsr::section && fs != Ifsr::page)
return false;
/* fetch fault data */
w = 0;
va = ip;
return true;
}
case DATA_ABORT:
{
/* check if fault was caused by translation miss */
Dfsr::access_t const fs = Dfsr::Fs::get(Dfsr::read());
if (fs != Dfsr::section && fs != Dfsr::page)
return false;
/* fetch fault data */
Dfsr::access_t const dfsr = Dfsr::read();
w = Dfsr::Wnr::get(dfsr);
va = Dfar::read();
return true;
}
default:
return false;
};
}

View File

@ -19,13 +19,6 @@
using namespace Kernel;
void Cpu_context::_init(size_t const stack_size, addr_t const table)
{
r12 = stack_size;
cpu_exception = Genode::Cpu::Ttbr0::init(table);
}
Cpu_idle::Cpu_idle(Cpu * const cpu) : Cpu_job(Cpu_priority::min, 0)
{
Cpu_job::cpu(cpu);

View File

@ -0,0 +1,21 @@
/*
* \brief Kernel cpu context specific implementation
* \author Stefan Kalkowski
* \date 2015-02-11
*/
/*
* Copyright (C) 2015 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
/* core includes */
#include <kernel/cpu.h>
void Kernel::Cpu_context::_init(size_t const stack_size, addr_t const table)
{
r12 = stack_size;
cpu_exception = Genode::Cpu::Ttbr0::init(table);
}

View File

@ -15,7 +15,6 @@
/* core includes */
#include <kernel/thread.h>
#include <kernel/pd.h>
#include <kernel/vm.h>
#include <kernel/kernel.h>
using namespace Kernel;
@ -29,26 +28,6 @@ Thread::Thread(unsigned const priority, unsigned const quota,
{ cpu_exception = RESET; }
void Thread::_call_new_vm()
{
/* lookup signal context */
auto const context = Signal_context::pool()->object(user_arg_3());
if (!context) {
PWRN("failed to lookup signal context");
user_arg_0(0);
return;
}
/* create virtual machine */
typedef Genode::Cpu_state_modes Cpu_state_modes;
auto const allocator = reinterpret_cast<void *>(user_arg_1());
auto const state = reinterpret_cast<Cpu_state_modes *>(user_arg_2());
Vm * const vm = new (allocator) Vm(state, context);
/* return kernel name of virtual machine */
user_arg_0(vm->id());
}
void Thread::exception(unsigned const cpu)
{
switch (cpu_exception) {

View File

@ -1,33 +0,0 @@
/*
* \brief Kernel backend for virtual machines
* \author Martin Stein
* \date 2013-10-30
*/
/*
* Copyright (C) 2013 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
/* core includes */
#include <kernel/vm.h>
using namespace Kernel;
void Vm::exception(unsigned const cpu)
{
switch(_state->cpu_exception) {
case Genode::Cpu_state::INTERRUPT_REQUEST:
case Genode::Cpu_state::FAST_INTERRUPT_REQUEST:
_interrupt(cpu);
return;
case Genode::Cpu_state::DATA_ABORT:
_state->dfar = Cpu::Dfar::read();
default:
Cpu_job::_deactivate_own_share();
_context->submit(1);
}
}

View File

@ -0,0 +1,38 @@
/*
* \brief Kernel backend for virtual machines
* \author Stefan Kalkowski
* \date 2015-02-10
*/
/*
* Copyright (C) 2015 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
/* core includes */
#include <kernel/thread.h>
#include <kernel/vm.h>
void Kernel::Thread::_call_bin_vm()
{
Vm * const vm = Vm::pool()->object(user_arg_1());
if (vm) vm->~Vm();
user_arg_0(vm ? 0 : -1);
}
void Kernel::Thread::_call_run_vm() {
Vm * const vm = Vm::pool()->object(user_arg_1());
if (vm) vm->run();
user_arg_0(vm ? 0 : -1);
}
void Kernel::Thread::_call_pause_vm()
{
Vm * const vm = Vm::pool()->object(user_arg_1());
if (vm) vm->pause();
user_arg_0(vm ? 0 : -1);
}

View File

@ -15,19 +15,6 @@
/* core includes */
.include "macros.s"
/***************
** Constants **
***************/
/* hardware names of CPU modes */
.set USR_MODE, 16
.set FIQ_MODE, 17
.set IRQ_MODE, 18
.set SVC_MODE, 19
.set ABT_MODE, 23
.set UND_MODE, 27
/* size of local variables */
.set BUFFER_SIZE, 3 * 4
@ -36,30 +23,6 @@
** Macros **
************/
/**
* Determine the base of the client context of the executing CPU
*
* \param target_reg register that shall receive the base pointer
* \param buf_reg register that can be polluted by the macro
*/
.macro _get_client_context_ptr target_reg, buf_reg
/* get kernel name of CPU */
_get_cpu_id \buf_reg
/* multiply CPU name with pointer size to get offset of pointer */
mov \target_reg, #CONTEXT_PTR_SIZE
mul \buf_reg, \buf_reg, \target_reg
/* get base of the pointer array */
adr \target_reg, _mt_client_context_ptr
/* add offset and base to get CPU-local pointer */
add \target_reg, \target_reg, \buf_reg
ldr \target_reg, [\target_reg]
.endm
/**
* Determine the base of the globally mapped buffer of the executing CPU
*
@ -131,7 +94,7 @@
_switch_protection_domain r1, r2, sp
/* get user context-pointer */
_get_client_context_ptr sp, r1
_get_client_context_ptr sp, r1, _mt_client_context_ptr
/* adjust and save user pc */
.if \pc_adjust != 0
@ -157,95 +120,6 @@
.endm /* _user_to_kernel_pic */
/**
* Save sp, lr and spsr register banks of specified exception mode
*/
.macro _save_bank mode
cps #\mode /* switch to given mode */
mrs r1, spsr /* store mode-specific spsr */
stmia r0!, {r1,sp,lr} /* store mode-specific sp and lr */
.endm /* _save_bank mode */
/**
* Switch from an interrupted VM to the kernel context
*
* \param exception_type immediate exception type ID
* \param pc_adjust immediate value that gets subtracted from the
* vm's PC before it gets saved
*/
.macro _vm_to_kernel exception_type, pc_adjust
ldr sp, _mt_client_context_ptr /* load context pointer */
stmia sp, {r0-lr}^ /* save user regs r0-r12,sp,lr */
add r0, sp, #15*4
.if \pc_adjust != 0 /* adjust pc if necessary */
sub lr, lr, #\pc_adjust
.endif
stmia r0!, {lr} /* save pc */
mrs r1, spsr /* spsr to r0 */
mov r2, #\exception_type /* exception reason to r1 */
stmia r0!, {r1-r2} /* save spsr, and exception reason */
mrc p15, 0, r3, c6, c0, 0 /* move DFAR to r3 */
mrc p15, 0, r4, c2, c0, 0 /* move TTBR0 to r4 */
mrc p15, 0, r5, c2, c0, 1 /* move TTBR1 to r5 */
mrc p15, 0, r6, c2, c0, 2 /* move TTBRC to r6 */
mov r1, #0
mcr p15, 0, r1, c1, c1, 0 /* disable non-secure bit */
_save_bank 27 /* save undefined banks */
_save_bank 19 /* save supervisor banks */
_save_bank 23 /* save abort banks */
_save_bank 18 /* save irq banks */
_save_bank 17 /* save fiq banks */
stmia r0!, {r8-r12} /* save fiq r8-r12 */
stmia r0!, {r3-r6} /* save MMU registers */
b _common_client_to_kernel_pic
.endm /* _vm_to_kernel */
/**
* Restore sp, lr and spsr register banks of specified exception mode
*/
.macro _restore_bank mode
cps #\mode /* switch to given mode */
ldmia r0!, {r1,sp,lr} /* load mode-specific sp, lr, and spsr into r1 */
msr spsr_cxfs, r1 /* load mode-specific spsr */
.endm
/**
* Switch from kernel context to a VM
*/
.macro _kernel_to_vm
ldr r0, _mt_client_context_ptr /* get vm context pointer */
add r0, r0, #18*4 /* add offset of banked modes */
_restore_bank 27 /* load undefined banks */
_restore_bank 19 /* load supervisor banks */
_restore_bank 23 /* load abort banks */
_restore_bank 18 /* load irq banks */
_restore_bank 17 /* load fiq banks */
ldmia r0!, {r8 - r12} /* load fiq r8-r12 */
cps #22 /* switch to monitor mode */
ldr sp, _mt_client_context_ptr /* get vm context pointer */
ldmia sp, {r0-lr}^ /* load user r0-r12,sp,lr */
ldr lr, [sp, #16*4] /* load vm's cpsr to lr */
msr spsr_cxfs, lr /* save cpsr to be load when switching */
mov lr, #13
mcr p15, 0, lr, c1, c1, 0 /* enable EA, FIQ, and NS bit in SCTRL */
ldr lr, [sp, #15*4] /* load vm's ip */
subs pc, lr, #0
.endm /* _kernel_to_vm */
/**
* Enter kernel after hypervisor call
*/
.macro _hyp_to_kernel exception_type
cps #SVC_MODE
mov r0, #\exception_type
1: b 1b
.endm /* _hyp_to_kernel */
/**********************************
** Linked into the text section **
**********************************/
@ -348,12 +222,6 @@
*/
clrex
/*********************************************************
** Kernel-entry code that is common for all exceptions **
*********************************************************/
_common_client_to_kernel_pic:
/*
* Switch to supervisor mode to circumvent incorrect behavior of
* kernel high-level code in fast interrupt mode and to ensure that
@ -382,7 +250,7 @@
_mt_user_entry_pic:
/* get user context and globally mapped buffer of this CPU */
_get_client_context_ptr lr, r0
_get_client_context_ptr lr, r0, _mt_client_context_ptr
_get_buffer_ptr sp, r0
/* load user psr in spsr */
@ -409,60 +277,6 @@
/* apply user r0-r1 and user pc which implies application of spsr */
ldm sp, {r0, r1, pc}^
/*
* On TrustZone exceptions the CPU has to jump to one of the following
* 7 entry vectors to switch to a kernel context.
*/
.p2align 5
.global _mon_kernel_entry
_mon_kernel_entry:
b _mon_rst_entry /* reset */
b _mon_und_entry /* undefined instruction */
b _mon_svc_entry /* supervisor call */
b _mon_pab_entry /* prefetch abort */
b _mon_dab_entry /* data abort */
nop /* reserved */
b _mon_irq_entry /* interrupt request */
_vm_to_kernel FIQ_TYPE, 4 /* fast interrupt request */
/* PICs that switch from a vm exception to the kernel */
_mon_rst_entry: _vm_to_kernel RST_TYPE, 0
_mon_und_entry: _vm_to_kernel UND_TYPE, 4
_mon_svc_entry: _vm_to_kernel SVC_TYPE, 0
_mon_pab_entry: _vm_to_kernel PAB_TYPE, 4
_mon_dab_entry: _vm_to_kernel DAB_TYPE, 8
_mon_irq_entry: _vm_to_kernel IRQ_TYPE, 4
/* kernel must jump to this point to switch to a vm */
.p2align 2
.global _mt_vm_entry_pic
_mt_vm_entry_pic:
_kernel_to_vm
/*
* On virtualization exceptions the CPU has to jump to one of the following
* 7 entry vectors to switch to a kernel context.
*/
.p2align 4
.global _hyp_kernel_entry
_hyp_kernel_entry:
b _hyp_rst_entry
b _hyp_und_entry /* undefined instruction */
b _hyp_svc_entry /* hypervisor call */
b _hyp_pab_entry /* prefetch abort */
b _hyp_dab_entry /* data abort */
b _hyp_trp_entry /* hypervisor trap */
b _hyp_irq_entry /* interrupt request */
_hyp_to_kernel 7 /* fast interrupt request */
_hyp_rst_entry: _hyp_to_kernel 0
_hyp_und_entry: _hyp_to_kernel 1
_hyp_svc_entry: _hyp_to_kernel 2
_hyp_pab_entry: _hyp_to_kernel 3
_hyp_dab_entry: _hyp_to_kernel 4
_hyp_trp_entry: _hyp_to_kernel 5
_hyp_irq_entry: _hyp_to_kernel 6
/* end of the mode transition code */
.global _mt_end
_mt_end:

View File

@ -0,0 +1,67 @@
/*
* \brief Kernel backend for virtual machines
* \author Martin Stein
* \author Stefan Kalkowski
* \date 2013-10-30
*/
/*
* Copyright (C) 2013 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
/* core includes */
#include <kernel/vm.h>
extern void * _mt_nonsecure_entry_pic;
extern Genode::addr_t _tz_client_context;
extern Genode::addr_t _mt_master_context_begin;
extern Genode::addr_t _tz_master_context;
namespace Kernel
{
Vm_ids * vm_ids() { return unmanaged_singleton<Vm_ids>(); }
Vm_pool * vm_pool() { return unmanaged_singleton<Vm_pool>(); }
}
using namespace Kernel;
Kernel::Vm::Vm(void * const state,
Kernel::Signal_context * const context,
void * const table)
: Cpu_job(Cpu_priority::min, 0),
_state((Genode::Vm_state * const)state),
_context(context), _table(0)
{
affinity(cpu_pool()->primary_cpu());
Genode::memcpy(&_tz_master_context, &_mt_master_context_begin,
sizeof(Cpu_context));
}
void Vm::exception(unsigned const cpu)
{
switch(_state->cpu_exception) {
case Genode::Cpu_state::INTERRUPT_REQUEST:
case Genode::Cpu_state::FAST_INTERRUPT_REQUEST:
_interrupt(cpu);
return;
case Genode::Cpu_state::DATA_ABORT:
_state->dfar = Cpu::Dfar::read();
default:
pause();
_context->submit(1);
}
}
void Vm::proceed(unsigned const cpu)
{
mtc()->switch_to(reinterpret_cast<Cpu::Context*>(_state), cpu,
(addr_t)&_mt_nonsecure_entry_pic,
(addr_t)&_tz_client_context);
}

View File

@ -0,0 +1,38 @@
/*
* \brief Kernel backend for thread-syscalls related to VMs
* \author Stefan Kalkowski
* \date 2015-02-23
*/
/*
* Copyright (C) 2015 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
/* core includes */
#include <kernel/vm.h>
#include <kernel/thread.h>
void Kernel::Thread::_call_new_vm()
{
/* lookup signal context */
auto const context = Signal_context::pool()->object(user_arg_4());
if (!context) {
PWRN("failed to lookup signal context");
user_arg_0(0);
return;
}
/* create virtual machine */
typedef Genode::Cpu_state_modes Cpu_state_modes;
void * const allocator = reinterpret_cast<void *>(user_arg_1());
void * const table = reinterpret_cast<void *>(user_arg_3());
Cpu_state_modes * const state =
reinterpret_cast<Cpu_state_modes *>(user_arg_2());
Vm * const vm = new (allocator) Vm(state, context, table);
/* return kernel name of virtual machine */
user_arg_0(vm->id());
}

View File

@ -0,0 +1,125 @@
/*
* \brief Transition between secure/normal worl
* \author Stefan Kalkowski
* \date 2015-02-16
*/
/*
* Copyright (C) 2015 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
/* core includes */
.include "macros.s"
/**
* Switch from nonsecure into secure world
*
* \param exception_type immediate exception type ID
* \param pc_adjust immediate value that gets subtracted from the
* vm's PC before it gets saved
*/
.macro _nonsecure_to_secure exception_type, pc_adjust
ldr sp, _tz_client_context /* load context pointer */
stmia sp, {r0-lr}^ /* save user regs r0-r12,sp,lr */
add r0, sp, #15*4
.if \pc_adjust != 0 /* adjust pc if necessary */
sub lr, lr, #\pc_adjust
.endif
stmia r0!, {lr} /* save pc */
mrs r1, spsr /* spsr to r0 */
mov r2, #\exception_type /* exception reason to r1 */
b _nonsecure_kernel_entry
.endm /* _non_to_secure */
/**
* Switch from secure into nonsecure world
*/
.macro _secure_to_nonsecure
ldr r0, _tz_client_context /* get vm context pointer */
add r0, r0, #18*4 /* add offset of banked modes */
_restore_bank 27 /* load undefined banks */
_restore_bank 19 /* load supervisor banks */
_restore_bank 23 /* load abort banks */
_restore_bank 18 /* load irq banks */
_restore_bank 17 /* load fiq banks */
ldmia r0!, {r8 - r12} /* load fiq r8-r12 */
cps #22 /* switch to monitor mode */
ldr sp, _tz_client_context /* get vm context pointer */
ldmia sp, {r0-lr}^ /* load user r0-r12,sp,lr */
ldr lr, [sp, #16*4] /* load vm's cpsr to lr */
msr spsr_cxfs, lr /* save cpsr to be load when switching */
mov lr, #13
mcr p15, 0, lr, c1, c1, 0 /* enable EA, FIQ, and NS bit in SCTRL */
ldr lr, [sp, #15*4] /* load vm's ip */
subs pc, lr, #0
.endm /* _secure_to_nonsecure */
.section .text
/* space for a copy of the kernel context */
.p2align 2
.global _tz_master_context
_tz_master_context:
.space 32 * 4
/* space for a client context-pointer */
.p2align 2
.global _tz_client_context
_tz_client_context:
.space CONTEXT_PTR_SIZE
_nonsecure_kernel_entry:
stmia r0!, {r1-r2} /* save spsr, and exception reason */
mrc p15, 0, r3, c6, c0, 0 /* move DFAR to r3 */
mrc p15, 0, r4, c2, c0, 0 /* move TTBR0 to r4 */
mrc p15, 0, r5, c2, c0, 1 /* move TTBR1 to r5 */
mrc p15, 0, r6, c2, c0, 2 /* move TTBRC to r6 */
mov r1, #0
mcr p15, 0, r1, c1, c1, 0 /* disable non-secure bit */
_save_bank 27 /* save undefined banks */
_save_bank 19 /* save supervisor banks */
_save_bank 23 /* save abort banks */
_save_bank 18 /* save irq banks */
_save_bank 17 /* save fiq banks */
stmia r0!, {r8-r12} /* save fiq r8-r12 */
stmia r0!, {r3-r6} /* save MMU registers */
cps #SVC_MODE
adr r0, _tz_master_context
_restore_kernel_sp r0, r1, r2 /* apply kernel sp */
add r1, r0, #LR_OFFSET
ldm r1, {lr, pc}
/* kernel must jump to this point to switch to a vm */
.global _mt_nonsecure_entry_pic
_mt_nonsecure_entry_pic:
_secure_to_nonsecure
/*
* On TrustZone exceptions the CPU has to jump to one of the following
* 7 entry vectors to switch to a kernel context.
*/
.p2align 5
.global _mon_kernel_entry
_mon_kernel_entry:
b _mon_rst_entry /* reset */
b _mon_und_entry /* undefined instruction */
b _mon_svc_entry /* supervisor call */
b _mon_pab_entry /* prefetch abort */
b _mon_dab_entry /* data abort */
nop /* reserved */
b _mon_irq_entry /* interrupt request */
_nonsecure_to_secure FIQ_TYPE, 4 /* fast interrupt request */
/* PICs that switch from a vm exception to the kernel */
_mon_rst_entry: _nonsecure_to_secure RST_TYPE, 0
_mon_und_entry: _nonsecure_to_secure UND_TYPE, 4
_mon_svc_entry: _nonsecure_to_secure SVC_TYPE, 0
_mon_pab_entry: _nonsecure_to_secure PAB_TYPE, 4
_mon_dab_entry: _nonsecure_to_secure DAB_TYPE, 8
_mon_irq_entry: _nonsecure_to_secure IRQ_TYPE, 4

View File

@ -0,0 +1,38 @@
/*
* \brief VM session component for 'base-hw'
* \author Stefan Kalkowski
* \date 2012-10-08
*/
/*
* Copyright (C) 2012-2013 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#include <kernel/core_interface.h>
#include <vm_session_component.h>
#include <core_env.h>
using namespace Genode;
void Vm_session_component::exception_handler(Signal_context_capability handler)
{
if (_vm_id) {
PWRN("Cannot register exception_handler repeatedly");
return;
}
_vm_id = Kernel::new_vm(&_vm, (void*)_ds.core_local_addr(), handler.dst(), 0);
}
Vm_session_component::Vm_session_component(Rpc_entrypoint *ds_ep,
size_t ram_quota)
: _ds_ep(ds_ep), _vm_id(0),
_ds(_ds_size(), _alloc_ds(ram_quota), UNCACHED, true, 0),
_ds_cap(static_cap_cast<Dataspace>(_ds_ep->manage(&_ds)))
{
_ds.assign_core_local_addr(core_env()->rm_session()->attach(_ds_cap));
}

View File

@ -0,0 +1,24 @@
/*
* \brief Kernel cpu context specific implementation
* \author Stefan Kalkowski
* \date 2015-02-11
*/
/*
* Copyright (C) 2015 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
/* core includes */
#include <kernel/cpu.h>
void Kernel::Cpu_context::_init(size_t const stack_size, addr_t const table)
{
r12 = stack_size;
cpu_exception = Genode::Cpu::Ttbr0::init(table);
sctlr = Cpu::Sctlr::init_virt_kernel();
ttbrc = Cpu::Ttbcr::init_virt_kernel();
mair0 = Cpu::Mair0::init_virt_kernel();
}

View File

@ -0,0 +1,267 @@
/*
* \brief Kernel backend for virtual machines
* \author Stefan Kalkowski
* \date 2015-02-10
*/
/*
* Copyright (C) 2015 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#include <platform_pd.h>
#include <kernel/vm.h>
namespace Kernel
{
Vm_ids * vm_ids() { return unmanaged_singleton<Vm_ids>(); }
Vm_pool * vm_pool() { return unmanaged_singleton<Vm_pool>(); }
/**
* ARM's virtual interrupt controller cpu interface
*/
struct Virtual_pic;
/**
* ARM's virtual timer counter
*/
struct Virtual_timer;
/**
* Kernel private virtualization interrupts, delivered to VM/VMMs
*/
struct Vm_irq;
/**
* Cpu-specific initialization for virtualization support
*/
void prepare_hypervisor(void);
}
using namespace Kernel;
extern void * _vt_vm_entry;
extern void * _vt_host_entry;
extern Genode::addr_t _vt_vm_context_ptr;
extern Genode::addr_t _vt_host_context_ptr;
struct Kernel::Vm_irq : Kernel::Irq
{
Vm_irq(unsigned const irq) : Kernel::Irq(irq) {}
/**
* A VM interrupt gets injected into the VM scheduled on the current CPU
*/
void occurred()
{
Cpu_job * job = cpu_pool()->executing_cpu()->scheduled_job();
Vm *vm = dynamic_cast<Vm*>(job);
if (!vm)
PERR("VM timer interrupt while VM is not runnning!");
else
vm->inject_irq(_id());
}
};
struct Kernel::Virtual_pic : Genode::Mmio
{
struct Gich_hcr : Register<0x00, 32> { };
struct Gich_vmcr : Register<0x08, 32> { };
struct Gich_misr : Register<0x10, 32> { };
struct Gich_eisr0 : Register<0x20, 32> { };
struct Gich_elrsr0 : Register<0x30, 32> { };
struct Gich_apr : Register<0xf0, 32> { };
template <unsigned SLOT>
struct Gich_lr : Register<0x100 + SLOT*4, 32> { };
Vm_irq irq = Genode::Board::VT_MAINTAINANCE_IRQ;
Virtual_pic()
: Genode::Mmio(Genode::Board::IRQ_CONTROLLER_VT_CTRL_BASE) { }
static Virtual_pic& pic()
{
static Virtual_pic vgic;
return vgic;
}
/**
* Save the virtual interrupt controller state to VM state
*/
static void save (Genode::Vm_state *s)
{
s->gic_hcr = pic().read<Gich_hcr >();
s->gic_misr = pic().read<Gich_misr >();
s->gic_vmcr = pic().read<Gich_vmcr >();
s->gic_apr = pic().read<Gich_apr >();
s->gic_eisr = pic().read<Gich_eisr0 >();
s->gic_elrsr0 = pic().read<Gich_elrsr0>();
s->gic_lr[0] = pic().read<Gich_lr<0> >();
s->gic_lr[1] = pic().read<Gich_lr<1> >();
s->gic_lr[2] = pic().read<Gich_lr<2> >();
s->gic_lr[3] = pic().read<Gich_lr<3> >();
/* disable virtual PIC CPU interface */
pic().write<Gich_hcr>(0);
}
/**
* Load the virtual interrupt controller state from VM state
*/
static void load (Genode::Vm_state *s)
{
pic().write<Gich_hcr >(s->gic_hcr );
pic().write<Gich_misr >(s->gic_misr);
pic().write<Gich_vmcr >(s->gic_vmcr);
pic().write<Gich_apr >(s->gic_apr );
pic().write<Gich_elrsr0>(s->gic_elrsr0);
pic().write<Gich_lr<0> >(s->gic_lr[0]);
pic().write<Gich_lr<1> >(s->gic_lr[1]);
pic().write<Gich_lr<2> >(s->gic_lr[2]);
pic().write<Gich_lr<3> >(s->gic_lr[3]);
}
};
struct Kernel::Virtual_timer
{
Vm_irq irq = Genode::Board::VT_TIMER_IRQ;
/**
* Return virtual timer object of currently executing cpu
*
* FIXME: remove this when re-designing the CPU (issue #1252)
*/
static Virtual_timer& timer()
{
static Virtual_timer timer[NR_OF_CPUS];
return timer[Cpu::executing_id()];
}
/**
* Resets the virtual timer, thereby it disables its interrupt
*/
static void reset()
{
timer().irq.disable();
asm volatile("mcr p15, 0, %0, c14, c3, 1 \n"
"mcr p15, 0, %0, c14, c3, 0" :: "r" (0));
}
/**
* Save the virtual timer state to VM state
*/
static void save(Genode::Vm_state *s)
{
asm volatile("mrc p15, 0, %0, c14, c3, 0 \n"
"mrc p15, 0, %1, c14, c3, 1" :
"=r" (s->timer_val), "=r" (s->timer_ctrl));
}
/**
* Load the virtual timer state from VM state
*/
static void load(Genode::Vm_state *s, unsigned const cpu_id)
{
if (s->timer_irq) timer().irq.enable();
asm volatile("mcr p15, 0, %0, c14, c3, 1 \n"
"mcr p15, 0, %1, c14, c3, 0 \n"
"mcr p15, 0, %2, c14, c3, 1" ::
"r" (0),
"r" (s->timer_val), "r" (s->timer_ctrl));
}
};
void Kernel::prepare_hypervisor()
{
Cpu * cpu = cpu_pool()->executing_cpu();
cpu->insert(&Virtual_timer::timer().irq);
cpu->insert(&Virtual_pic::pic().irq);
/* set hypervisor exception vector */
Cpu::hyp_exception_entry_at(&_vt_host_entry);
/* set hypervisor's translation table */
Genode::Translation_table * table =
core_pd()->platform_pd()->translation_table_phys();
Cpu::Httbr::translation_table((addr_t)table);
/* prepare MMU usage by hypervisor code */
Cpu::Htcr::write(Cpu::Ttbcr::init_virt_kernel());
Cpu::Hcptr::write(Cpu::Hcptr::init());
Cpu::Hmair0::write(Cpu::Mair0::init_virt_kernel());
Cpu::Vtcr::write(Cpu::Vtcr::init());
Cpu::Hsctlr::write(Cpu::Sctlr::init_virt_kernel());
/* initialize host context used in virtualization world switch */
*((void**)&_vt_host_context_ptr) = &_mt_master_context_begin;
}
Kernel::Vm::Vm(void * const state,
Kernel::Signal_context * const context,
void * const table)
: Cpu_job(Cpu_priority::min, 0),
_state((Genode::Vm_state * const)state),
_context(context),
_table(table) {
affinity(cpu_pool()->primary_cpu());
Virtual_pic::pic().irq.enable();
}
void Kernel::Vm::exception(unsigned const cpu_id)
{
Virtual_timer::save(_state);
switch(_state->cpu_exception) {
case Genode::Cpu_state::INTERRUPT_REQUEST:
case Genode::Cpu_state::FAST_INTERRUPT_REQUEST:
_interrupt(cpu_id);
break;
default:
pause();
_context->submit(1);
}
Virtual_pic::save(_state);
Virtual_timer::reset();
}
void Kernel::Vm::proceed(unsigned const cpu_id)
{
/*
* the following values have to be enforced by the hypervisor
*/
_state->vttbr = Cpu::Ttbr0::init((Genode::addr_t)_table, id());
/*
* use the following report fields not needed for loading the context
* to transport the HSTR and HCR register descriptions into the assembler
* path in a dense way
*/
_state->hsr = Cpu::Hstr::init();
_state->hpfar = Cpu::Hcr::init();
Virtual_pic::load(_state);
Virtual_timer::load(_state, cpu_id);
mtc()->switch_to(reinterpret_cast<Cpu::Context*>(_state), cpu_id,
(addr_t) &_vt_vm_entry, (addr_t)&_vt_vm_context_ptr);
}
void Vm::inject_irq(unsigned irq)
{
_state->gic_irq = irq;
pause();
_context->submit(1);
}

View File

@ -0,0 +1,38 @@
/*
* \brief Kernel backend for thread-syscalls related to virtual machines
* \author Stefan Kalkowski
* \date 2015-02-10
*/
/*
* Copyright (C) 2015 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#include <kernel/vm.h>
#include <kernel/thread.h>
void Kernel::Thread::_call_new_vm()
{
/* lookup signal context */
auto const context = Signal_context::pool()->object(user_arg_4());
if (!context) {
PWRN("failed to lookup signal context");
user_arg_0(0);
return;
}
/* create virtual machine */
typedef Genode::Cpu_state_modes Cpu_state_modes;
void * const allocator = reinterpret_cast<void *>(user_arg_1());
void * const table = reinterpret_cast<void *>(user_arg_3());
Cpu_state_modes * const state =
reinterpret_cast<Cpu_state_modes *>(user_arg_2());
Vm * const vm = new (allocator) Vm(state, context, table);
/* return kernel name of virtual machine */
user_arg_0(vm->id());
}

View File

@ -0,0 +1,175 @@
/*
* \brief Transition between virtual/host mode
* \author Stefan Kalkowski
* \date 2015-02-16
*/
/*
* Copyright (C) 2015 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
/* core includes */
.include "macros.s"
.macro _vm_exit exception_type
str r0, [sp]
mrc p15, 4, r0, c1, c1, 0 /* read HCR register */
tst r0, #1 /* check VM bit */
ldreq r0, [sp]
beq _host_to_vm
mov r0, #\exception_type
str r0, [sp, #17*4]
b _vm_to_host
.endm /* _vm_exit */
.section .text
/* space for a copy of the host context */
.p2align 2
.global _vt_host_context_ptr
_vt_host_context_ptr:
.space CONTEXT_PTR_SIZE
/* space for a vm context-pointer per CPU */
.p2align 2
.global _vt_vm_context_ptr
_vt_vm_context_ptr:
.rept NR_OF_CPUS
.space CONTEXT_PTR_SIZE
.endr
_host_to_vm:
msr elr_hyp, r2
msr spsr_cxfs, r3 /* load cpsr */
mcrr p15, 6, r5, r6, c2 /* write VTTBR */
mcr p15, 0, r7, c1, c0, 0 /* write SCTRL */
mcr p15, 4, r8, c1, c1, 3 /* write HSTR */
mcr p15, 4, r9, c1, c1, 0 /* write HCR register */
mcr p15, 0, r12, c2, c0, 2 /* write TTBRC */
sub sp, r0, #46*4
ldm r0!, {r1-r12}
mcr p15, 0, r1, c2, c0, 0 /* write TTBR0 */
mcr p15, 0, r2, c2, c0, 1 /* write TTBR1 */
mcr p15, 0, r3, c10, c2, 0 /* write PRRR */
mcr p15, 0, r4, c10, c2, 1 /* write NMRR */
mcr p15, 0, r5, c3, c0, 0 /* write DACR */
mcr p15, 0, r6, c5, c0, 0 /* write DFSR */
mcr p15, 0, r7, c5, c0, 1 /* write IFSR */
mcr p15, 0, r8, c5, c1, 0 /* write ADFSR */
mcr p15, 0, r9, c5, c1, 1 /* write AIFSR */
mcr p15, 0, r10, c6, c0, 0 /* write DFAR */
mcr p15, 0, r11, c6, c0, 2 /* write IFAR */
mcr p15, 0, r12, c13, c0, 1 /* write CIDR */
ldm r0, {r1-r4}
mcr p15, 0, r1, c13, c0, 2 /* write TLS1 */
mcr p15, 0, r2, c13, c0, 3 /* write TLS2 */
mcr p15, 0, r3, c13, c0, 4 /* write TLS3 */
mcr p15, 0, r4, c1, c0, 2 /* write CPACR */
ldmia sp, {r0-r12} /* load vm's r0-r12 */
eret
_vm_to_host:
add r0, sp, #1*4
stmia r0, {r1-r12} /* save regs r1-r12 */
mov r1, #0
mcrr p15, 6, r1, r1, c2 /* write VTTBR */
mcr p15, 4, r1, c1, c1, 0 /* write HCR register */
mcr p15, 4, r1, c1, c1, 3 /* write HSTR register */
mcr p15, 0, r1, c1, c0, 2 /* write CPACR */
mrs r1, ELR_hyp /* read ip */
mrs r2, spsr /* read cpsr */
mrc p15, 0, r3, c1, c0, 0 /* read SCTRL */
mrc p15, 4, r4, c5, c2, 0 /* read HSR */
mrc p15, 4, r5, c6, c0, 4 /* read HPFAR */
mrc p15, 4, r6, c6, c0, 0 /* read HDFAR */
mrc p15, 4, r7, c6, c0, 2 /* read HIFAR */
mrc p15, 0, r8, c2, c0, 2 /* read TTBRC */
mrc p15, 0, r9, c2, c0, 0 /* read TTBR0 */
mrc p15, 0, r10, c2, c0, 1 /* read TTBR1 */
add r0, sp, #40*4 /* offset SCTRL */
stm r0!, {r3-r10}
add r0, r0, #3*4
mrc p15, 0, r3, c5, c0, 0 /* read DFSR */
mrc p15, 0, r4, c5, c0, 1 /* read IFSR */
mrc p15, 0, r5, c5, c1, 0 /* read ADFSR */
mrc p15, 0, r6, c5, c1, 1 /* read AIFSR */
mrc p15, 0, r7, c6, c0, 0 /* read DFAR */
mrc p15, 0, r8, c6, c0, 2 /* read IFAR */
mrc p15, 0, r9, c13, c0, 1 /* read CIDR */
mrc p15, 0, r10, c13, c0, 2 /* read TLS1 */
mrc p15, 0, r11, c13, c0, 3 /* read TLS2 */
mrc p15, 0, r12, c13, c0, 4 /* read TLS3 */
stm r0, {r3-r12}
add r0, sp, #13*4
ldr r3, _vt_host_context_ptr
_restore_kernel_sp r3, r4, r5
add r3, r3, #CIDR_OFFSET
ldmia r3, {r4-r9}
_switch_protection_domain r0, r4, r5
mcr p15, 0, r6, c1, c0, 0 /* write SCTRL */
mcr p15, 0, r7, c2, c0, 2 /* write TTBRC */
mcr p15, 0, r8, c10, c2, 0 /* write MAIR0 */
mcr p15, 0, r9, c3, c0, 0 /* write DACR */
cps #SVC_MODE
stmia r0, {r13-r14}^ /* save user regs sp,lr */
add r0, r0, #2*4
stmia r0!, {r1-r2} /* save ip, cpsr */
add r0, r0, #1*4
_save_bank UND_MODE /* save undefined banks */
_save_bank SVC_MODE /* save supervisor banks */
_save_bank ABT_MODE /* save abort banks */
_save_bank IRQ_MODE /* save irq banks */
_save_bank FIQ_MODE /* save fiq banks */
stmia r0!, {r8-r12} /* save fiq r8-r12 */
cps #SVC_MODE
ldr r0, _vt_host_context_ptr
_restore_kernel_sp r0, r1, r2 /* apply host kernel sp */
add r1, r0, #LR_OFFSET /* apply host kernel lr */
ldm r1, {lr, pc}
/* host kernel must jump to this point to switch to a vm */
.global _vt_vm_entry
_vt_vm_entry:
_get_client_context_ptr r0, lr, _vt_vm_context_ptr
add r0, r0, #SP_OFFSET
ldm r0, {r13 - r14}^
add r0, r0, #2*4
ldmia r0!, {r2 - r4}
_restore_bank UND_MODE
_restore_bank SVC_MODE
_restore_bank ABT_MODE
_restore_bank IRQ_MODE
_restore_bank FIQ_MODE
ldmia r0!, {r8 - r12}
cps #SVC_MODE
ldm r0!, {r5 - r12}
hvc #0
/*
* On virtualization exceptions the CPU has to jump to one of the following
* 7 entry vectors to switch to a kernel context.
*/
.p2align 5
.global _vt_host_entry
_vt_host_entry:
b _vt_rst_entry
b _vt_und_entry /* undefined instruction */
b _vt_svc_entry /* hypervisor call */
b _vt_pab_entry /* prefetch abort */
b _vt_dab_entry /* data abort */
b _vt_trp_entry /* hypervisor trap */
b _vt_irq_entry /* interrupt request */
_vm_exit 7 /* fast interrupt request */
_vt_rst_entry: _vm_exit 1
_vt_und_entry: _vm_exit 2
_vt_svc_entry: _vm_exit 3
_vt_pab_entry: _vm_exit 4
_vt_dab_entry: _vm_exit 5
_vt_irq_entry: _vm_exit 6
_vt_trp_entry: _vm_exit 8

View File

@ -0,0 +1,102 @@
/*
* \brief VM session component for 'base-hw'
* \author Stefan Kalkowski
* \date 2015-02-17
*/
/*
* Copyright (C) 2015 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
/* Genode includes */
#include <util/construct_at.h>
/* core includes */
#include <kernel/core_interface.h>
#include <vm_session_component.h>
#include <platform.h>
#include <core_env.h>
using namespace Genode;
void Vm_session_component::exception_handler(Signal_context_capability handler)
{
if (_vm_id) {
PWRN("Cannot register exception_handler repeatedly");
return;
}
Core_mem_allocator * cma =
static_cast<Core_mem_allocator*>(platform()->core_mem_alloc());
_vm_id = Kernel::new_vm(&_vm, (void*)_ds.core_local_addr(), handler.dst(),
cma->phys_addr(_table));
}
void Vm_session_component::_attach(addr_t phys_addr, addr_t vm_addr, size_t size)
{
Page_flags pflags = Page_flags::apply_mapping(true, CACHED, false);
try {
for (;;)
try {
_table->insert_translation(vm_addr, phys_addr, size, pflags, _pslab);
return;
} catch(Page_slab::Out_of_slabs) {
_pslab->alloc_slab_block();
}
} catch(Allocator::Out_of_memory) {
PERR("Translation table needs to much RAM");
} catch(...) {
PERR("Invalid mapping %p -> %p (%zx)", (void*)phys_addr,
(void*)vm_addr, size);
}
}
void Vm_session_component::attach(Dataspace_capability ds_cap, addr_t vm_addr)
{
/* check dataspace validity */
Object_pool<Dataspace_component>::Guard dsc(_ds_ep->lookup_and_lock(ds_cap));
if (!dsc) throw Invalid_dataspace();
_attach(dsc->phys_addr(), vm_addr, dsc->size());
}
void Vm_session_component::attach_pic(addr_t vm_addr)
{
_attach(Board::IRQ_CONTROLLER_VT_CPU_BASE, vm_addr,
Board::IRQ_CONTROLLER_VT_CPU_SIZE);
}
void Vm_session_component::detach(addr_t vm_addr, size_t size) {
_table->remove_translation(vm_addr, size, _pslab); }
Vm_session_component::Vm_session_component(Rpc_entrypoint *ds_ep,
size_t ram_quota)
: _ds_ep(ds_ep), _vm_id(0),
_ds(_ds_size(), _alloc_ds(ram_quota), UNCACHED, true, 0),
_ds_cap(static_cap_cast<Dataspace>(_ds_ep->manage(&_ds)))
{
_ds.assign_core_local_addr(core_env()->rm_session()->attach(_ds_cap));
Core_mem_allocator * cma =
static_cast<Core_mem_allocator*>(platform()->core_mem_alloc());
void *tt;
/* get some aligned space for the translation table */
if (!cma->alloc_aligned(sizeof(Translation_table), (void**)&tt,
Translation_table::ALIGNM_LOG2).is_ok()) {
PERR("failed to allocate kernel object");
throw Root::Quota_exceeded();
}
_table = construct_at<Translation_table>(tt);
_pslab = new (cma) Page_slab(cma);
}

View File

@ -0,0 +1,57 @@
/*
* \brief VM session component for 'base-hw'
* \author Stefan Kalkowski
* \date 2012-10-08
*/
/*
* Copyright (C) 2012-2013 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#include <vm_session_component.h>
#include <platform.h>
#include <core_env.h>
using namespace Genode;
addr_t Vm_session_component::_alloc_ds(size_t &ram_quota)
{
addr_t addr;
if (_ds_size() > ram_quota ||
platform()->ram_alloc()->alloc_aligned(_ds_size(), (void**)&addr,
get_page_size_log2()).is_error())
throw Root::Quota_exceeded();
ram_quota -= _ds_size();
return addr;
}
void Vm_session_component::run(void)
{
if (!_vm_id || Kernel::run_vm(_vm_id))
PWRN("Unknown VM: is the exception handler registered?");
}
void Vm_session_component::pause(void)
{
if (!_vm_id || Kernel::pause_vm(_vm_id))
PWRN("Unknown VM: is the exception handler registered?");
}
Vm_session_component::~Vm_session_component()
{
/* dissolve VM dataspace from service entry point */
_ds_ep->dissolve(&_ds);
if (Kernel::bin_vm(_vm_id)) PERR("Cannot destruct unknown VM");
/* free region in allocator */
core_env()->rm_session()->detach(_ds.core_local_addr());
platform()->ram_alloc()->free((void*)_ds.phys_addr());
}

View File

@ -14,10 +14,17 @@
/* core includes */
#include <board.h>
#include <cpu.h>
#include <kernel/kernel.h>
#include <kernel/cpu.h>
#include <kernel/vm.h>
#include <unmanaged_singleton.h>
#include <long_translation_table.h>
/* hypervisor exception vector address */
extern void* _hyp_kernel_entry;
namespace Kernel {
void prepare_hypervisor(void);
}
static unsigned char hyp_mode_stack[1024];
static inline void prepare_nonsecure_world()
{
@ -29,6 +36,11 @@ static inline void prepare_nonsecure_world()
if (Cpsr::M::get(Cpsr::read()) == Cpsr::M::HYP)
return;
/* ARM generic timer counter freq needs to be set in secure mode */
volatile unsigned long * mct_control = (unsigned long*) 0x101C0240;
*mct_control = 0x100;
asm volatile ("mcr p15, 0, %0, c14, c0, 0" :: "r" (24000000));
/*
* enable coprocessor 10 + 11 access and SMP bit access in auxiliary control
* register for non-secure world
@ -69,15 +81,17 @@ static inline void switch_to_supervisor_mode()
"msr sp_svc, sp \n" /* copy current mode's sp */
"msr lr_svc, lr \n" /* copy current mode's lr */
"msr elr_hyp, lr \n" /* copy current mode's lr to hyp lr */
"msr sp_hyp, %[stack] \n" /* copy to hyp stack pointer */
"msr spsr_cxfs, %[psr] \n" /* set psr for supervisor mode */
"adr lr, 1f \n" /* load exception return address */
"eret \n" /* exception return */
:: [psr] "r" (psr));
"1:":: [psr] "r" (psr), [stack] "r" (&hyp_mode_stack));
}
void Genode::Board::prepare_kernel()
{
prepare_nonsecure_world();
Genode::Cpu::hyp_exception_entry_at(&_hyp_kernel_entry);
Kernel::prepare_hypervisor();
switch_to_supervisor_mode();
}

View File

@ -0,0 +1,34 @@
/*
* \brief Platform specific services for Arndale
* \author Stefan Kalkowski
* \date 2014-07-08
*/
/*
* Copyright (C) 2014 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
/* Genode includes */
#include <base/service.h>
/* Core includes */
#include <platform_services.h>
#include <vm_root.h>
/*
* Add ARM virtualization specific vm service
*/
void Genode::platform_add_local_services(Genode::Rpc_entrypoint *ep,
Genode::Sliced_heap *sh,
Genode::Service_registry *ls)
{
using namespace Genode;
static Vm_root vm_root(ep, sh);
static Local_service vm_ls(Vm_session::service_name(), &vm_root);
ls->insert(&vm_ls);
}

View File

@ -22,46 +22,3 @@ unsigned Cpu::executing_id() { return Mpidr::Aff_0::get(Mpidr::read()); }
unsigned Cpu::primary_id() { return Board::PRIMARY_MPIDR_AFF_0; }
addr_t Cpu::Context::translation_table() const { return ttbr0; }
void Cpu::Context::translation_table(addr_t const t) { ttbr0 = t; }
bool Cpu::User_context::in_fault(addr_t & va, addr_t & w) const
{
switch (cpu_exception) {
case PREFETCH_ABORT:
{
/* check if fault was caused by a translation miss */
Ifsr::access_t const fs = Ifsr::Fs::get(Ifsr::read());
if ((fs & 0b11100) != 0b100)
return false;
/* fetch fault data */
w = 0;
va = ip;
return true;
}
case DATA_ABORT:
{
/* check if fault was caused by translation miss */
Dfsr::access_t const fs = Dfsr::Fs::get(Dfsr::read());
if ((fs & 0b11100) != 0b100)
return false;
/* fetch fault data */
Dfsr::access_t const dfsr = Dfsr::read();
w = Dfsr::Wnr::get(dfsr);
va = Dfar::read();
return true;
}
default:
return false;
};
}

View File

@ -51,6 +51,3 @@ Native_region * Platform::_core_only_mmio_regions(unsigned const i)
};
return i < sizeof(_regions)/sizeof(_regions[0]) ? &_regions[i] : 0;
}
Cpu::User_context::User_context() { cpsr = Psr::init_user(); }

View File

@ -47,17 +47,17 @@ void Kernel::init_trustzone(Pic * pic)
/* configure non-secure interrupts */
for (unsigned i = 0; i < Pic::NR_OF_IRQ; i++) {
if ((i != Imx53::Board::EPIT_1_IRQ) &&
(i != Imx53::Board::EPIT_2_IRQ) &&
(i != Imx53::Board::I2C_2_IRQ) &&
(i != Imx53::Board::I2C_3_IRQ) &&
(i < Imx53::Board::GPIO1_IRQL || i > Imx53::Board::GPIO4_IRQH) &&
(i < Imx53::Board::GPIO5_IRQL || i > Imx53::Board::GPIO7_IRQH))
if ((i != Board::EPIT_1_IRQ) &&
(i != Board::EPIT_2_IRQ) &&
(i != Board::I2C_2_IRQ) &&
(i != Board::I2C_3_IRQ) &&
(i < Board::GPIO1_IRQL || i > Board::GPIO4_IRQH) &&
(i < Board::GPIO5_IRQL || i > Board::GPIO7_IRQH))
pic->unsecure(i);
}
/* configure central security unit */
Genode::Csu csu(Imx53::Board::CSU_BASE);
Genode::Csu csu(Board::CSU_BASE);
}

View File

@ -62,9 +62,6 @@ Native_region * Platform::_core_only_mmio_regions(unsigned const i)
}
Cpu::User_context::User_context() { cpsr = Psr::init_user(); }
static Board::Pl310 * l2_cache() {
return unmanaged_singleton<Board::Pl310>(Board::PL310_MMIO_BASE); }
@ -72,3 +69,6 @@ static Board::Pl310 * l2_cache() {
void Board::outer_cache_invalidate() { l2_cache()->invalidate(); }
void Board::outer_cache_flush() { l2_cache()->flush(); }
void Board::prepare_kernel() { l2_cache()->invalidate(); }
Cpu::User_context::User_context() { cpsr = Psr::init_user(); }

View File

@ -1,95 +0,0 @@
/*
* \brief VM session component for 'base-hw'
* \author Stefan Kalkowski
* \date 2012-10-08
*/
/*
* Copyright (C) 2012-2013 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
/* Genode includes */
#include <util/string.h>
#include <util/arg_string.h>
#include <root/root.h>
#include <cpu/cpu_state.h>
/* core includes */
#include <kernel/core_interface.h>
#include <vm_session_component.h>
#include <platform.h>
#include <core_env.h>
using namespace Genode;
addr_t Vm_session_component::_alloc_ds(size_t &ram_quota)
{
addr_t addr;
if (_ds_size() > ram_quota ||
platform()->ram_alloc()->alloc_aligned(_ds_size(), (void**)&addr,
get_page_size_log2()).is_error())
throw Root::Quota_exceeded();
ram_quota -= _ds_size();
return addr;
}
void Vm_session_component::exception_handler(Signal_context_capability handler)
{
if (_vm_id) {
PWRN("Cannot register exception_handler repeatedly");
return;
}
_vm_id = Kernel::new_vm(_vm, (void*)_ds.core_local_addr(), handler.dst());
}
void Vm_session_component::run(void)
{
if (!_vm_id) {
PWRN("No exception handler registered!");
return;
}
Kernel::run_vm(_vm_id);
}
void Vm_session_component::pause(void)
{
if (!_vm_id) {
PWRN("No exception handler registered!");
return;
}
Kernel::pause_vm(_vm_id);
}
Vm_session_component::Vm_session_component(Rpc_entrypoint *ds_ep,
size_t ram_quota)
: _ds_ep(ds_ep), _vm_id(0),
_ds(_ds_size(), _alloc_ds(ram_quota), UNCACHED, true, 0),
_ds_cap(static_cap_cast<Dataspace>(_ds_ep->manage(&_ds)))
{
_ds.assign_core_local_addr(core_env()->rm_session()->attach(_ds_cap));
/* alloc needed memory */
if (Kernel::vm_size() > ram_quota ||
!platform()->core_mem_alloc()->alloc(Kernel::vm_size(), &_vm))
throw Root::Quota_exceeded();
}
Vm_session_component::~Vm_session_component()
{
/* dissolve VM dataspace from service entry point */
_ds_ep->dissolve(&_ds);
/* free region in allocator */
core_env()->rm_session()->detach(_ds.core_local_addr());
platform()->ram_alloc()->free((void*)_ds.phys_addr());
platform()->core_mem_alloc()->free(_vm);
}

View File

@ -11,8 +11,8 @@
* under the terms of the GNU General Public License version 2.
*/
#ifndef _INCLUDE__DRIVERS__BOARD_BASE_H_
#define _INCLUDE__DRIVERS__BOARD_BASE_H_
#ifndef _INCLUDE__PLATFORM__VEA9X4__DRIVERS__BOARD_BASE_H_
#define _INCLUDE__PLATFORM__VEA9X4__DRIVERS__BOARD_BASE_H_
namespace Genode
{
@ -79,5 +79,5 @@ namespace Genode
};
}
#endif /* _INCLUDE__DRIVERS__BOARD_BASE_H_ */
#endif /* _INCLUDE__PLATFORM__VEA9X4__DRIVERS__BOARD_BASE_H_ */

View File

@ -36,8 +36,15 @@ class Genode::Exynos5
MMIO_0_SIZE = 0x10000000,
/* interrupt controller */
IRQ_CONTROLLER_BASE = 0x10480000,
IRQ_CONTROLLER_SIZE = 0x00010000,
IRQ_CONTROLLER_BASE = 0x10480000,
IRQ_CONTROLLER_SIZE = 0x00010000,
IRQ_CONTROLLER_VT_CTRL_BASE = 0x10484000,
IRQ_CONTROLLER_VT_CPU_BASE = 0x10486000,
IRQ_CONTROLLER_VT_CPU_SIZE = 0x1000,
/* virtual interrupts */
VT_MAINTAINANCE_IRQ = 25,
VT_TIMER_IRQ = 27,
/* UART */
UART_2_MMIO_BASE = 0x12C20000,

112
repos/os/run/vmm.run Normal file
View File

@ -0,0 +1,112 @@
#
# \brief Virtual-machine monitor demo
# \author Stefan Kalkowski
# \date 2015-06-25
#
assert_spec hw_arndale
set build_components {
core init
drivers/timer
drivers/platform
drivers/uart
server/vmm
}
build $build_components
create_boot_directory
install_config {
<config verbose="yes">
<parent-provides>
<service name="ROM"/>
<service name="RAM"/>
<service name="IRQ"/>
<service name="IO_MEM"/>
<service name="CAP"/>
<service name="PD"/>
<service name="RM"/>
<service name="CPU"/>
<service name="LOG"/>
<service name="SIGNAL"/>
<service name="VM"/>
</parent-provides>
<default-route>
<any-service><parent/><any-child/></any-service>
</default-route>
<start name="platform_drv">
<resource name="RAM" quantum="1M"/>
<provides><service name="Regulator"/></provides>
<config/>
</start>
<start name="timer">
<resource name="RAM" quantum="1M"/>
<provides><service name="Timer"/></provides>
</start>
<start name="uart_drv">
<resource name="RAM" quantum="2M"/>
<provides>
<service name="Terminal"/>
<service name="Uart"/>
</provides>
<config>
<policy label="vmm" uart="1"/>
</config>
</start>
<start name="vmm">
<resource name="RAM" quantum="256M"/>
</start>
</config>
}
#
# This test uses a Linux kernel built from unmodified vanilla kernel sources
# but using a slightly simplified kernel configuration, as well as device tree
# for a minimal Versatile Express Cortex A15 like emulated board.
#
# The used sources, including the modified device tree and configuration file
# can be found in the following git repository/branch:
#
# https://github.com/skalk/linux/tree/vexpress-vt
#
# To compile the kernel and device tree blob used in this script, do the
# following steps:
#
# ! git checkout https://github.com/skalk/linux.git
# ! cd linux
# ! git checkout origin/vexpress-vt
# ! make ARCH=arm CROSS_COMPILE=<cross_compiler_prefix> vexpress_config
# ! make ARCH=arm CROSS_COMPILE=<cross_compiler_prefix> -j8 Image
# ! make ARCH=arm CROSS_COMPILE=<cross_compiler_prefix> vexpress-v2p-ca15-tc1.dtb
#
if {![file exists bin/linux]} {
puts "Download linux kernel ..."
exec >& /dev/null wget -c -O bin/linux http://genode.org/files/release-15.02/arm_vt/linux
}
if {![file exists bin/dtb]} {
puts "Download device tree blob ..."
exec >& /dev/null wget -c -O bin/dtb http://genode.org/files/release-15.02/arm_vt/dtb
}
set boot_modules {
core init
platform_drv
uart_drv
timer
vmm
linux
dtb
}
build_boot_image $boot_modules
#
# Execute test case
#
run_genode_until {.*\/ #.*} 220
set serial_id [output_spawn_id]
send -i $serial_id "ls\n"
run_genode_until "var" 30 $serial_id
exec rm bin/linux bin/dtb

View File

@ -17,6 +17,7 @@
#include <base/thread.h>
#include <drivers/board_base.h>
#include <drivers/trustzone.h>
#include <vm_state.h>
/* local includes */
#include <vm.h>

View File

@ -22,8 +22,8 @@ class Mmu
{
private:
Vm_state *_state;
Ram *_ram;
Genode::Vm_state *_state;
Ram *_ram;
unsigned _n_bits() { return _state->ttbrc & 0x7; }
@ -68,7 +68,7 @@ class Mmu
public:
Mmu(Vm_state *state, Ram *ram)
Mmu(Genode::Vm_state *state, Ram *ram)
: _state(state), _ram(ram) {}

View File

@ -40,7 +40,7 @@ class Vm {
Genode::Dataspace_client _kernel_cap;
Genode::Dataspace_client _initrd_cap;
const char* _cmdline;
Vm_state *_state;
Genode::Vm_state *_state;
Genode::Io_mem_connection _ram_iomem;
Ram _ram;
Genode::addr_t _kernel_offset;
@ -90,7 +90,7 @@ class Vm {
_kernel_cap(_kernel_rom.dataspace()),
_initrd_cap(_initrd_rom.dataspace()),
_cmdline(cmdline),
_state((Vm_state*)Genode::env()->rm_session()->attach(_vm_con.cpu_state())),
_state((Genode::Vm_state*)Genode::env()->rm_session()->attach(_vm_con.cpu_state())),
_ram_iomem(ram_base, ram_size),
_ram(ram_base, ram_size, (Genode::addr_t)Genode::env()->rm_session()->attach(_ram_iomem.dataspace())),
_kernel_offset(kernel_offset),
@ -99,7 +99,7 @@ class Vm {
void start()
{
Genode::memset((void*)_state, 0, sizeof(Vm_state));
Genode::memset((void*)_state, 0, sizeof(Genode::Vm_state));
_load_kernel();
_load_initrd();
_prepare_atag();
@ -161,7 +161,7 @@ class Vm {
_state->ip, va_to_pa(_state->ip));
printf(" cpsr = %08lx\n", _state->cpsr);
for (unsigned i = 0;
i < Vm_state::Mode_state::MAX; i++) {
i < Genode::Vm_state::Mode_state::MAX; i++) {
printf(" sp_%s = %08lx [%08lx]\n", modes[i],
_state->mode[i].sp, va_to_pa(_state->mode[i].sp));
printf(" lr_%s = %08lx [%08lx]\n", modes[i],
@ -186,8 +186,8 @@ class Vm {
return 0;
}
Vm_state *state() const { return _state; }
Ram *ram() { return &_ram; }
Genode::Vm_state *state() const { return _state; }
Ram *ram() { return &_ram; }
};
#endif /* _SRC__SERVER__VMM__INCLUDE__VM_H_ */

View File

@ -1,27 +0,0 @@
/*
* \brief Virtual Machine Monitor VM state definition
* \author Stefan Kalkowski
* \date 2012-06-25
*/
/*
* Copyright (C) 2012-2013 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#ifndef _SRC__SERVER__VMM__INCLUDE__VM_STATE_H_
#define _SRC__SERVER__VMM__INCLUDE__VM_STATE_H_
/* Genode includes */
#include <cpu/cpu_state.h>
struct Vm_state : Genode::Cpu_state_modes
{
Genode::addr_t dfar; /* data fault address */
Genode::addr_t ttbr[2]; /* translation table base regs */
Genode::addr_t ttbrc; /* translation table base control */
};
#endif /* _SRC__SERVER__VMM__INCLUDE__VM_STATE_H_ */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,4 @@
TARGET = vmm
REQUIRES = hw_arndale
LIBS = base
SRC_CC = main.cc

View File

@ -0,0 +1,30 @@
.section ".text.crt0"
.global _start
_start:
/* idle a little initially because U-Boot likes it this way */
mov r8, r8
mov r8, r8
mov r8, r8
mov r8, r8
mov r8, r8
mov r8, r8
mov r8, r8
mov r8, r8
/* zero-fill BSS segment */
ldr r0, =_bss_start
ldr r1, =_bss_end
mov r2, #0
1:
cmp r1, r0
ble 2f
str r2, [r0]
add r0, r0, #4
b 1b
2:
hvc #0
1: b 1b

View File

@ -0,0 +1,3 @@
TARGET = test-kernel
REQUIRES = hw_arndale
SRC_S = main.s

View File

@ -45,3 +45,4 @@ pthread
virtualbox_auto_disk
virtualbox_auto_share
tz_vmm
vmm