mirror of
https://github.com/genodelabs/genode.git
synced 2025-01-26 14:19:19 +00:00
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:
parent
07c8d1652e
commit
7582396e9c
80
repos/base-hw/include/platform/arndale/vm_state.h
Normal file
80
repos/base-hw/include/platform/arndale/vm_state.h
Normal 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_ */
|
@ -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_ */
|
@ -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); }
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
13
repos/base-hw/lib/mk/platform_imx53/core-trustzone.inc
Normal file
13
repos/base-hw/lib/mk/platform_imx53/core-trustzone.inc
Normal 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
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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_ */
|
||||
|
@ -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>
|
||||
|
@ -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();
|
||||
|
@ -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; }
|
||||
};
|
||||
|
||||
|
@ -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;
|
||||
};
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
*/
|
||||
|
@ -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
|
||||
|
||||
|
@ -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_ */
|
@ -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_ */
|
@ -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));
|
||||
|
@ -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
|
||||
|
@ -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_ */
|
@ -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); }
|
||||
|
||||
|
||||
/*********
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
*/
|
||||
|
@ -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;
|
||||
|
@ -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>(); }
|
||||
}
|
20
repos/base-hw/src/core/kernel/vm_thread.cc
Normal file
20
repos/base-hw/src/core/kernel/vm_thread.cc
Normal 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); }
|
@ -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;
|
||||
};
|
||||
}
|
||||
|
@ -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);
|
||||
|
21
repos/base-hw/src/core/spec/arm/kernel/cpu_context.cc
Normal file
21
repos/base-hw/src/core/spec/arm/kernel/cpu_context.cc
Normal 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);
|
||||
}
|
@ -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) {
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
38
repos/base-hw/src/core/spec/arm_v7/kernel/vm_thread.cc
Normal file
38
repos/base-hw/src/core/spec/arm_v7/kernel/vm_thread.cc
Normal 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);
|
||||
}
|
@ -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:
|
||||
|
67
repos/base-hw/src/core/spec/arm_v7/trustzone/kernel/vm.cc
Normal file
67
repos/base-hw/src/core/spec/arm_v7/trustzone/kernel/vm.cc
Normal 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);
|
||||
}
|
@ -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());
|
||||
}
|
125
repos/base-hw/src/core/spec/arm_v7/trustzone/mode_transition.s
Normal file
125
repos/base-hw/src/core/spec/arm_v7/trustzone/mode_transition.s
Normal 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
|
||||
|
@ -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));
|
||||
}
|
@ -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();
|
||||
}
|
267
repos/base-hw/src/core/spec/arm_v7/virtualization/kernel/vm.cc
Normal file
267
repos/base-hw/src/core/spec/arm_v7/virtualization/kernel/vm.cc
Normal 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);
|
||||
}
|
@ -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());
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
57
repos/base-hw/src/core/spec/arm_v7/vm_session_component.cc
Normal file
57
repos/base-hw/src/core/spec/arm_v7/vm_session_component.cc
Normal 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());
|
||||
}
|
@ -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();
|
||||
}
|
||||
|
34
repos/base-hw/src/core/spec/arndale/platform_services.cc
Normal file
34
repos/base-hw/src/core/spec/arndale/platform_services.cc
Normal 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);
|
||||
}
|
@ -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;
|
||||
};
|
||||
}
|
||||
|
@ -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(); }
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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(); }
|
||||
|
@ -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);
|
||||
}
|
@ -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_ */
|
||||
|
||||
|
@ -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
112
repos/os/run/vmm.run
Normal 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
|
@ -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>
|
||||
|
@ -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) {}
|
||||
|
||||
|
||||
|
@ -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_ */
|
||||
|
@ -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_ */
|
1330
repos/os/src/server/vmm/main.cc
Normal file
1330
repos/os/src/server/vmm/main.cc
Normal file
File diff suppressed because it is too large
Load Diff
4
repos/os/src/server/vmm/target.mk
Normal file
4
repos/os/src/server/vmm/target.mk
Normal file
@ -0,0 +1,4 @@
|
||||
TARGET = vmm
|
||||
REQUIRES = hw_arndale
|
||||
LIBS = base
|
||||
SRC_CC = main.cc
|
30
repos/os/src/server/vmm/test/kernel/main.s
Normal file
30
repos/os/src/server/vmm/test/kernel/main.s
Normal 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
|
3
repos/os/src/server/vmm/test/kernel/target.mk
Normal file
3
repos/os/src/server/vmm/test/kernel/target.mk
Normal file
@ -0,0 +1,3 @@
|
||||
TARGET = test-kernel
|
||||
REQUIRES = hw_arndale
|
||||
SRC_S = main.s
|
@ -45,3 +45,4 @@ pthread
|
||||
virtualbox_auto_disk
|
||||
virtualbox_auto_share
|
||||
tz_vmm
|
||||
vmm
|
||||
|
Loading…
x
Reference in New Issue
Block a user