mirror of
https://github.com/genodelabs/genode.git
synced 2024-12-21 22:47:50 +00:00
parent
f82714f341
commit
af29dcf557
109
repos/base-hw/include/spec/arm_64/cpu/vm_state_virtualization.h
Normal file
109
repos/base-hw/include/spec/arm_64/cpu/vm_state_virtualization.h
Normal file
@ -0,0 +1,109 @@
|
||||
/*
|
||||
* \brief CPU, PIC, and timer context of a virtual machine
|
||||
* \author Stefan Kalkowski
|
||||
* \date 2015-02-10
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2015-2017 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU Affero General Public License version 3.
|
||||
*/
|
||||
|
||||
#ifndef _INCLUDE__SPEC__ARM_64__CPU__VM_STATE_VIRTUALIZATION_H_
|
||||
#define _INCLUDE__SPEC__ARM_64__CPU__VM_STATE_VIRTUALIZATION_H_
|
||||
|
||||
/* Genode includes */
|
||||
#include <cpu/cpu_state.h>
|
||||
|
||||
namespace Genode
|
||||
{
|
||||
/**
|
||||
* CPU context of a virtual machine
|
||||
*/
|
||||
struct Vm_state;
|
||||
|
||||
using uint128_t = __uint128_t;
|
||||
}
|
||||
|
||||
struct Genode::Vm_state : Genode::Cpu_state
|
||||
{
|
||||
Genode::uint64_t pstate { 0 };
|
||||
Genode::uint64_t exception_type { 0 };
|
||||
Genode::uint64_t esr_el2 { 0 };
|
||||
|
||||
/** Fpu registers **/
|
||||
Genode::uint128_t q[32] { 0 };
|
||||
Genode::uint32_t fpcr { 0 };
|
||||
Genode::uint32_t fpsr { 0 };
|
||||
|
||||
Genode::uint64_t elr_el1 { 0 };
|
||||
Genode::uint64_t sp_el1 { 0 };
|
||||
Genode::uint32_t spsr_el1 { 0 };
|
||||
Genode::uint32_t esr_el1 { 0 };
|
||||
|
||||
Genode::uint64_t sctlr_el1 { 0 };
|
||||
Genode::uint64_t actlr_el1 { 0 };
|
||||
Genode::uint64_t vbar_el1 { 0 };
|
||||
Genode::uint32_t cpacr_el1 { 0 };
|
||||
Genode::uint32_t afsr0_el1 { 0 };
|
||||
Genode::uint32_t afsr1_el1 { 0 };
|
||||
Genode::uint32_t contextidr_el1 { 0 };
|
||||
|
||||
Genode::uint64_t ttbr0_el1 { 0 };
|
||||
Genode::uint64_t ttbr1_el1 { 0 };
|
||||
Genode::uint64_t tcr_el1 { 0 };
|
||||
Genode::uint64_t mair_el1 { 0 };
|
||||
Genode::uint64_t amair_el1 { 0 };
|
||||
Genode::uint64_t far_el1 { 0 };
|
||||
Genode::uint64_t par_el1 { 0 };
|
||||
|
||||
Genode::uint64_t tpidrro_el0 { 0 };
|
||||
Genode::uint64_t tpidr_el0 { 0 };
|
||||
Genode::uint64_t tpidr_el1 { 0 };
|
||||
|
||||
Genode::uint64_t vmpidr_el2 { 0 };
|
||||
|
||||
Genode::uint64_t far_el2 { 0 };
|
||||
Genode::uint64_t hpfar_el2 { 0 };
|
||||
|
||||
/**
|
||||
* Timer related registers
|
||||
*/
|
||||
struct Timer {
|
||||
Genode::uint64_t offset { 0 };
|
||||
Genode::uint64_t compare { 0 };
|
||||
Genode::uint32_t control { 0 };
|
||||
Genode::uint32_t kcontrol { 0 };
|
||||
bool irq { false };
|
||||
} timer {};
|
||||
|
||||
/**
|
||||
* Interrupt related values
|
||||
*/
|
||||
struct Pic
|
||||
{
|
||||
unsigned last_irq { 1023 };
|
||||
unsigned virtual_irq { 1023 };
|
||||
} irqs {};
|
||||
|
||||
/**************************
|
||||
** Platform information **
|
||||
**************************/
|
||||
|
||||
Genode::uint64_t id_aa64isar0_el1 { 0 };
|
||||
Genode::uint64_t id_aa64isar1_el1 { 0 };
|
||||
Genode::uint64_t id_aa64mmfr0_el1 { 0 };
|
||||
Genode::uint64_t id_aa64mmfr1_el1 { 0 };
|
||||
Genode::uint64_t id_aa64mmfr2_el1 { 0 };
|
||||
Genode::uint64_t id_aa64pfr0_el1 { 0 };
|
||||
Genode::uint64_t id_aa64pfr1_el1 { 0 };
|
||||
Genode::uint64_t id_aa64zfr0_el1 { 0 };
|
||||
|
||||
Genode::uint32_t ccsidr_inst_el1[7] { 0 };
|
||||
Genode::uint32_t ccsidr_data_el1[7] { 0 };
|
||||
Genode::uint64_t clidr_el1 { 0 };
|
||||
};
|
||||
|
||||
#endif /* _INCLUDE__SPEC__ARM_64__CPU__VM_STATE_VIRTUALIZATION_H_ */
|
@ -14,8 +14,8 @@ SRC_CC += spec/arm/gicv2.cc
|
||||
SRC_CC += spec/arm_v7/virtualization/kernel/vm.cc
|
||||
SRC_CC += spec/arm/virtualization/platform_services.cc
|
||||
SRC_CC += spec/arm/virtualization/vm_session_component.cc
|
||||
SRC_CC += spec/arm/vm_session_component.cc
|
||||
SRC_CC += vm_session_common.cc
|
||||
SRC_CC += vm_session_component.cc
|
||||
|
||||
# add assembly sources
|
||||
SRC_S += spec/arm_v7/virtualization/exception_vector.s
|
||||
|
@ -5,7 +5,8 @@ SRC_CC += kernel/vm_thread_on.cc
|
||||
SRC_CC += spec/arm_v7/trustzone/kernel/vm.cc
|
||||
SRC_CC += spec/arm_v7/trustzone/platform_services.cc
|
||||
SRC_CC += spec/arm_v7/trustzone/vm_session_component.cc
|
||||
SRC_CC += spec/arm_v7/vm_session_component.cc
|
||||
SRC_CC += vm_session_common.cc
|
||||
SRC_CC += vm_session_component.cc
|
||||
|
||||
SRC_S += spec/arm_v7/trustzone/exception_vector.s
|
||||
|
||||
|
@ -13,10 +13,11 @@ SRC_CC += kernel/vm_thread_on.cc
|
||||
SRC_CC += spec/arm/generic_timer.cc
|
||||
SRC_CC += spec/arm/gicv2.cc
|
||||
SRC_CC += spec/arm_v7/virtualization/kernel/vm.cc
|
||||
SRC_CC += spec/arm/virtualization/gicv2.cc
|
||||
SRC_CC += spec/arm/virtualization/platform_services.cc
|
||||
SRC_CC += spec/arm/virtualization/vm_session_component.cc
|
||||
SRC_CC += spec/arm/vm_session_component.cc
|
||||
SRC_CC += vm_session_common.cc
|
||||
SRC_CC += vm_session_component.cc
|
||||
|
||||
# add assembly sources
|
||||
SRC_S += spec/arm_v7/virtualization/exception_vector.s
|
||||
|
@ -17,7 +17,8 @@ SRC_CC += spec/arm/imx_tzic.cc
|
||||
SRC_CC += spec/arm_v7/trustzone/kernel/vm.cc
|
||||
SRC_CC += spec/arm_v7/trustzone/platform_services.cc
|
||||
SRC_CC += spec/arm_v7/trustzone/vm_session_component.cc
|
||||
SRC_CC += spec/arm_v7/vm_session_component.cc
|
||||
SRC_CC += vm_session_common.cc
|
||||
SRC_CC += vm_session_component.cc
|
||||
|
||||
# add assembly sources
|
||||
SRC_S += spec/arm_v7/trustzone/exception_vector.s
|
||||
|
@ -1,10 +1,10 @@
|
||||
INC_DIR += $(REP_DIR)/src/core/spec/imx8q_evk
|
||||
INC_DIR += $(REP_DIR)/src/core/spec/arm_v8
|
||||
INC_DIR += $(REP_DIR)/src/core/spec/arm/virtualization
|
||||
|
||||
# add C++ sources
|
||||
SRC_CC += kernel/cpu_mp.cc
|
||||
SRC_CC += kernel/vm_thread_off.cc
|
||||
SRC_CC += platform_services.cc
|
||||
SRC_CC += kernel/vm_thread_on.cc
|
||||
SRC_CC += spec/64bit/memory_map.cc
|
||||
SRC_CC += spec/arm/generic_timer.cc
|
||||
SRC_CC += spec/arm/gicv3.cc
|
||||
@ -13,10 +13,16 @@ SRC_CC += spec/arm/platform_support.cc
|
||||
SRC_CC += spec/arm_v8/cpu.cc
|
||||
SRC_CC += spec/arm_v8/kernel/cpu.cc
|
||||
SRC_CC += spec/arm_v8/kernel/thread.cc
|
||||
SRC_CC += spec/arm_v8/virtualization/kernel/vm.cc
|
||||
SRC_CC += spec/arm/virtualization/platform_services.cc
|
||||
SRC_CC += spec/arm/virtualization/vm_session_component.cc
|
||||
SRC_CC += vm_session_common.cc
|
||||
SRC_CC += vm_session_component.cc
|
||||
|
||||
#add assembly sources
|
||||
SRC_S += spec/arm_v8/exception_vector.s
|
||||
SRC_S += spec/arm_v8/crt0.s
|
||||
SRC_S += spec/arm_v8/virtualization/exception_vector.s
|
||||
|
||||
vpath spec/64bit/memory_map.cc $(BASE_DIR)/../base-hw/src/lib/hw
|
||||
|
||||
|
@ -35,7 +35,10 @@ SRC_CC += spec/x86_64/muen/platform_services.cc
|
||||
SRC_CC += spec/x86_64/muen/platform_support.cc
|
||||
SRC_CC += spec/x86_64/muen/sinfo_instance.cc
|
||||
SRC_CC += spec/x86_64/muen/timer.cc
|
||||
SRC_CC += spec/x86_64/muen/vm_session_component.cc
|
||||
SRC_CC += spec/x86_64/platform_support_common.cc
|
||||
SRC_CC += vm_session_common.cc
|
||||
SRC_CC += vm_session_component.cc
|
||||
|
||||
SRC_CC += spec/64bit/memory_map.cc
|
||||
|
||||
|
@ -11,6 +11,7 @@
|
||||
* under the terms of the GNU Affero General Public License version 3.
|
||||
*/
|
||||
|
||||
#include <hw/spec/arm_64/memory_map.h>
|
||||
#include <platform.h>
|
||||
|
||||
using Board::Cpu;
|
||||
@ -57,11 +58,54 @@ static inline void prepare_non_secure_world()
|
||||
}
|
||||
|
||||
|
||||
static inline void prepare_hypervisor()
|
||||
static inline void prepare_hypervisor(Cpu::Ttbr::access_t const ttbr)
|
||||
{
|
||||
Cpu::Hcr::access_t scr = Cpu::Hcr::read();
|
||||
Cpu::Hcr::Rw::set(scr, 1); /* exec in aarch64 */
|
||||
Cpu::Hcr::write(scr);
|
||||
using namespace Hw::Mm;
|
||||
|
||||
/* forbid trace access */
|
||||
Cpu::Cptr_el2::access_t cptr = Cpu::Cptr_el2::read();
|
||||
Cpu::Cptr_el2::Tta::set(cptr, 1);
|
||||
Cpu::Cptr_el2::write(cptr);
|
||||
|
||||
/* allow physical counter/timer access without trapping */
|
||||
Cpu::Cnthctl_el2::write(0b111);
|
||||
|
||||
/* forbid any 32bit access to coprocessor/sysregs */
|
||||
Cpu::Hstr_el2::write(0xffff);
|
||||
|
||||
Cpu::Hcr_el2::access_t hcr = Cpu::Hcr_el2::read();
|
||||
Cpu::Hcr_el2::Rw::set(hcr, 1); /* exec in aarch64 */
|
||||
Cpu::Hcr_el2::write(hcr);
|
||||
|
||||
/* set hypervisor exception vector */
|
||||
Cpu::Vbar_el2::write(el2_addr(hypervisor_exception_vector().base));
|
||||
Genode::addr_t const stack_el2 = el2_addr(hypervisor_stack().base +
|
||||
hypervisor_stack().size);
|
||||
|
||||
/* set hypervisor's translation table */
|
||||
Cpu::Ttbr0_el2::write(ttbr);
|
||||
|
||||
Cpu::Tcr_el2::access_t tcr_el2 = 0;
|
||||
Cpu::Tcr_el2::T0sz::set(tcr_el2, 25);
|
||||
Cpu::Tcr_el2::Irgn0::set(tcr_el2, 1);
|
||||
Cpu::Tcr_el2::Orgn0::set(tcr_el2, 1);
|
||||
Cpu::Tcr_el2::Sh0::set(tcr_el2, 0b10);
|
||||
|
||||
/* prepare MMU usage by hypervisor code */
|
||||
Cpu::Tcr_el2::write(tcr_el2);
|
||||
|
||||
/* set memory attributes in indirection register */
|
||||
Cpu::Mair::access_t mair = 0;
|
||||
Cpu::Mair::Attr0::set(mair, Cpu::Mair::NORMAL_MEMORY_UNCACHED);
|
||||
Cpu::Mair::Attr1::set(mair, Cpu::Mair::DEVICE_MEMORY);
|
||||
Cpu::Mair::Attr2::set(mair, Cpu::Mair::NORMAL_MEMORY_CACHED);
|
||||
Cpu::Mair::Attr3::set(mair, Cpu::Mair::DEVICE_MEMORY);
|
||||
Cpu::Mair_el2::write(mair);
|
||||
|
||||
Cpu::Vtcr_el2::access_t vtcr = 0;
|
||||
Cpu::Vtcr_el2::T0sz::set(vtcr, 25);
|
||||
Cpu::Vtcr_el2::Sl0::set(vtcr, 1); /* set to starting level 1 */
|
||||
Cpu::Vtcr_el2::write(vtcr);
|
||||
|
||||
Cpu::Spsr::access_t pstate = 0;
|
||||
Cpu::Spsr::Sp::set(pstate, 1); /* select non-el0 stack pointer */
|
||||
@ -72,12 +116,22 @@ static inline void prepare_hypervisor()
|
||||
Cpu::Spsr::D::set(pstate, 1);
|
||||
Cpu::Spsr_el2::write(pstate);
|
||||
|
||||
Cpu::Sctlr::access_t sctlr = Cpu::Sctlr_el2::read();
|
||||
Cpu::Sctlr::M::set(sctlr, 1);
|
||||
Cpu::Sctlr::A::set(sctlr, 0);
|
||||
Cpu::Sctlr::C::set(sctlr, 1);
|
||||
Cpu::Sctlr::Sa::set(sctlr, 0);
|
||||
Cpu::Sctlr::I::set(sctlr, 1);
|
||||
Cpu::Sctlr::Wxn::set(sctlr, 0);
|
||||
Cpu::Sctlr_el2::write(sctlr);
|
||||
|
||||
asm volatile("mov x0, sp \n"
|
||||
"msr sp_el1, x0 \n"
|
||||
"adr x0, 1f \n"
|
||||
"msr elr_el2, x0 \n"
|
||||
"mov sp, %0 \n"
|
||||
"eret \n"
|
||||
"1:");
|
||||
"1:": : "r"(stack_el2): "x0");
|
||||
}
|
||||
|
||||
|
||||
@ -87,13 +141,16 @@ unsigned Bootstrap::Platform::enable_mmu()
|
||||
bool primary = primary_cpu;
|
||||
if (primary) primary_cpu = false;
|
||||
|
||||
::Board::Pic pic __attribute__((unused)) {};
|
||||
Cpu::Ttbr::access_t ttbr =
|
||||
Cpu::Ttbr::Baddr::masked((Genode::addr_t)core_pd->table_base);
|
||||
|
||||
while (Cpu::current_privilege_level() > Cpu::Current_el::EL1) {
|
||||
if (Cpu::current_privilege_level() == Cpu::Current_el::EL3)
|
||||
if (Cpu::current_privilege_level() == Cpu::Current_el::EL3) {
|
||||
prepare_non_secure_world();
|
||||
else
|
||||
prepare_hypervisor();
|
||||
} else {
|
||||
::Board::Pic pic __attribute__((unused)) {};
|
||||
prepare_hypervisor(ttbr);
|
||||
}
|
||||
}
|
||||
|
||||
/* primary cpu wakes up all others */
|
||||
@ -102,6 +159,9 @@ unsigned Bootstrap::Platform::enable_mmu()
|
||||
/* enable performance counter for user-land */
|
||||
Cpu::Pmuserenr_el0::write(0b1111);
|
||||
|
||||
/* enable user-level access of physical/virtual counter */
|
||||
Cpu::Cntkctl_el1::write(0b11);
|
||||
|
||||
Cpu::Vbar_el1::write(Hw::Mm::supervisor_exception_vector().base);
|
||||
|
||||
/* set memory attributes in indirection register */
|
||||
@ -110,9 +170,8 @@ unsigned Bootstrap::Platform::enable_mmu()
|
||||
Cpu::Mair::Attr1::set(mair, Cpu::Mair::DEVICE_MEMORY);
|
||||
Cpu::Mair::Attr2::set(mair, Cpu::Mair::NORMAL_MEMORY_CACHED);
|
||||
Cpu::Mair::Attr3::set(mair, Cpu::Mair::DEVICE_MEMORY);
|
||||
Cpu::Mair::write(mair);
|
||||
Cpu::Mair_el1::write(mair);
|
||||
|
||||
Cpu::Ttbr::access_t ttbr = Cpu::Ttbr::Baddr::masked((Genode::addr_t)core_pd->table_base);
|
||||
Cpu::Ttbr0_el1::write(ttbr);
|
||||
Cpu::Ttbr1_el1::write(ttbr);
|
||||
|
||||
@ -129,13 +188,14 @@ unsigned Bootstrap::Platform::enable_mmu()
|
||||
Cpu::Tcr_el1::As::set(tcr, 1);
|
||||
Cpu::Tcr_el1::write(tcr);
|
||||
|
||||
Cpu::Sctlr_el1::access_t sctlr = Cpu::Sctlr_el1::read();
|
||||
Cpu::Sctlr_el1::C::set(sctlr, 1);
|
||||
Cpu::Sctlr_el1::I::set(sctlr, 1);
|
||||
Cpu::Sctlr_el1::A::set(sctlr, 0);
|
||||
Cpu::Sctlr_el1::M::set(sctlr, 1);
|
||||
Cpu::Sctlr_el1::Sa0::set(sctlr, 1);
|
||||
Cpu::Sctlr_el1::Sa::set(sctlr, 0);
|
||||
Cpu::Sctlr::access_t sctlr = Cpu::Sctlr_el1::read();
|
||||
Cpu::Sctlr::C::set(sctlr, 1);
|
||||
Cpu::Sctlr::I::set(sctlr, 1);
|
||||
Cpu::Sctlr::A::set(sctlr, 0);
|
||||
Cpu::Sctlr::M::set(sctlr, 1);
|
||||
Cpu::Sctlr::Sa0::set(sctlr, 1);
|
||||
Cpu::Sctlr::Sa::set(sctlr, 0);
|
||||
Cpu::Sctlr::Uct::set(sctlr, 1);
|
||||
Cpu::Sctlr_el1::write(sctlr);
|
||||
|
||||
return 0;
|
||||
|
@ -22,6 +22,8 @@ namespace Genode { class Vm_state; }
|
||||
#include <kernel/pd.h>
|
||||
#include <kernel/signal_receiver.h>
|
||||
|
||||
#include <board.h>
|
||||
|
||||
namespace Kernel
|
||||
{
|
||||
/**
|
||||
@ -36,19 +38,22 @@ class Kernel::Vm : public Cpu_job,
|
||||
{
|
||||
private:
|
||||
|
||||
using State = Board::Vm_state;
|
||||
|
||||
/*
|
||||
* Noncopyable
|
||||
*/
|
||||
Vm(Vm const &);
|
||||
Vm &operator = (Vm const &);
|
||||
|
||||
enum State { ACTIVE, INACTIVE };
|
||||
enum Scheduler_state { ACTIVE, INACTIVE };
|
||||
|
||||
unsigned _id = 0;
|
||||
Genode::Vm_state * const _state;
|
||||
Signal_context * const _context;
|
||||
void * const _table;
|
||||
State _scheduled = INACTIVE;
|
||||
unsigned _id = 0;
|
||||
State & _state;
|
||||
Signal_context & _context;
|
||||
void * const _table;
|
||||
Scheduler_state _scheduled = INACTIVE;
|
||||
Board::Vcpu_context _vcpu_context;
|
||||
|
||||
public:
|
||||
|
||||
@ -59,9 +64,10 @@ class Kernel::Vm : public Cpu_job,
|
||||
* \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,
|
||||
void * const table);
|
||||
Vm(unsigned cpu,
|
||||
State & state,
|
||||
Signal_context & context,
|
||||
void * const table);
|
||||
|
||||
~Vm();
|
||||
|
||||
@ -85,12 +91,13 @@ class Kernel::Vm : public Cpu_job,
|
||||
* \retval cap id when successful, otherwise invalid cap id
|
||||
*/
|
||||
static capid_t syscall_create(Genode::Kernel_object<Vm> & vm,
|
||||
unsigned cpu,
|
||||
void * const state,
|
||||
capid_t const signal_context_id,
|
||||
void * const table)
|
||||
{
|
||||
return call(call_id_new_vm(), (Call_arg)&vm, (Call_arg)state,
|
||||
(Call_arg)table, signal_context_id);
|
||||
return call(call_id_new_vm(), (Call_arg)&vm, (Call_arg)cpu,
|
||||
(Call_arg)state, (Call_arg)table, signal_context_id);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -18,13 +18,14 @@
|
||||
void Kernel::Thread::_call_new_vm()
|
||||
{
|
||||
Signal_context * context =
|
||||
pd().cap_tree().find<Signal_context>(user_arg_4());
|
||||
pd().cap_tree().find<Signal_context>(user_arg_5());
|
||||
if (!context) {
|
||||
user_arg_0(cap_id_invalid());
|
||||
return;
|
||||
}
|
||||
|
||||
_call_new<Vm>((void*)user_arg_2(), context, (void*)user_arg_3());
|
||||
_call_new<Vm>((unsigned)user_arg_2(), *(Board::Vm_state*)user_arg_3(),
|
||||
*context, (void*)user_arg_4());
|
||||
}
|
||||
|
||||
|
||||
|
33
repos/base-hw/src/core/spec/arm/trustzone_board.h
Normal file
33
repos/base-hw/src/core/spec/arm/trustzone_board.h
Normal file
@ -0,0 +1,33 @@
|
||||
/*
|
||||
* \brief Board driver
|
||||
* \author Stefan Kalkowski
|
||||
* \date 2019-11-11
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2019 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU Affero General Public License version 3.
|
||||
*/
|
||||
|
||||
#ifndef _CORE__SPEC__ARM_TRUSTZONE_BOARD_H_
|
||||
#define _CORE__SPEC__ARM_TRUSTZONE_BOARD_H_
|
||||
|
||||
#include <spec/arm/cpu/vm_state_trustzone.h>
|
||||
|
||||
namespace Kernel { class Cpu; }
|
||||
|
||||
namespace Board {
|
||||
using Genode::Vm_state;
|
||||
|
||||
enum { VCPU_MAX = 1 };
|
||||
|
||||
struct Vm_page_table {};
|
||||
struct Vm_page_table_array {};
|
||||
|
||||
struct Pic : Hw::Pic { struct Virtual_context {}; };
|
||||
struct Vcpu_context { Vcpu_context(Kernel::Cpu &) {} };
|
||||
}
|
||||
|
||||
#endif /* _CORE__SPEC__ARM_TRUSTZONE_BOARD_H_ */
|
62
repos/base-hw/src/core/spec/arm/virtualization/gicv2.cc
Normal file
62
repos/base-hw/src/core/spec/arm/virtualization/gicv2.cc
Normal file
@ -0,0 +1,62 @@
|
||||
/*
|
||||
* \brief Gicv2 with virtualization extensions
|
||||
* \author Stefan Kalkowski
|
||||
* \date 2019-09-02
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2019 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU Affero General Public License version 3.
|
||||
*/
|
||||
|
||||
#include <util/mmio.h>
|
||||
|
||||
#include <platform.h>
|
||||
#include <spec/arm/virtualization/gicv2.h>
|
||||
|
||||
using Board::Pic;
|
||||
|
||||
Pic::Gich::Gich()
|
||||
: Genode::Mmio(Genode::Platform::mmio_to_virt(Board::Cpu_mmio::IRQ_CONTROLLER_VT_CTRL_BASE)) { }
|
||||
|
||||
|
||||
bool Pic::ack_virtual_irq(Pic::Virtual_context & c)
|
||||
{
|
||||
c.misr = _gich.read<Gich::Gich_misr >();
|
||||
c.vmcr = _gich.read<Gich::Gich_vmcr >();
|
||||
c.apr = _gich.read<Gich::Gich_apr >();
|
||||
c.eisr = _gich.read<Gich::Gich_eisr0 >();
|
||||
c.elrsr = _gich.read<Gich::Gich_elrsr0>();
|
||||
c.lr = _gich.read<Gich::Gich_lr0 >();
|
||||
_gich.write<Gich::Gich_hcr>(0);
|
||||
|
||||
if (c.eisr & 1) {
|
||||
c.lr = 0;
|
||||
c.elrsr = 0xffffffff;
|
||||
c.misr = 0;
|
||||
c.eisr = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void Pic::insert_virtual_irq(Pic::Virtual_context & c, unsigned irq)
|
||||
{
|
||||
enum { SPURIOUS = 1023 };
|
||||
|
||||
if (irq != SPURIOUS && !c.lr) {
|
||||
c.elrsr &= 0x7ffffffe;
|
||||
c.lr = irq | 1 << 28 | 1 << 19;
|
||||
}
|
||||
|
||||
_gich.write<Gich::Gich_misr >(c.misr);
|
||||
_gich.write<Gich::Gich_vmcr >(c.vmcr);
|
||||
_gich.write<Gich::Gich_apr >(c.apr);
|
||||
_gich.write<Gich::Gich_elrsr0>(c.elrsr);
|
||||
_gich.write<Gich::Gich_lr0 >(c.lr);
|
||||
_gich.write<Gich::Gich_hcr>(0b1);
|
||||
}
|
55
repos/base-hw/src/core/spec/arm/virtualization/gicv2.h
Normal file
55
repos/base-hw/src/core/spec/arm/virtualization/gicv2.h
Normal file
@ -0,0 +1,55 @@
|
||||
/*
|
||||
* \brief Gicv2 with virtualization extensions
|
||||
* \author Stefan Kalkowski
|
||||
* \date 2019-09-02
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2019 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU Affero General Public License version 3.
|
||||
*/
|
||||
|
||||
#ifndef _CORE__SPEC__ARM__VIRTUALIZATION__GICV2_H_
|
||||
#define _CORE__SPEC__ARM__VIRTUALIZATION__GICV2_H_
|
||||
|
||||
#include <hw/spec/arm/gicv2.h>
|
||||
|
||||
namespace Board { struct Pic; };
|
||||
|
||||
|
||||
class Board::Pic : public Hw::Gicv2
|
||||
{
|
||||
private:
|
||||
|
||||
struct Gich : 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> { };
|
||||
struct Gich_lr0 : Register<0x100, 32> { };
|
||||
|
||||
Gich();
|
||||
} _gich {};
|
||||
|
||||
public:
|
||||
|
||||
struct Virtual_context
|
||||
{
|
||||
Genode::uint32_t lr { 0 };
|
||||
Genode::uint32_t apr { 0 };
|
||||
Genode::uint32_t vmcr { 0x4c0000 };
|
||||
Genode::uint32_t misr { 0 };
|
||||
Genode::uint32_t eisr { 0 };
|
||||
Genode::uint32_t elrsr { 0xffffffff };
|
||||
};
|
||||
|
||||
bool ack_virtual_irq(Virtual_context & c);
|
||||
void insert_virtual_irq(Virtual_context & c, unsigned irq);
|
||||
};
|
||||
|
||||
#endif /* _CORE__SPEC__ARM__VIRTUALIZATION__GICV2_H_ */
|
56
repos/base-hw/src/core/spec/arm/virtualization/gicv3.h
Normal file
56
repos/base-hw/src/core/spec/arm/virtualization/gicv3.h
Normal file
@ -0,0 +1,56 @@
|
||||
/*
|
||||
* \brief Gicv2 with virtualization extensions
|
||||
* \author Stefan Kalkowski
|
||||
* \date 2019-09-02
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2019 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU Affero General Public License version 3.
|
||||
*/
|
||||
|
||||
#ifndef _CORE__SPEC__ARM__VIRTUALIZATION__GICV3_H_
|
||||
#define _CORE__SPEC__ARM__VIRTUALIZATION__GICV3_H_
|
||||
|
||||
#include <hw/spec/arm/gicv3.h>
|
||||
|
||||
namespace Board { class Pic; };
|
||||
|
||||
class Board::Pic : public Hw::Pic
|
||||
{
|
||||
public:
|
||||
|
||||
struct Virtual_context {
|
||||
Genode::uint64_t lr { 0 };
|
||||
Genode::uint32_t apr { 0 };
|
||||
Genode::uint32_t vmcr { 0x4c0000 };
|
||||
Genode::uint32_t misr { 0 };
|
||||
Genode::uint32_t eisr { 0 };
|
||||
Genode::uint32_t elrsr { 0xffffffff };
|
||||
};
|
||||
|
||||
bool ack_virtual_irq(Virtual_context & c)
|
||||
{
|
||||
if (!(c.eisr & 1)) return false;
|
||||
|
||||
c.lr = 0;
|
||||
c.elrsr = 0xffffffff;
|
||||
c.misr = 0;
|
||||
c.eisr = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
void insert_virtual_irq(Virtual_context & c, unsigned irq)
|
||||
{
|
||||
enum { SPURIOUS = 1023 };
|
||||
|
||||
if (irq == SPURIOUS || c.lr) return;
|
||||
|
||||
c.lr = irq | 1ULL << 41 | 1ULL << 60 | 1ULL << 62;
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* _CORE__SPEC__ARM__VIRTUALIZATION__GICV3_H_ */
|
||||
|
@ -37,9 +37,19 @@ void Genode::platform_add_local_services(Rpc_entrypoint &ep,
|
||||
using namespace Genode;
|
||||
|
||||
map_local(Platform::core_phys_addr((addr_t)&hypervisor_exception_vector),
|
||||
Hw::Mm::hypervisor_exception_vector().base, 1,
|
||||
Hw::Mm::hypervisor_exception_vector().base,
|
||||
Hw::Mm::hypervisor_exception_vector().size / get_page_size(),
|
||||
Hw::PAGE_FLAGS_KERN_TEXT);
|
||||
|
||||
void * stack = nullptr;
|
||||
assert(platform().ram_alloc().alloc_aligned(Hw::Mm::hypervisor_stack().size,
|
||||
(void**)&stack,
|
||||
get_page_size_log2()).ok());
|
||||
map_local((addr_t)stack,
|
||||
Hw::Mm::hypervisor_stack().base,
|
||||
Hw::Mm::hypervisor_stack().size / get_page_size(),
|
||||
Hw::PAGE_FLAGS_KERN_DATA);
|
||||
|
||||
static Vm_root vm_root(ep, sh, core_env().ram_allocator(),
|
||||
core_env().local_rm(), trace_sources);
|
||||
static Core_service<Vm_session_component> vm_service(services, vm_root);
|
||||
|
@ -16,8 +16,9 @@
|
||||
|
||||
/* core includes */
|
||||
#include <kernel/core_interface.h>
|
||||
#include <spec/arm/virtualization/vm_session_component.h>
|
||||
#include <vm_session_component.h>
|
||||
#include <platform.h>
|
||||
#include <cpu_thread_component.h>
|
||||
#include <core_env.h>
|
||||
|
||||
using namespace Genode;
|
||||
@ -26,14 +27,6 @@ static Core_mem_allocator & cma() {
|
||||
return static_cast<Core_mem_allocator&>(platform().core_mem_alloc()); }
|
||||
|
||||
|
||||
void Vm_session_component::_exception_handler(Signal_context_capability handler, Vcpu_id)
|
||||
{
|
||||
if (!_kobj.create(_ds_addr, Capability_space::capid(handler),
|
||||
cma().phys_addr(&_table)))
|
||||
Genode::warning("Cannot instantiate vm kernel object, invalid signal context?");
|
||||
}
|
||||
|
||||
|
||||
void Vm_session_component::_attach(addr_t phys_addr, addr_t vm_addr, size_t size)
|
||||
{
|
||||
using namespace Hw;
|
||||
@ -78,8 +71,8 @@ void * Vm_session_component::_alloc_table()
|
||||
{
|
||||
void * table;
|
||||
/* get some aligned space for the translation table */
|
||||
if (!cma().alloc_aligned(sizeof(Table), (void**)&table,
|
||||
Table::ALIGNM_LOG2).ok()) {
|
||||
if (!cma().alloc_aligned(sizeof(Board::Vm_page_table), (void**)&table,
|
||||
Board::Vm_page_table::ALIGNM_LOG2).ok()) {
|
||||
error("failed to allocate kernel object");
|
||||
throw Insufficient_ram_quota();
|
||||
}
|
||||
@ -101,19 +94,10 @@ Vm_session_component::Vm_session_component(Rpc_entrypoint &ds_ep,
|
||||
_constrained_md_ram_alloc(ram_alloc, _ram_quota_guard(), _cap_quota_guard()),
|
||||
_sliced_heap(_constrained_md_ram_alloc, region_map),
|
||||
_region_map(region_map),
|
||||
_table(*construct_at<Table>(_alloc_table())),
|
||||
_table_array(*(new (cma()) Array([this] (void * virt) {
|
||||
_table(*construct_at<Board::Vm_page_table>(_alloc_table())),
|
||||
_table_array(*(new (cma()) Board::Vm_page_table_array([this] (void * virt) {
|
||||
return (addr_t)cma().phys_addr(virt);})))
|
||||
{
|
||||
_ds_cap = _constrained_md_ram_alloc.alloc(_ds_size(), Genode::Cache_attribute::UNCACHED);
|
||||
|
||||
try {
|
||||
_ds_addr = region_map.attach(_ds_cap);
|
||||
} catch (...) {
|
||||
_constrained_md_ram_alloc.free(_ds_cap);
|
||||
throw;
|
||||
}
|
||||
|
||||
/* configure managed VM area */
|
||||
_map.add_range(0, 0UL - 0x1000);
|
||||
_map.add_range(0UL - 0x1000, 0x1000);
|
||||
@ -133,9 +117,12 @@ Vm_session_component::~Vm_session_component()
|
||||
}
|
||||
|
||||
/* free region in allocator */
|
||||
if (_ds_cap.valid()) {
|
||||
_region_map.detach(_ds_addr);
|
||||
_constrained_md_ram_alloc.free(_ds_cap);
|
||||
for (unsigned i = 0; i < _id_alloc; i++) {
|
||||
Vcpu & vcpu = _vcpus[i];
|
||||
if (vcpu.ds_cap.valid()) {
|
||||
_region_map.detach(vcpu.ds_addr);
|
||||
_constrained_md_ram_alloc.free(vcpu.ds_cap);
|
||||
}
|
||||
}
|
||||
|
||||
/* free guest-to-host page tables */
|
||||
|
@ -1,40 +0,0 @@
|
||||
/*
|
||||
* \brief VM session component for 'base-hw'
|
||||
* \author Stefan Kalkowski
|
||||
* \date 2012-10-08
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2012-2017 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU Affero General Public License version 3.
|
||||
*/
|
||||
|
||||
#include <vm_session_component.h>
|
||||
#include <platform.h>
|
||||
#include <core_env.h>
|
||||
|
||||
using namespace Genode;
|
||||
|
||||
|
||||
addr_t Vm_session_component::_alloc_ds()
|
||||
{
|
||||
addr_t addr;
|
||||
if (platform().ram_alloc().alloc_aligned(_ds_size(), (void**)&addr,
|
||||
get_page_size_log2()).error())
|
||||
throw Insufficient_ram_quota();
|
||||
return addr;
|
||||
}
|
||||
|
||||
|
||||
void Vm_session_component::_run(Vcpu_id)
|
||||
{
|
||||
if (_kobj.constructed()) Kernel::run_vm(*_kobj);
|
||||
}
|
||||
|
||||
|
||||
void Vm_session_component::_pause(Vcpu_id)
|
||||
{
|
||||
if (_kobj.constructed()) Kernel::pause_vm(*_kobj);
|
||||
}
|
@ -20,13 +20,16 @@
|
||||
using namespace Kernel;
|
||||
|
||||
|
||||
Kernel::Vm::Vm(void * const state,
|
||||
Kernel::Signal_context * const context,
|
||||
void * const /* table */)
|
||||
Kernel::Vm::Vm(unsigned,
|
||||
Genode::Vm_state & state,
|
||||
Kernel::Signal_context & context,
|
||||
void * const)
|
||||
:
|
||||
Cpu_job(Cpu_priority::MIN, 0),
|
||||
_state((Genode::Vm_state *)state),
|
||||
_context(context), _table(0)
|
||||
_state(state),
|
||||
_context(context),
|
||||
_table(0),
|
||||
_vcpu_context(cpu_pool().primary_cpu())
|
||||
{
|
||||
affinity(cpu_pool().primary_cpu());
|
||||
}
|
||||
@ -37,17 +40,17 @@ Kernel::Vm::~Vm() {}
|
||||
|
||||
void Vm::exception(Cpu & cpu)
|
||||
{
|
||||
switch(_state->cpu_exception) {
|
||||
case Genode::Cpu_state::INTERRUPT_REQUEST:
|
||||
switch(_state.cpu_exception) {
|
||||
case Genode::Cpu_state::INTERRUPT_REQUEST: [[fallthrough]]
|
||||
case Genode::Cpu_state::FAST_INTERRUPT_REQUEST:
|
||||
_interrupt(cpu.id());
|
||||
return;
|
||||
case Genode::Cpu_state::DATA_ABORT:
|
||||
_state->dfar = Cpu::Dfar::read();
|
||||
_state.dfar = Cpu::Dfar::read();
|
||||
[[fallthrough]];
|
||||
default:
|
||||
pause();
|
||||
_context->submit(1);
|
||||
_context.submit(1);
|
||||
}
|
||||
}
|
||||
|
||||
@ -55,22 +58,21 @@ void Vm::exception(Cpu & cpu)
|
||||
bool secure_irq(unsigned const i);
|
||||
|
||||
|
||||
extern "C" void monitor_mode_enter_normal_world(Cpu::Context*, void*);
|
||||
extern "C" void monitor_mode_enter_normal_world(Genode::Vm_state&, void*);
|
||||
extern void * kernel_stack;
|
||||
|
||||
|
||||
void Vm::proceed(Cpu & cpu)
|
||||
{
|
||||
unsigned const irq = _state->irq_injection;
|
||||
unsigned const irq = _state.irq_injection;
|
||||
if (irq) {
|
||||
if (cpu.pic().secure(irq)) {
|
||||
Genode::raw("Refuse to inject secure IRQ into VM");
|
||||
} else {
|
||||
cpu.pic().trigger(irq);
|
||||
_state->irq_injection = 0;
|
||||
_state.irq_injection = 0;
|
||||
}
|
||||
}
|
||||
|
||||
monitor_mode_enter_normal_world(reinterpret_cast<Cpu::Context*>(_state),
|
||||
(void*) cpu.stack_start());
|
||||
monitor_mode_enter_normal_world(_state, (void*) cpu.stack_start());
|
||||
}
|
||||
|
@ -11,23 +11,44 @@
|
||||
* under the terms of the GNU Affero General Public License version 3.
|
||||
*/
|
||||
|
||||
#include <kernel/core_interface.h>
|
||||
/* Genode includes */
|
||||
#include <util/construct_at.h>
|
||||
|
||||
/* core includes */
|
||||
#include <vm_session_component.h>
|
||||
#include <core_env.h>
|
||||
#include <platform.h>
|
||||
|
||||
using namespace Genode;
|
||||
|
||||
|
||||
void Vm_session_component::_exception_handler(Signal_context_capability handler, Vcpu_id)
|
||||
static Board::Vm_page_table_array & dummy_array()
|
||||
{
|
||||
if (!_kobj.create(_ds_addr, Capability_space::capid(handler), nullptr)) {
|
||||
warning("Cannot instantiate vm kernel object twice,"
|
||||
"or invalid signal context?");
|
||||
}
|
||||
static Board::Vm_page_table_array a;
|
||||
return a;
|
||||
}
|
||||
|
||||
|
||||
Vm_session_component::Vm_session_component(Rpc_entrypoint &ds_ep,
|
||||
void Vm_session_component::_attach(addr_t, addr_t, size_t) { }
|
||||
|
||||
|
||||
void Vm_session_component::_attach_vm_memory(Dataspace_component &,
|
||||
addr_t const,
|
||||
Attach_attr const) { }
|
||||
|
||||
|
||||
void Vm_session_component::attach_pic(addr_t) { }
|
||||
|
||||
|
||||
void Vm_session_component::_detach_vm_memory(addr_t, size_t) { }
|
||||
|
||||
|
||||
void * Vm_session_component::_alloc_table()
|
||||
{
|
||||
static Board::Vm_page_table table;
|
||||
return (void*) &table;
|
||||
}
|
||||
|
||||
|
||||
Vm_session_component::Vm_session_component(Rpc_entrypoint &ep,
|
||||
Resources resources,
|
||||
Label const &,
|
||||
Diag,
|
||||
@ -37,26 +58,32 @@ Vm_session_component::Vm_session_component(Rpc_entrypoint &ds_ep,
|
||||
:
|
||||
Ram_quota_guard(resources.ram_quota),
|
||||
Cap_quota_guard(resources.cap_quota),
|
||||
_ds_ep(&ds_ep),
|
||||
_ep(ep),
|
||||
_constrained_md_ram_alloc(ram_alloc, _ram_quota_guard(), _cap_quota_guard()),
|
||||
_region_map(region_map)
|
||||
{
|
||||
_ds_cap = _constrained_md_ram_alloc.alloc(_ds_size(), Genode::Cache_attribute::UNCACHED);
|
||||
|
||||
try {
|
||||
_ds_addr = region_map.attach(_ds_cap);
|
||||
} catch (...) {
|
||||
_constrained_md_ram_alloc.free(_ds_cap);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
_sliced_heap(_constrained_md_ram_alloc, region_map),
|
||||
_region_map(region_map),
|
||||
_table(*construct_at<Board::Vm_page_table>(_alloc_table())),
|
||||
_table_array(dummy_array()) { }
|
||||
|
||||
|
||||
Vm_session_component::~Vm_session_component()
|
||||
{
|
||||
/* detach all regions */
|
||||
while (true) {
|
||||
addr_t out_addr = 0;
|
||||
|
||||
if (!_map.any_block_addr(&out_addr))
|
||||
break;
|
||||
|
||||
detach(out_addr);
|
||||
}
|
||||
|
||||
/* free region in allocator */
|
||||
if (_ds_cap.valid()) {
|
||||
_region_map.detach(_ds_addr);
|
||||
_constrained_md_ram_alloc.free(_ds_cap);
|
||||
for (unsigned i = 0; i < _id_alloc; i++) {
|
||||
Vcpu & vcpu = _vcpus[i];
|
||||
if (vcpu.ds_cap.valid()) {
|
||||
_region_map.detach(vcpu.ds_addr);
|
||||
_constrained_md_ram_alloc.free(vcpu.ds_cap);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,95 +0,0 @@
|
||||
/*
|
||||
* \brief Core-specific instance of the VM session interface
|
||||
* \author Stefan Kalkowski
|
||||
* \date 2012-10-08
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2012-2017 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU Affero General Public License version 3.
|
||||
*/
|
||||
|
||||
#ifndef _CORE__SPEC__ARM_V7__TRUSTZONE__VM_SESSION_COMPONENT_H_
|
||||
#define _CORE__SPEC__ARM_V7__TRUSTZONE__VM_SESSION_COMPONENT_H_
|
||||
|
||||
/* Genode includes */
|
||||
#include <base/allocator.h>
|
||||
#include <base/session_object.h>
|
||||
#include <vm_session/vm_session.h>
|
||||
#include <dataspace/capability.h>
|
||||
#include <trace/source_registry.h>
|
||||
|
||||
/* Core includes */
|
||||
#include <object.h>
|
||||
#include <kernel/vm.h>
|
||||
|
||||
namespace Genode {
|
||||
class Vm_session_component;
|
||||
}
|
||||
|
||||
class Genode::Vm_session_component
|
||||
:
|
||||
private Ram_quota_guard,
|
||||
private Cap_quota_guard,
|
||||
public Rpc_object<Vm_session, Vm_session_component>
|
||||
{
|
||||
private:
|
||||
|
||||
/*
|
||||
* Noncopyable
|
||||
*/
|
||||
Vm_session_component(Vm_session_component const &);
|
||||
Vm_session_component &operator = (Vm_session_component const &);
|
||||
|
||||
Rpc_entrypoint *_ds_ep;
|
||||
Constrained_ram_allocator _constrained_md_ram_alloc;
|
||||
Region_map &_region_map;
|
||||
Ram_dataspace_capability _ds_cap { };
|
||||
Region_map::Local_addr _ds_addr { 0 };
|
||||
Kernel_object<Kernel::Vm> _kobj {};
|
||||
|
||||
static size_t _ds_size() {
|
||||
return align_addr(sizeof(Cpu_state_modes),
|
||||
get_page_size_log2()); }
|
||||
|
||||
addr_t _alloc_ds();
|
||||
|
||||
protected:
|
||||
|
||||
Ram_quota_guard &_ram_quota_guard() { return *this; }
|
||||
Cap_quota_guard &_cap_quota_guard() { return *this; }
|
||||
|
||||
public:
|
||||
|
||||
using Ram_quota_guard::upgrade;
|
||||
using Cap_quota_guard::upgrade;
|
||||
using Rpc_object<Vm_session, Vm_session_component>::cap;
|
||||
|
||||
Vm_session_component(Rpc_entrypoint &, Resources, Label const &,
|
||||
Diag, Ram_allocator &ram, Region_map &,
|
||||
unsigned priority, Trace::Source_registry &);
|
||||
~Vm_session_component();
|
||||
|
||||
/**************************
|
||||
** Vm session interface **
|
||||
**************************/
|
||||
|
||||
Dataspace_capability _cpu_state(Vcpu_id) { return _ds_cap; }
|
||||
void _exception_handler(Signal_context_capability handler, Vcpu_id);
|
||||
void _run(Vcpu_id);
|
||||
void _pause(Vcpu_id);
|
||||
|
||||
void attach(Dataspace_capability, addr_t, Attach_attr) override {
|
||||
warning("Not implemented for TrustZone case"); }
|
||||
|
||||
void attach_pic(addr_t /* vm_addr */) override {
|
||||
warning("Not implemented for TrustZone case"); }
|
||||
|
||||
void detach(addr_t /* vm_addr */, size_t /* size */) override {
|
||||
warning("Not implemented for TrustZone case"); }
|
||||
unsigned _create_vcpu(Thread_capability) { return 0; }
|
||||
};
|
||||
|
||||
#endif /* _CORE__SPEC__ARM_V7__TRUSTZONE__VM_SESSION_COMPONENT_H_ */
|
@ -41,7 +41,7 @@ using namespace Kernel;
|
||||
|
||||
extern "C" void kernel();
|
||||
extern void * kernel_stack;
|
||||
extern "C" void hypervisor_enter_vm(Cpu::Context*);
|
||||
extern "C" void hypervisor_enter_vm(Genode::Vm_state&);
|
||||
|
||||
struct Host_context {
|
||||
addr_t sp;
|
||||
@ -103,18 +103,18 @@ struct Kernel::Virtual_pic : Genode::Mmio
|
||||
/**
|
||||
* Save the virtual interrupt controller state to VM state
|
||||
*/
|
||||
static void save (Genode::Vm_state *s)
|
||||
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> >();
|
||||
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);
|
||||
@ -123,17 +123,17 @@ struct Kernel::Virtual_pic : Genode::Mmio
|
||||
/**
|
||||
* Load the virtual interrupt controller state from VM state
|
||||
*/
|
||||
static void load (Genode::Vm_state *s)
|
||||
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]);
|
||||
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]);
|
||||
}
|
||||
};
|
||||
|
||||
@ -166,25 +166,25 @@ struct Kernel::Virtual_timer
|
||||
/**
|
||||
* Save the virtual timer state to VM state
|
||||
*/
|
||||
static void save(Genode::Vm_state *s)
|
||||
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));
|
||||
"=r" (s.timer_val), "=r" (s.timer_ctrl));
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the virtual timer state from VM state
|
||||
*/
|
||||
static void load(Genode::Vm_state *s)
|
||||
static void load(Genode::Vm_state &s)
|
||||
{
|
||||
if (s->timer_irq) timer().irq.enable();
|
||||
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));
|
||||
"r" (s.timer_val), "r" (s.timer_ctrl));
|
||||
}
|
||||
};
|
||||
|
||||
@ -205,14 +205,16 @@ static Vmid_allocator &alloc()
|
||||
}
|
||||
|
||||
|
||||
Kernel::Vm::Vm(void * const state,
|
||||
Kernel::Signal_context * const context,
|
||||
Kernel::Vm::Vm(unsigned, /* FIXME: smp support */
|
||||
Genode::Vm_state & state,
|
||||
Kernel::Signal_context & context,
|
||||
void * const table)
|
||||
: Cpu_job(Cpu_priority::MIN, 0),
|
||||
_id(alloc().alloc()),
|
||||
_state((Genode::Vm_state *)state),
|
||||
_state(state),
|
||||
_context(context),
|
||||
_table(table)
|
||||
_table(table),
|
||||
_vcpu_context(cpu_pool().primary_cpu())
|
||||
{
|
||||
affinity(cpu_pool().primary_cpu());
|
||||
Virtual_pic::pic().irq.enable();
|
||||
@ -235,15 +237,15 @@ void Kernel::Vm::exception(Cpu & cpu)
|
||||
{
|
||||
Virtual_timer::save(_state);
|
||||
|
||||
switch(_state->cpu_exception) {
|
||||
switch(_state.cpu_exception) {
|
||||
case Genode::Cpu_state::INTERRUPT_REQUEST:
|
||||
case Genode::Cpu_state::FAST_INTERRUPT_REQUEST:
|
||||
_state->gic_irq = Board::VT_MAINTAINANCE_IRQ;
|
||||
_state.gic_irq = Board::VT_MAINTAINANCE_IRQ;
|
||||
_interrupt(cpu.id());
|
||||
break;
|
||||
default:
|
||||
pause();
|
||||
_context->submit(1);
|
||||
_context.submit(1);
|
||||
}
|
||||
|
||||
Virtual_pic::save(_state);
|
||||
@ -256,27 +258,27 @@ void Kernel::Vm::proceed(Cpu &)
|
||||
/*
|
||||
* the following values have to be enforced by the hypervisor
|
||||
*/
|
||||
_state->vttbr = Cpu::Ttbr_64bit::Ba::masked((Cpu::Ttbr_64bit::access_t)_table);
|
||||
Cpu::Ttbr_64bit::Asid::set(_state->vttbr, _id);
|
||||
_state.vttbr = Cpu::Ttbr_64bit::Ba::masked((Cpu::Ttbr_64bit::access_t)_table);
|
||||
Cpu::Ttbr_64bit::Asid::set(_state.vttbr, _id);
|
||||
|
||||
/*
|
||||
* use the following report fields not needed for loading the context
|
||||
* 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();
|
||||
_state.hsr = Cpu::Hstr::init();
|
||||
_state.hpfar = Cpu::Hcr::init();
|
||||
|
||||
Virtual_pic::load(_state);
|
||||
Virtual_timer::load(_state);
|
||||
|
||||
hypervisor_enter_vm(reinterpret_cast<Cpu::Context*>(_state));
|
||||
hypervisor_enter_vm(_state);
|
||||
}
|
||||
|
||||
|
||||
void Vm::inject_irq(unsigned irq)
|
||||
{
|
||||
_state->gic_irq = irq;
|
||||
_state.gic_irq = irq;
|
||||
pause();
|
||||
_context->submit(1);
|
||||
_context.submit(1);
|
||||
}
|
||||
|
@ -0,0 +1,369 @@
|
||||
/*
|
||||
* \brief Transition between virtual/host mode
|
||||
* \author Alexander Boettcher
|
||||
* \author Stefan Kalkowski
|
||||
* \date 2019-06-25
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2019 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU Affero General Public License version 3.
|
||||
*/
|
||||
|
||||
|
||||
.section .text
|
||||
|
||||
/*
|
||||
* see D1.10.2 Exception vectors chapter
|
||||
*/
|
||||
.p2align 12
|
||||
.global hypervisor_exception_vector
|
||||
hypervisor_exception_vector:
|
||||
.rept 16
|
||||
add sp, sp, #-16 /* push x0, x1 to stack */
|
||||
stp x0, x1, [sp]
|
||||
mrs x1, hcr_el2 /* read HCR register */
|
||||
tst x1, #1 /* check VM bit */
|
||||
beq _host_to_vm /* if VM bit is not set, switch to VM */
|
||||
ldr x0, [sp, #32] /* otherwise, load vm_state pointer */
|
||||
adr x1, . /* hold exception vector offset in x1 */
|
||||
and x1, x1, #0xf80
|
||||
b _vm_to_host
|
||||
.balign 128
|
||||
.endr
|
||||
|
||||
_host_to_vm:
|
||||
|
||||
add sp, sp, #-16 /* push arg2 (vm pic state) to stack */
|
||||
str x2, [sp]
|
||||
|
||||
msr vttbr_el2, x3 /* stage2 table pointer was arg3 */
|
||||
|
||||
add x0, x0, #31*8 /* skip x0...x30, loaded later */
|
||||
|
||||
ldr x1, [x0], #1*8 /* sp */
|
||||
ldp x2, x3, [x0], #2*8 /* ip, pstate */
|
||||
msr sp_el0, x1
|
||||
msr elr_el2, x2
|
||||
msr spsr_el2, x3
|
||||
|
||||
add x0, x0, #2*8 /* skip exception_type and esr_el2 */
|
||||
|
||||
/** FPU register **/
|
||||
ldp q0, q1, [x0], #2*16
|
||||
ldp q2, q3, [x0], #2*16
|
||||
ldp q4, q5, [x0], #2*16
|
||||
ldp q6, q7, [x0], #2*16
|
||||
ldp q8, q9, [x0], #2*16
|
||||
ldp q10, q11, [x0], #2*16
|
||||
ldp q12, q13, [x0], #2*16
|
||||
ldp q14, q15, [x0], #2*16
|
||||
ldp q16, q17, [x0], #2*16
|
||||
ldp q18, q19, [x0], #2*16
|
||||
ldp q20, q21, [x0], #2*16
|
||||
ldp q22, q23, [x0], #2*16
|
||||
ldp q24, q25, [x0], #2*16
|
||||
ldp q26, q27, [x0], #2*16
|
||||
ldp q28, q29, [x0], #2*16
|
||||
ldp q30, q31, [x0], #2*16
|
||||
ldp w1, w2, [x0], #2*4
|
||||
msr fpcr, x1
|
||||
msr fpsr, x2
|
||||
|
||||
/** system register **/
|
||||
ldp x1, x2, [x0], #2*8 /* elr_el1, sp_el1 */
|
||||
ldp w3, w4, [x0], #2*4 /* spsr_el1, esr_el1 */
|
||||
ldp x5, x6, [x0], #2*8 /* sctlr_el1, actlr_el1 */
|
||||
ldr x7, [x0], #8 /* vbar_el1 */
|
||||
ldp w8, w9, [x0], #2*4 /* cpacr_el1, afsr0_el1 */
|
||||
ldp w10, w11, [x0], #2*4 /* afsr1_el1, contextidr_el1 */
|
||||
ldp x12, x13, [x0], #2*8 /* ttbr0_el1, ttbr1_el1 */
|
||||
ldp x14, x15, [x0], #2*8 /* tcr_el1, mair_el1 */
|
||||
ldp x16, x17, [x0], #2*8 /* amair_el1, far_el1 */
|
||||
ldp x18, x19, [x0], #2*8 /* par_el1, tpidrro_el0 */
|
||||
ldp x20, x21, [x0], #2*8 /* tpidr_el0, tpidr_el1 */
|
||||
ldr x22, [x0], #3*8 /* vmpidr_el2 */
|
||||
msr elr_el1, x1
|
||||
msr sp_el1, x2
|
||||
msr spsr_el1, x3
|
||||
msr esr_el1, x4
|
||||
msr sctlr_el1, x5
|
||||
msr actlr_el1, x6
|
||||
msr vbar_el1, x7
|
||||
msr cpacr_el1, x8
|
||||
msr afsr0_el1, x9
|
||||
msr afsr1_el1, x10
|
||||
msr contextidr_el1, x11
|
||||
msr ttbr0_el1, x12
|
||||
msr ttbr1_el1, x13
|
||||
msr tcr_el1, x14
|
||||
msr mair_el1, x15
|
||||
msr amair_el1, x16
|
||||
msr far_el1, x17
|
||||
msr par_el1, x18
|
||||
msr tpidrro_el0, x19
|
||||
msr tpidr_el0, x20
|
||||
msr tpidr_el1, x21
|
||||
msr vmpidr_el2, x22
|
||||
|
||||
|
||||
/**********************
|
||||
** load timer state **
|
||||
**********************/
|
||||
|
||||
ldp x22, x23, [x0], #2*8 /* timer.offset, timer.compare */
|
||||
ldp w24, w25, [x0] /* timer.control, kcontrol */
|
||||
msr cntvoff_el2, x22
|
||||
msr cntv_cval_el0, x23
|
||||
msr cntv_ctl_el0, x24
|
||||
msr cntkctl_el1, x25
|
||||
|
||||
mov x0, #0b100
|
||||
msr cnthctl_el2, x0
|
||||
|
||||
|
||||
/************************
|
||||
** debug/perfm access **
|
||||
************************/
|
||||
|
||||
mrs x0, mdcr_el2
|
||||
movz x1, #0b111101100000
|
||||
orr x0, x0, x1
|
||||
msr mdcr_el2, x0
|
||||
|
||||
|
||||
/**********************
|
||||
** Load pic context **
|
||||
**********************/
|
||||
|
||||
ldr x0, [sp]
|
||||
|
||||
ldr x1, [x0], #8 /* lr0 */
|
||||
ldp w2, w3, [x0] /* apr, vmcr */
|
||||
|
||||
msr S3_4_C12_C12_0, x1
|
||||
msr S3_4_C12_C9_0, x2
|
||||
msr S3_4_C12_C11_7, x3
|
||||
|
||||
mov x0, #1 /* enable PIC virtualization */
|
||||
msr S3_4_C12_C11_0, x0
|
||||
|
||||
/** enable VM mode **/
|
||||
movz x1, #0b1110000000111001
|
||||
movk x1, #0b10111, lsl 16
|
||||
mrs x0, hcr_el2
|
||||
orr x0, x0, x1
|
||||
msr hcr_el2, x0
|
||||
|
||||
ldr x30, [sp, #16] /* load head of Vm_state again */
|
||||
|
||||
/** general-purpose registers **/
|
||||
ldp x0, x1, [x30], #2*8
|
||||
ldp x2, x3, [x30], #2*8
|
||||
ldp x4, x5, [x30], #2*8
|
||||
ldp x6, x7, [x30], #2*8
|
||||
ldp x8, x9, [x30], #2*8
|
||||
ldp x10, x11, [x30], #2*8
|
||||
ldp x12, x13, [x30], #2*8
|
||||
ldp x14, x15, [x30], #2*8
|
||||
ldp x16, x17, [x30], #2*8
|
||||
ldp x18, x19, [x30], #2*8
|
||||
ldp x20, x21, [x30], #2*8
|
||||
ldp x22, x23, [x30], #2*8
|
||||
ldp x24, x25, [x30], #2*8
|
||||
ldp x26, x27, [x30], #2*8
|
||||
ldp x28, x29, [x30], #2*8
|
||||
ldr x30, [x30]
|
||||
|
||||
eret
|
||||
|
||||
_vm_to_host:
|
||||
|
||||
/*********************
|
||||
** Save vm context **
|
||||
*********************/
|
||||
|
||||
/** general-purpose register **/
|
||||
add x0, x0, #2*8 /* skip x0 and x1 for now */
|
||||
stp x2, x3, [x0], #2*8
|
||||
stp x4, x5, [x0], #2*8
|
||||
stp x6, x7, [x0], #2*8
|
||||
stp x8, x9, [x0], #2*8
|
||||
stp x10, x11, [x0], #2*8
|
||||
stp x12, x13, [x0], #2*8
|
||||
stp x14, x15, [x0], #2*8
|
||||
stp x16, x17, [x0], #2*8
|
||||
stp x18, x19, [x0], #2*8
|
||||
stp x20, x21, [x0], #2*8
|
||||
stp x22, x23, [x0], #2*8
|
||||
stp x24, x25, [x0], #2*8
|
||||
stp x26, x27, [x0], #2*8
|
||||
stp x28, x29, [x0], #2*8
|
||||
str x30, [x0], #1*8
|
||||
|
||||
/** save sp, ip, pstate and exception reason **/
|
||||
mrs x2, sp_el0
|
||||
mrs x3, elr_el2
|
||||
mrs x4, spsr_el2
|
||||
mrs x5, esr_el2
|
||||
stp x2, x3, [x0], #2*8
|
||||
stp x4, x1, [x0], #2*8
|
||||
str x5, [x0], #1*8
|
||||
|
||||
/** fpu registers **/
|
||||
stp q0, q1, [x0], #32
|
||||
stp q2, q3, [x0], #32
|
||||
stp q4, q5, [x0], #32
|
||||
stp q6, q7, [x0], #32
|
||||
stp q8, q9, [x0], #32
|
||||
stp q10, q11, [x0], #32
|
||||
stp q12, q13, [x0], #32
|
||||
stp q14, q15, [x0], #32
|
||||
stp q16, q17, [x0], #32
|
||||
stp q18, q19, [x0], #32
|
||||
stp q20, q21, [x0], #32
|
||||
stp q22, q23, [x0], #32
|
||||
stp q24, q25, [x0], #32
|
||||
stp q26, q27, [x0], #32
|
||||
stp q28, q29, [x0], #32
|
||||
stp q30, q31, [x0], #32
|
||||
|
||||
mrs x1, fpcr
|
||||
mrs x2, fpsr
|
||||
mrs x3, elr_el1
|
||||
mrs x4, sp_el1
|
||||
mrs x5, spsr_el1
|
||||
mrs x6, esr_el1
|
||||
mrs x7, sctlr_el1
|
||||
mrs x8, actlr_el1
|
||||
mrs x9, vbar_el1
|
||||
mrs x10, cpacr_el1
|
||||
mrs x11, afsr0_el1
|
||||
mrs x12, afsr1_el1
|
||||
mrs x13, contextidr_el1
|
||||
mrs x14, ttbr0_el1
|
||||
mrs x15, ttbr1_el1
|
||||
mrs x16, tcr_el1
|
||||
mrs x17, mair_el1
|
||||
mrs x18, amair_el1
|
||||
mrs x19, far_el1
|
||||
mrs x20, par_el1
|
||||
mrs x21, tpidrro_el0
|
||||
mrs x22, tpidr_el0
|
||||
mrs x23, tpidr_el1
|
||||
mrs x24, far_el2
|
||||
mrs x25, hpfar_el2
|
||||
stp w1, w2, [x0], #2*4
|
||||
stp x3, x4, [x0], #2*8
|
||||
stp w5, w6, [x0], #2*4
|
||||
stp x7, x8, [x0], #2*8
|
||||
str x9, [x0], #1*8
|
||||
stp w10, w11, [x0], #2*4
|
||||
stp w12, w13, [x0], #2*4
|
||||
stp x14, x15, [x0], #2*8
|
||||
stp x16, x17, [x0], #2*8
|
||||
stp x18, x19, [x0], #2*8
|
||||
stp x20, x21, [x0], #2*8
|
||||
stp x22, x23, [x0], #3*8
|
||||
stp x24, x25, [x0], #2*8
|
||||
|
||||
|
||||
/**********************
|
||||
** save timer state **
|
||||
**********************/
|
||||
|
||||
mrs x26, cntvoff_el2
|
||||
mrs x27, cntv_cval_el0
|
||||
mrs x28, cntv_ctl_el0
|
||||
mrs x29, cntkctl_el1
|
||||
stp x26, x27, [x0], #2*8
|
||||
stp w28, w29, [x0]
|
||||
|
||||
mov x0, #0b111
|
||||
msr cnthctl_el2, x0
|
||||
|
||||
|
||||
ldp x0, x1, [sp], #2*8 /* pop x0, x1 from stack */
|
||||
ldr x29, [sp], #2*8 /* pop vm pic state from stack */
|
||||
ldp x2, x30, [sp], #2*8 /* pop vm, and host state from stack */
|
||||
stp x0, x1, [x2] /* save x0, x1 to vm state */
|
||||
|
||||
|
||||
/**********************
|
||||
** Save pic context **
|
||||
**********************/
|
||||
|
||||
mrs x10, S3_4_C12_C12_0
|
||||
mrs x11, S3_4_C12_C9_0
|
||||
mrs x12, S3_4_C12_C11_7
|
||||
mrs x13, S3_4_C12_C11_2
|
||||
mrs x14, S3_4_C12_C11_3
|
||||
mrs x15, S3_4_C12_C11_5
|
||||
|
||||
str x10, [x29], #8 /* lr0 */
|
||||
stp w11, w12, [x29], #2*4 /* apr, vmcr */
|
||||
stp w13, w14, [x29], #2*4 /* misr, eisr */
|
||||
str w15, [x29] /* elrsr */
|
||||
|
||||
msr S3_4_C12_C11_0, xzr /* disable PIC virtualization */
|
||||
|
||||
|
||||
/***********************
|
||||
** Load host context **
|
||||
***********************/
|
||||
|
||||
add x30, x30, #32*8 /* skip general-purpose regs, sp */
|
||||
ldp x0, x1, [x30] /* host state ip, and pstate */
|
||||
add x30, x30, #34*16 /* skip fpu regs etc. */
|
||||
ldp w2, w3, [x30], #4*4 /* fpcr and fpsr */
|
||||
ldr x4, [x30], #2*8 /* sp_el1 */
|
||||
ldp x5, x6, [x30], #2*8 /* sctlr_el1, actlr_el1 */
|
||||
ldr x7, [x30], #1*8 /* vbar_el1 */
|
||||
ldr w8, [x30], #4*4 /* cpacr_el1 */
|
||||
ldp x9, x10, [x30], #2*8 /* ttbr0_el1, ttbr1_el1 */
|
||||
ldp x11, x12, [x30], #2*8 /* tcr_el1, mair_el1 */
|
||||
ldr x13, [x30] /* amair_el1 */
|
||||
|
||||
msr elr_el2, x0
|
||||
msr spsr_el2, x1
|
||||
msr fpcr, x2
|
||||
msr fpsr, x3
|
||||
msr sp_el1, x4
|
||||
msr sctlr_el1, x5
|
||||
msr actlr_el1, x6
|
||||
msr vbar_el1, x7
|
||||
msr cpacr_el1, x8
|
||||
msr ttbr0_el1, x9
|
||||
msr ttbr1_el1, x10
|
||||
msr tcr_el1, x11
|
||||
msr mair_el1, x12
|
||||
msr amair_el1, x13
|
||||
mrs x0, mpidr_el1
|
||||
msr vmpidr_el2, x0
|
||||
|
||||
|
||||
/************************
|
||||
** debug/perfm access **
|
||||
************************/
|
||||
|
||||
mrs x0, mdcr_el2
|
||||
movz x1, #0b111101100000
|
||||
bic x0, x0, x1
|
||||
msr mdcr_el2, x0
|
||||
|
||||
/** disable VM mode **/
|
||||
movz x1, #0b1110000000111001
|
||||
movk x1, #0b10111, lsl 16
|
||||
mrs x0, hcr_el2
|
||||
msr vttbr_el2, xzr /* stage2 table pointer zeroing */
|
||||
bic x0, x0, x1
|
||||
msr hcr_el2, x0
|
||||
|
||||
eret
|
||||
|
||||
/* host kernel must jump to this point to switch to a vm */
|
||||
.global hypervisor_enter_vm
|
||||
hypervisor_enter_vm:
|
||||
hvc #0
|
215
repos/base-hw/src/core/spec/arm_v8/virtualization/kernel/vm.cc
Normal file
215
repos/base-hw/src/core/spec/arm_v8/virtualization/kernel/vm.cc
Normal file
@ -0,0 +1,215 @@
|
||||
/*
|
||||
* \brief Kernel backend for virtual machines
|
||||
* \author Stefan Kalkowski
|
||||
* \date 2015-02-10
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2015-2017 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU Affero General Public License version 3.
|
||||
*/
|
||||
|
||||
#include <base/log.h>
|
||||
#include <cpu/vm_state_virtualization.h>
|
||||
#include <util/mmio.h>
|
||||
|
||||
#include <hw/assert.h>
|
||||
#include <hw/spec/arm_64/memory_map.h>
|
||||
#include <map_local.h>
|
||||
#include <platform_pd.h>
|
||||
#include <kernel/cpu.h>
|
||||
#include <kernel/vm.h>
|
||||
|
||||
using Genode::addr_t;
|
||||
using Kernel::Cpu;
|
||||
using Kernel::Vm;
|
||||
|
||||
extern "C" void kernel();
|
||||
extern void * kernel_stack;
|
||||
extern "C" void hypervisor_enter_vm(addr_t vm, addr_t host,
|
||||
addr_t pic, addr_t guest_table);
|
||||
|
||||
|
||||
static Genode::Vm_state & host_context()
|
||||
{
|
||||
static Genode::Constructible<Genode::Vm_state> host_context;
|
||||
if (!host_context.constructed()) {
|
||||
host_context.construct();
|
||||
host_context->ip = (addr_t) &kernel;
|
||||
host_context->pstate = 0;
|
||||
Cpu::Spsr::Sp::set(host_context->pstate, 1); /* select non-el0 stack pointer */
|
||||
Cpu::Spsr::El::set(host_context->pstate, Cpu::Current_el::EL1);
|
||||
Cpu::Spsr::F::set(host_context->pstate, 1);
|
||||
Cpu::Spsr::I::set(host_context->pstate, 1);
|
||||
Cpu::Spsr::A::set(host_context->pstate, 1);
|
||||
Cpu::Spsr::D::set(host_context->pstate, 1);
|
||||
host_context->fpcr = Cpu::Fpcr::read();
|
||||
host_context->fpsr = 0;
|
||||
host_context->sctlr_el1 = Cpu::Sctlr_el1::read();
|
||||
host_context->actlr_el1 = Cpu::Actlr_el1::read();
|
||||
host_context->vbar_el1 = Cpu::Vbar_el1::read();
|
||||
host_context->cpacr_el1 = Cpu::Cpacr_el1::read();
|
||||
host_context->ttbr0_el1 = Cpu::Ttbr0_el1::read();
|
||||
host_context->ttbr1_el1 = Cpu::Ttbr1_el1::read();
|
||||
host_context->tcr_el1 = Cpu::Tcr_el1::read();
|
||||
host_context->mair_el1 = Cpu::Mair_el1::read();
|
||||
host_context->amair_el1 = Cpu::Amair_el1::read();
|
||||
}
|
||||
return *host_context;
|
||||
}
|
||||
|
||||
|
||||
Board::Vcpu_context::Vm_irq::Vm_irq(unsigned const irq, Cpu & cpu)
|
||||
: Kernel::Irq(irq, cpu.irq_pool())
|
||||
{ }
|
||||
|
||||
|
||||
void Board::Vcpu_context::Vm_irq::handle(Cpu &, Vm & vm, unsigned irq) {
|
||||
vm.inject_irq(irq); }
|
||||
|
||||
|
||||
void Board::Vcpu_context::Vm_irq::occurred()
|
||||
{
|
||||
Cpu & cpu = Kernel::cpu_pool().executing_cpu();
|
||||
Vm *vm = dynamic_cast<Vm*>(&cpu.scheduled_job());
|
||||
if (!vm) Genode::raw("VM interrupt while VM is not runnning!");
|
||||
else handle(cpu, *vm, _irq_nr);
|
||||
}
|
||||
|
||||
|
||||
Board::Vcpu_context::Pic_maintainance_irq::Pic_maintainance_irq(Cpu & cpu)
|
||||
: Board::Vcpu_context::Vm_irq(Board::VT_MAINTAINANCE_IRQ, cpu) {
|
||||
//FIXME Irq::enable only enables caller cpu
|
||||
cpu.pic().unmask(_irq_nr, cpu.id()); }
|
||||
|
||||
Board::Vcpu_context::Virtual_timer_irq::Virtual_timer_irq(Cpu & cpu)
|
||||
: irq(Board::VT_TIMER_IRQ, cpu) {}
|
||||
|
||||
|
||||
void Board::Vcpu_context::Virtual_timer_irq::enable() { irq.enable(); }
|
||||
|
||||
|
||||
void Board::Vcpu_context::Virtual_timer_irq::disable()
|
||||
{
|
||||
irq.disable();
|
||||
asm volatile("msr cntv_ctl_el0, xzr");
|
||||
asm volatile("msr cntkctl_el1, %0" :: "r" (0b11));
|
||||
}
|
||||
|
||||
|
||||
using Vmid_allocator = Genode::Bit_allocator<256>;
|
||||
|
||||
static Vmid_allocator &alloc()
|
||||
{
|
||||
static Vmid_allocator * allocator = nullptr;
|
||||
if (!allocator) {
|
||||
allocator = unmanaged_singleton<Vmid_allocator>();
|
||||
|
||||
/* reserve VM ID 0 for the hypervisor */
|
||||
unsigned id = allocator->alloc();
|
||||
assert (id == 0);
|
||||
}
|
||||
return *allocator;
|
||||
}
|
||||
|
||||
|
||||
Vm::Vm(unsigned cpu,
|
||||
Genode::Vm_state & state,
|
||||
Kernel::Signal_context & context,
|
||||
void * const table)
|
||||
: Cpu_job(Cpu_priority::MIN, 0),
|
||||
_id(alloc().alloc()),
|
||||
_state(state),
|
||||
_context(context),
|
||||
_table(table),
|
||||
_vcpu_context(cpu_pool().cpu(cpu))
|
||||
{
|
||||
affinity(cpu_pool().cpu(cpu));
|
||||
|
||||
_state.id_aa64isar0_el1 = Cpu::Id_aa64isar0_el1::read();
|
||||
_state.id_aa64isar1_el1 = Cpu::Id_aa64isar1_el1::read();
|
||||
_state.id_aa64mmfr0_el1 = Cpu::Id_aa64mmfr0_el1::read();
|
||||
_state.id_aa64mmfr1_el1 = Cpu::Id_aa64mmfr1_el1::read();
|
||||
_state.id_aa64mmfr2_el1 = /* FIXME Cpu::Id_aa64mmfr2_el1::read(); */ 0;
|
||||
|
||||
Cpu::Clidr_el1::access_t clidr = Cpu::Clidr_el1::read();
|
||||
for (unsigned i = 0; i < 7; i++) {
|
||||
unsigned level = clidr >> (i*3) & 0b111;
|
||||
|
||||
if (level == Cpu::Clidr_el1::NO_CACHE) break;
|
||||
|
||||
if ((level == Cpu::Clidr_el1::INSTRUCTION_CACHE) ||
|
||||
(level == Cpu::Clidr_el1::SEPARATE_CACHE)) {
|
||||
Cpu::Csselr_el1::access_t csselr = 0;
|
||||
Cpu::Csselr_el1::Instr::set(csselr, 1);
|
||||
Cpu::Csselr_el1::Level::set(csselr, level);
|
||||
Cpu::Csselr_el1::write(csselr);
|
||||
_state.ccsidr_inst_el1[level] = Cpu::Ccsidr_el1::read();
|
||||
}
|
||||
|
||||
if (level != Cpu::Clidr_el1::INSTRUCTION_CACHE) {
|
||||
Cpu::Csselr_el1::write(Cpu::Csselr_el1::Level::bits(level));
|
||||
_state.ccsidr_data_el1[level] = Cpu::Ccsidr_el1::read();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Vm::~Vm() { alloc().free(_id); }
|
||||
|
||||
|
||||
void Vm::exception(Cpu & cpu)
|
||||
{
|
||||
switch (_state.exception_type) {
|
||||
case Cpu::IRQ_LEVEL_EL0: [[fallthrough]]
|
||||
case Cpu::IRQ_LEVEL_EL1: [[fallthrough]]
|
||||
case Cpu::FIQ_LEVEL_EL0: [[fallthrough]]
|
||||
case Cpu::FIQ_LEVEL_EL1:
|
||||
_interrupt(cpu.id());
|
||||
break;
|
||||
case Cpu::SYNC_LEVEL_EL0: [[fallthrough]]
|
||||
case Cpu::SYNC_LEVEL_EL1: [[fallthrough]]
|
||||
case Cpu::SERR_LEVEL_EL0: [[fallthrough]]
|
||||
case Cpu::SERR_LEVEL_EL1:
|
||||
pause();
|
||||
_context.submit(1);
|
||||
break;
|
||||
default:
|
||||
Genode::raw("Exception vector: ", (void*)_state.exception_type,
|
||||
" not implemented!");
|
||||
};
|
||||
|
||||
if (cpu.pic().ack_virtual_irq(_vcpu_context.pic))
|
||||
inject_irq(Board::VT_MAINTAINANCE_IRQ);
|
||||
_vcpu_context.vtimer_irq.disable();
|
||||
}
|
||||
|
||||
|
||||
void Vm::proceed(Cpu & cpu)
|
||||
{
|
||||
if (_state.timer.irq) _vcpu_context.vtimer_irq.enable();
|
||||
|
||||
cpu.pic().insert_virtual_irq(_vcpu_context.pic, _state.irqs.virtual_irq);
|
||||
|
||||
/*
|
||||
* the following values have to be enforced by the hypervisor
|
||||
*/
|
||||
Cpu::Vttbr_el2::access_t vttbr_el2 =
|
||||
Cpu::Vttbr_el2::Ba::masked((Cpu::Vttbr_el2::access_t)_table);
|
||||
Cpu::Vttbr_el2::Asid::set(vttbr_el2, _id);
|
||||
addr_t guest = Hw::Mm::el2_addr(&_state);
|
||||
addr_t pic = Hw::Mm::el2_addr(&_vcpu_context.pic);
|
||||
addr_t host = Hw::Mm::el2_addr(&host_context());
|
||||
host_context().sp_el1 = cpu.stack_start();
|
||||
|
||||
hypervisor_enter_vm(guest, host, pic, vttbr_el2);
|
||||
}
|
||||
|
||||
void Vm::inject_irq(unsigned irq)
|
||||
{
|
||||
_state.irqs.last_irq = irq;
|
||||
pause();
|
||||
_context.submit(1);
|
||||
}
|
@ -17,11 +17,25 @@
|
||||
#include <hw/spec/arm/gicv2.h>
|
||||
#include <hw/spec/arm/arndale_board.h>
|
||||
#include <spec/arm/exynos_mct.h>
|
||||
#include <spec/arm/cpu/vm_state_virtualization.h>
|
||||
#include <translation_table.h>
|
||||
#include <kernel/configuration.h>
|
||||
|
||||
namespace Kernel { class Cpu; }
|
||||
|
||||
namespace Board {
|
||||
using namespace Hw::Arndale_board;
|
||||
|
||||
using Pic = Hw::Gicv2;
|
||||
|
||||
enum { VCPU_MAX = 1 };
|
||||
|
||||
using Vm_state = Genode::Vm_state;
|
||||
using Vm_page_table = Hw::Level_1_stage_2_translation_table;
|
||||
using Vm_page_table_array =
|
||||
Vm_page_table::Allocator::Array<Kernel::DEFAULT_TRANSLATION_TABLE_MAX>;
|
||||
|
||||
struct Vcpu_context { Vcpu_context(Kernel::Cpu &) {} };
|
||||
}
|
||||
|
||||
#endif /* _CORE__SPEC__ARNDALE__BOARD_H_ */
|
||||
|
@ -18,10 +18,8 @@
|
||||
#include <hw/spec/arm/imx_tzic.h>
|
||||
#include <hw/spec/arm/imx53_qsb_board.h>
|
||||
#include <spec/arm/imx_epit.h>
|
||||
#include <spec/arm/trustzone_board.h>
|
||||
|
||||
namespace Board {
|
||||
using namespace Hw::Imx53_qsb_board;
|
||||
using Hw::Pic;
|
||||
}
|
||||
namespace Board { using namespace Hw::Imx53_qsb_board; }
|
||||
|
||||
#endif /* _CORE__SPEC__IMX53_QSB__BOARD_H_ */
|
||||
|
@ -14,16 +14,28 @@
|
||||
#ifndef _CORE__SPEC__IMX7D_SABRE__BOARD_H_
|
||||
#define _CORE__SPEC__IMX7D_SABRE__BOARD_H_
|
||||
|
||||
#include <hw/spec/arm/gicv2.h>
|
||||
#include <hw/spec/arm/imx7d_sabre_board.h>
|
||||
#include <spec/arm/virtualization/gicv2.h>
|
||||
#include <spec/arm/generic_timer.h>
|
||||
#include <spec/arm/cpu/vm_state_virtualization.h>
|
||||
#include <translation_table.h>
|
||||
#include <kernel/configuration.h>
|
||||
|
||||
namespace Kernel { class Cpu; }
|
||||
|
||||
namespace Board {
|
||||
using namespace Hw::Imx7d_sabre_board;
|
||||
|
||||
using Pic = Hw::Gicv2;
|
||||
struct Virtual_local_pic {};
|
||||
|
||||
enum { TIMER_IRQ = 30 };
|
||||
enum { TIMER_IRQ = 30, VCPU_MAX = 1 };
|
||||
|
||||
using Vm_state = Genode::Vm_state;
|
||||
using Vm_page_table = Hw::Level_1_stage_2_translation_table;
|
||||
using Vm_page_table_array =
|
||||
Vm_page_table::Allocator::Array<Kernel::DEFAULT_TRANSLATION_TABLE_MAX>;
|
||||
|
||||
struct Vcpu_context { Vcpu_context(Kernel::Cpu &) {} };
|
||||
}
|
||||
|
||||
#endif /* _CORE__SPEC__IMX7_SABRELITE__BOARD_H_ */
|
||||
|
@ -15,14 +15,73 @@
|
||||
#define _CORE__SPEC__IMX8Q_EVK__BOARD_H_
|
||||
|
||||
#include <hw/spec/arm_64/imx8q_evk_board.h>
|
||||
#include <hw/spec/arm/gicv3.h>
|
||||
#include <spec/arm/generic_timer.h>
|
||||
#include <spec/arm/virtualization/gicv3.h>
|
||||
#include <spec/arm_64/cpu/vm_state_virtualization.h>
|
||||
#include <translation_table.h>
|
||||
#include <kernel/configuration.h>
|
||||
#include <kernel/irq.h>
|
||||
|
||||
namespace Board {
|
||||
using namespace Hw::Imx8q_evk_board;
|
||||
using Hw::Pic;
|
||||
|
||||
enum { TIMER_IRQ = 30 };
|
||||
enum {
|
||||
TIMER_IRQ = 14 + 16,
|
||||
VT_TIMER_IRQ = 11 + 16,
|
||||
VT_MAINTAINANCE_IRQ = 9 + 16,
|
||||
VCPU_MAX = 16
|
||||
};
|
||||
|
||||
using Vm_page_table = Hw::Level_1_stage_2_translation_table;
|
||||
using Vm_page_table_array =
|
||||
Vm_page_table::Allocator::Array<Kernel::DEFAULT_TRANSLATION_TABLE_MAX>;
|
||||
|
||||
struct Vcpu_context;
|
||||
|
||||
using Vm_state = Genode::Vm_state;
|
||||
};
|
||||
|
||||
namespace Kernel {
|
||||
class Cpu;
|
||||
class Vm;
|
||||
};
|
||||
|
||||
struct Board::Vcpu_context
|
||||
{
|
||||
struct Vm_irq : Kernel::Irq
|
||||
{
|
||||
Vm_irq(unsigned const irq, Kernel::Cpu &);
|
||||
virtual ~Vm_irq() {};
|
||||
|
||||
virtual void handle(Kernel::Cpu &, Kernel::Vm & vm, unsigned irq);
|
||||
void occurred() override;
|
||||
};
|
||||
|
||||
|
||||
struct Pic_maintainance_irq : Vm_irq
|
||||
{
|
||||
Pic_maintainance_irq(Kernel::Cpu &);
|
||||
|
||||
void handle(Kernel::Cpu &, Kernel::Vm &, unsigned) override { }
|
||||
};
|
||||
|
||||
|
||||
struct Virtual_timer_irq
|
||||
{
|
||||
Vm_irq irq;
|
||||
|
||||
Virtual_timer_irq(Kernel::Cpu &);
|
||||
|
||||
void enable();
|
||||
void disable();
|
||||
};
|
||||
|
||||
Vcpu_context(Kernel::Cpu & cpu)
|
||||
: pic_irq(cpu), vtimer_irq(cpu) {}
|
||||
|
||||
Pic::Virtual_context pic {};
|
||||
Pic_maintainance_irq pic_irq;
|
||||
Virtual_timer_irq vtimer_irq;
|
||||
};
|
||||
|
||||
#endif /* _CORE__SPEC__IMX8Q_EVK__BOARD_H_ */
|
||||
|
@ -18,10 +18,8 @@
|
||||
#include <hw/spec/arm/imx_tzic.h>
|
||||
#include <hw/spec/arm/usb_armory_board.h>
|
||||
#include <spec/arm/imx_epit.h>
|
||||
#include <spec/arm/trustzone_board.h>
|
||||
|
||||
namespace Board {
|
||||
using namespace Hw::Usb_armory_board;
|
||||
using Hw::Pic;
|
||||
}
|
||||
namespace Board { using namespace Hw::Usb_armory_board; }
|
||||
|
||||
#endif /* _CORE__SPEC__USB_ARMORY__BOARD_H_ */
|
||||
|
@ -17,6 +17,9 @@
|
||||
#include <hw/spec/x86_64/pc_board.h>
|
||||
#include <spec/x86_64/muen/pic.h>
|
||||
#include <spec/x86_64/muen/timer.h>
|
||||
#include <cpu/cpu_state.h>
|
||||
|
||||
namespace Kernel { class Cpu; }
|
||||
|
||||
namespace Board {
|
||||
using namespace Hw::Pc_board;
|
||||
@ -33,6 +36,15 @@ namespace Board {
|
||||
TIMER_VECTOR_KERNEL = 32,
|
||||
TIMER_VECTOR_USER = 50,
|
||||
};
|
||||
|
||||
using Vm_state = Genode::Cpu_state;
|
||||
|
||||
enum { VCPU_MAX = 1 };
|
||||
|
||||
struct Vm_page_table {};
|
||||
struct Vm_page_table_array {};
|
||||
|
||||
struct Vcpu_context { Vcpu_context(Kernel::Cpu &) {} };
|
||||
}
|
||||
|
||||
#endif /* _CORE__SPEC__X86_64__MUEN__BOARD_H_ */
|
||||
|
@ -17,14 +17,16 @@
|
||||
#include <platform_pd.h>
|
||||
#include <kernel/cpu.h>
|
||||
#include <kernel/vm.h>
|
||||
#include <kernel/vm_state.h>
|
||||
|
||||
Kernel::Vm::Vm(void * const state, Kernel::Signal_context * const context,
|
||||
Kernel::Vm::Vm(unsigned,
|
||||
Board::Vm_state & state,
|
||||
Kernel::Signal_context & context,
|
||||
void * const)
|
||||
: Cpu_job(Cpu_priority::MIN, 0),
|
||||
_state((Genode::Vm_state *) state),
|
||||
_state(state),
|
||||
_context(context),
|
||||
_table(nullptr)
|
||||
_table(nullptr),
|
||||
_vcpu_context(cpu_pool().primary_cpu())
|
||||
{
|
||||
affinity(cpu_pool().primary_cpu());
|
||||
}
|
||||
@ -36,20 +38,20 @@ Kernel::Vm::~Vm() { }
|
||||
void Kernel::Vm::exception(Cpu & cpu)
|
||||
{
|
||||
pause();
|
||||
if (_state->trapno == 200) {
|
||||
_context->submit(1);
|
||||
if (_state.trapno == 200) {
|
||||
_context.submit(1);
|
||||
return;
|
||||
}
|
||||
|
||||
if (_state->trapno >= Genode::Cpu_state::INTERRUPTS_START &&
|
||||
_state->trapno <= Genode::Cpu_state::INTERRUPTS_END) {
|
||||
cpu.pic().irq_occurred(_state->trapno);
|
||||
if (_state.trapno >= Genode::Cpu_state::INTERRUPTS_START &&
|
||||
_state.trapno <= Genode::Cpu_state::INTERRUPTS_END) {
|
||||
cpu.pic().irq_occurred(_state.trapno);
|
||||
_interrupt(cpu.id());
|
||||
_context->submit(1);
|
||||
_context.submit(1);
|
||||
return;
|
||||
}
|
||||
Genode::raw("VM: triggered unknown exception ", _state->trapno,
|
||||
" with error code ", _state->errcode);
|
||||
Genode::raw("VM: triggered unknown exception ", _state.trapno,
|
||||
" with error code ", _state.errcode);
|
||||
|
||||
ASSERT_NEVER_CALLED;
|
||||
}
|
||||
@ -57,7 +59,7 @@ void Kernel::Vm::exception(Cpu & cpu)
|
||||
|
||||
void Kernel::Vm::proceed(Cpu & cpu)
|
||||
{
|
||||
cpu.tss.ist[0] = (addr_t)_state + sizeof(Genode::Cpu_state);
|
||||
cpu.tss.ist[0] = (addr_t)&_state + sizeof(Genode::Cpu_state);
|
||||
|
||||
asm volatile("sti \n"
|
||||
"mov $1, %rax \n"
|
||||
|
@ -1,22 +0,0 @@
|
||||
/*
|
||||
* \brief CPU context of a virtual machine
|
||||
* \author Stefan Kalkowski
|
||||
* \date 2015-06-03
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2015-2017 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU Affero General Public License version 3.
|
||||
*/
|
||||
|
||||
#ifndef _CORE__SPEC__X86_64__MUEN__VM_STATE_H_
|
||||
#define _CORE__SPEC__X86_64__MUEN__VM_STATE_H_
|
||||
|
||||
namespace Genode
|
||||
{
|
||||
struct Vm_state : Cpu_state {};
|
||||
}
|
||||
|
||||
#endif /* _CORE__SPEC__X86_64__MUEN__VM_STATE_H_ */
|
@ -26,6 +26,8 @@ class Board::Pic
|
||||
{
|
||||
public:
|
||||
|
||||
struct Virtual_context {};
|
||||
|
||||
enum {
|
||||
/*
|
||||
* FIXME: dummy ipi value on non-SMP platform, should be removed
|
||||
|
@ -0,0 +1,89 @@
|
||||
/*
|
||||
* \brief Core-specific instance of the VM session interface
|
||||
* \author Stefan Kalkowski
|
||||
* \date 2015-06-03
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2015-2017 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU Affero General Public License version 3.
|
||||
*/
|
||||
|
||||
/* Genode includes */
|
||||
#include <util/construct_at.h>
|
||||
|
||||
/* core includes */
|
||||
#include <vm_session_component.h>
|
||||
#include <platform.h>
|
||||
|
||||
using namespace Genode;
|
||||
|
||||
static Board::Vm_page_table_array & dummy_array()
|
||||
{
|
||||
static Board::Vm_page_table_array a;
|
||||
return a;
|
||||
}
|
||||
|
||||
|
||||
void Vm_session_component::_attach(addr_t, addr_t, size_t) { }
|
||||
|
||||
|
||||
void Vm_session_component::_attach_vm_memory(Dataspace_component &,
|
||||
addr_t const,
|
||||
Attach_attr const) { }
|
||||
|
||||
|
||||
void Vm_session_component::attach_pic(addr_t) { }
|
||||
|
||||
|
||||
void Vm_session_component::_detach_vm_memory(addr_t, size_t) { }
|
||||
|
||||
|
||||
void * Vm_session_component::_alloc_table()
|
||||
{
|
||||
static Board::Vm_page_table table;
|
||||
return (void*) &table;
|
||||
}
|
||||
|
||||
|
||||
Vm_session_component::Vm_session_component(Rpc_entrypoint &ep,
|
||||
Resources resources,
|
||||
Label const &,
|
||||
Diag,
|
||||
Ram_allocator &ram_alloc,
|
||||
Region_map ®ion_map,
|
||||
unsigned, Trace::Source_registry &)
|
||||
:
|
||||
Ram_quota_guard(resources.ram_quota),
|
||||
Cap_quota_guard(resources.cap_quota),
|
||||
_ep(ep),
|
||||
_constrained_md_ram_alloc(ram_alloc, _ram_quota_guard(), _cap_quota_guard()),
|
||||
_sliced_heap(_constrained_md_ram_alloc, region_map),
|
||||
_region_map(region_map),
|
||||
_table(*construct_at<Board::Vm_page_table>(_alloc_table())),
|
||||
_table_array(dummy_array()) { }
|
||||
|
||||
|
||||
Vm_session_component::~Vm_session_component()
|
||||
{
|
||||
/* detach all regions */
|
||||
while (true) {
|
||||
addr_t out_addr = 0;
|
||||
|
||||
if (!_map.any_block_addr(&out_addr))
|
||||
break;
|
||||
|
||||
detach(out_addr);
|
||||
}
|
||||
|
||||
/* free region in allocator */
|
||||
for (unsigned i = 0; i < _id_alloc; i++) {
|
||||
Vcpu & vcpu = _vcpus[i];
|
||||
if (vcpu.ds_cap.valid()) {
|
||||
_region_map.detach(vcpu.ds_addr);
|
||||
_constrained_md_ram_alloc.free(vcpu.ds_cap);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,88 +0,0 @@
|
||||
/*
|
||||
* \brief Core-specific instance of the VM session interface
|
||||
* \author Stefan Kalkowski
|
||||
* \date 2015-06-03
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2015-2017 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU Affero General Public License version 3.
|
||||
*/
|
||||
|
||||
#ifndef _CORE__SPEC__X86_64__MUEN__VM_SESSION_COMPONENT_H_
|
||||
#define _CORE__SPEC__X86_64__MUEN__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 <trace/source_registry.h>
|
||||
|
||||
/* Core includes */
|
||||
#include <dataspace_component.h>
|
||||
#include <object.h>
|
||||
#include <kernel/vm.h>
|
||||
#include <kernel/vm_state.h>
|
||||
|
||||
namespace Genode {
|
||||
class Vm_session_component;
|
||||
}
|
||||
|
||||
class Genode::Vm_session_component
|
||||
:
|
||||
private Ram_quota_guard,
|
||||
private Cap_quota_guard,
|
||||
public Rpc_object<Vm_session, Vm_session_component>
|
||||
{
|
||||
private:
|
||||
|
||||
Kernel_object<Kernel::Vm> _kobj {};
|
||||
Vm_state _state;
|
||||
|
||||
public:
|
||||
|
||||
Vm_session_component(Rpc_entrypoint &, Resources resources,
|
||||
Label const &, Diag, Ram_allocator &,
|
||||
Region_map &, unsigned,
|
||||
Trace::Source_registry &)
|
||||
:
|
||||
Ram_quota_guard(resources.ram_quota),
|
||||
Cap_quota_guard(resources.cap_quota),
|
||||
_state()
|
||||
{ }
|
||||
|
||||
~Vm_session_component() { }
|
||||
|
||||
using Ram_quota_guard::upgrade;
|
||||
using Cap_quota_guard::upgrade;
|
||||
using Genode::Rpc_object<Genode::Vm_session, Vm_session_component>::cap;
|
||||
|
||||
/**************************
|
||||
** Vm session interface **
|
||||
**************************/
|
||||
|
||||
Dataspace_capability _cpu_state(Vcpu_id) { return Dataspace_capability(); }
|
||||
|
||||
void _exception_handler(Signal_context_capability handler, Vcpu_id)
|
||||
{
|
||||
if (!_kobj.create(&_state, Capability_space::capid(handler), nullptr))
|
||||
warning("Cannot instantiate vm kernel object, "
|
||||
"invalid signal context?");
|
||||
}
|
||||
|
||||
void _run(Vcpu_id) {
|
||||
if (_kobj.constructed()) Kernel::run_vm(*_kobj); }
|
||||
|
||||
void _pause(Vcpu_id) {
|
||||
if (_kobj.constructed()) Kernel::pause_vm(*_kobj); }
|
||||
|
||||
void attach(Dataspace_capability, addr_t, Attach_attr) override { }
|
||||
void attach_pic(addr_t) override { }
|
||||
void detach(addr_t, size_t) override { }
|
||||
Vcpu_id _create_vcpu(Thread_capability) { return 0; }
|
||||
};
|
||||
|
||||
#endif /* _CORE__SPEC__X86_64__MUEN__VM_SESSION_COMPONENT_H_ */
|
114
repos/base-hw/src/core/vm_session_component.cc
Normal file
114
repos/base-hw/src/core/vm_session_component.cc
Normal file
@ -0,0 +1,114 @@
|
||||
/*
|
||||
* \brief VM session component for 'base-hw'
|
||||
* \author Stefan Kalkowski
|
||||
* \date 2012-10-08
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2012-2017 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU Affero General Public License version 3.
|
||||
*/
|
||||
|
||||
/* Genode includes */
|
||||
#include <util/construct_at.h>
|
||||
|
||||
/* core includes */
|
||||
#include <kernel/core_interface.h>
|
||||
#include <vm_session_component.h>
|
||||
#include <platform.h>
|
||||
#include <cpu_thread_component.h>
|
||||
#include <core_env.h>
|
||||
|
||||
using namespace Genode;
|
||||
|
||||
static Core_mem_allocator & cma() {
|
||||
return static_cast<Core_mem_allocator&>(platform().core_mem_alloc()); }
|
||||
|
||||
|
||||
size_t Vm_session_component::_ds_size() {
|
||||
return align_addr(sizeof(Board::Vm_state), get_page_size_log2()); }
|
||||
|
||||
|
||||
addr_t Vm_session_component::_alloc_ds()
|
||||
{
|
||||
addr_t addr;
|
||||
if (platform().ram_alloc().alloc_aligned(_ds_size(), (void**)&addr,
|
||||
get_page_size_log2()).error())
|
||||
throw Insufficient_ram_quota();
|
||||
return addr;
|
||||
}
|
||||
|
||||
|
||||
void Vm_session_component::_run(Vcpu_id id)
|
||||
{
|
||||
if (_valid_id(id) && _vcpus[id.id].kobj.constructed())
|
||||
Kernel::run_vm(*_vcpus[id.id].kobj);
|
||||
}
|
||||
|
||||
|
||||
void Vm_session_component::_pause(Vcpu_id id)
|
||||
{
|
||||
if (_valid_id(id) && _vcpus[id.id].kobj.constructed())
|
||||
Kernel::pause_vm(*_vcpus[id.id].kobj);
|
||||
}
|
||||
|
||||
|
||||
void Vm_session_component::_exception_handler(Signal_context_capability handler,
|
||||
Vcpu_id id)
|
||||
{
|
||||
if (!_valid_id(id)) {
|
||||
Genode::warning("invalid vcpu id ", id.id);
|
||||
return;
|
||||
}
|
||||
|
||||
Vcpu & vcpu = _vcpus[id.id];
|
||||
if (vcpu.kobj.constructed()) {
|
||||
Genode::warning("Cannot register vcpu handler twice");
|
||||
return;
|
||||
}
|
||||
|
||||
unsigned const cpu = vcpu.location.valid() ? vcpu.location.xpos() : 0;
|
||||
|
||||
if (!vcpu.kobj.create(cpu, vcpu.ds_addr, Capability_space::capid(handler),
|
||||
cma().phys_addr(&_table)))
|
||||
Genode::warning("Cannot instantiate vm kernel object, ",
|
||||
"invalid signal context?");
|
||||
}
|
||||
|
||||
|
||||
Vm_session::Vcpu_id Vm_session_component::_create_vcpu(Thread_capability tcap)
|
||||
{
|
||||
using namespace Genode;
|
||||
|
||||
if (_id_alloc == Board::VCPU_MAX) return Vcpu_id{Vcpu_id::INVALID};
|
||||
|
||||
Affinity::Location vcpu_location;
|
||||
auto lambda = [&] (Cpu_thread_component *ptr) {
|
||||
if (!ptr) return;
|
||||
vcpu_location = ptr->platform_thread().affinity();
|
||||
};
|
||||
_ep.apply(tcap, lambda);
|
||||
|
||||
Vcpu & vcpu = _vcpus[_id_alloc];
|
||||
vcpu.ds_cap = _constrained_md_ram_alloc.alloc(_ds_size(),
|
||||
Cache_attribute::UNCACHED);
|
||||
try {
|
||||
vcpu.ds_addr = _region_map.attach(vcpu.ds_cap);
|
||||
} catch (...) {
|
||||
_constrained_md_ram_alloc.free(vcpu.ds_cap);
|
||||
throw;
|
||||
}
|
||||
|
||||
vcpu.location = vcpu_location;
|
||||
return Vcpu_id { _id_alloc++ };
|
||||
}
|
||||
|
||||
|
||||
Genode::Dataspace_capability
|
||||
Vm_session_component::_cpu_state(Vm_session::Vcpu_id id)
|
||||
{
|
||||
return (_valid_id(id)) ? _vcpus[id.id].ds_cap
|
||||
: Genode::Ram_dataspace_capability();
|
||||
}
|
@ -11,8 +11,8 @@
|
||||
* under the terms of the GNU Affero General Public License version 3.
|
||||
*/
|
||||
|
||||
#ifndef _CORE__SPEC__ARM_V7__VIRTUALIZATION__VM_SESSION_COMPONENT_H_
|
||||
#define _CORE__SPEC__ARM_V7__VIRTUALIZATION__VM_SESSION_COMPONENT_H_
|
||||
#ifndef _CORE__VM_SESSION_COMPONENT_H_
|
||||
#define _CORE__VM_SESSION_COMPONENT_H_
|
||||
|
||||
/* Genode includes */
|
||||
#include <base/allocator.h>
|
||||
@ -20,14 +20,12 @@
|
||||
#include <base/session_object.h>
|
||||
#include <vm_session/vm_session.h>
|
||||
#include <dataspace/capability.h>
|
||||
#include <hw/spec/arm/lpae.h>
|
||||
|
||||
/* Core includes */
|
||||
#include <object.h>
|
||||
#include <region_map_component.h>
|
||||
#include <translation_table.h>
|
||||
#include <kernel/vm.h>
|
||||
#include <cpu/vm_state_virtualization.h>
|
||||
|
||||
#include <trace/source_registry.h>
|
||||
|
||||
@ -39,8 +37,8 @@ class Genode::Vm_session_component
|
||||
:
|
||||
private Ram_quota_guard,
|
||||
private Cap_quota_guard,
|
||||
public Rpc_object<Vm_session, Vm_session_component>,
|
||||
public Region_map_detach
|
||||
public Rpc_object<Vm_session, Vm_session_component>,
|
||||
public Region_map_detach
|
||||
{
|
||||
private:
|
||||
|
||||
@ -52,30 +50,31 @@ class Genode::Vm_session_component
|
||||
Vm_session_component(Vm_session_component const &);
|
||||
Vm_session_component &operator = (Vm_session_component const &);
|
||||
|
||||
using Table = Hw::Level_1_stage_2_translation_table;
|
||||
using Array = Table::Allocator::Array<Kernel::DEFAULT_TRANSLATION_TABLE_MAX>;
|
||||
struct Vcpu
|
||||
{
|
||||
Ram_dataspace_capability ds_cap { };
|
||||
Region_map::Local_addr ds_addr { nullptr };
|
||||
Kernel_object<Kernel::Vm> kobj {};
|
||||
Affinity::Location location {};
|
||||
} _vcpus[Board::VCPU_MAX];
|
||||
|
||||
Rpc_entrypoint &_ep;
|
||||
Constrained_ram_allocator _constrained_md_ram_alloc;
|
||||
Sliced_heap _sliced_heap;
|
||||
Avl_region _map { &_sliced_heap };
|
||||
Region_map &_region_map;
|
||||
Ram_dataspace_capability _ds_cap { };
|
||||
Region_map::Local_addr _ds_addr { nullptr };
|
||||
Table &_table;
|
||||
Array &_table_array;
|
||||
Kernel_object<Kernel::Vm> _kobj {};
|
||||
Rpc_entrypoint &_ep;
|
||||
Constrained_ram_allocator _constrained_md_ram_alloc;
|
||||
Sliced_heap _sliced_heap;
|
||||
Avl_region _map { &_sliced_heap };
|
||||
Region_map &_region_map;
|
||||
Board::Vm_page_table &_table;
|
||||
Board::Vm_page_table_array &_table_array;
|
||||
unsigned _id_alloc { 0 };
|
||||
|
||||
static size_t _ds_size() {
|
||||
return align_addr(sizeof(Vm_state),
|
||||
get_page_size_log2()); }
|
||||
|
||||
addr_t _alloc_ds();
|
||||
void * _alloc_table();
|
||||
void _attach(addr_t phys_addr, addr_t vm_addr, size_t size);
|
||||
|
||||
void _attach_vm_memory(Dataspace_component &, addr_t, Attach_attr);
|
||||
void _detach_vm_memory(addr_t, size_t);
|
||||
static size_t _ds_size();
|
||||
bool _valid_id(Vcpu_id id) { return id.id < Board::VCPU_MAX; }
|
||||
addr_t _alloc_ds();
|
||||
void * _alloc_table();
|
||||
void _attach(addr_t phys_addr, addr_t vm_addr, size_t size);
|
||||
void _attach_vm_memory(Dataspace_component &, addr_t,
|
||||
Attach_attr);
|
||||
void _detach_vm_memory(addr_t, size_t);
|
||||
|
||||
protected:
|
||||
|
||||
@ -104,14 +103,16 @@ class Genode::Vm_session_component
|
||||
** Vm session interface **
|
||||
**************************/
|
||||
|
||||
Dataspace_capability _cpu_state(Vcpu_id) { return _ds_cap; }
|
||||
void _exception_handler(Signal_context_capability, Vcpu_id);
|
||||
void _run(Vcpu_id);
|
||||
void _pause(Vcpu_id);
|
||||
void attach(Dataspace_capability, addr_t, Attach_attr) override;
|
||||
void attach_pic(addr_t) override;
|
||||
void detach(addr_t, size_t) override;
|
||||
Vcpu_id _create_vcpu(Thread_capability) { return 0; }
|
||||
|
||||
Dataspace_capability _cpu_state(Vcpu_id);
|
||||
Vcpu_id _create_vcpu(Thread_capability);
|
||||
void _exception_handler(Signal_context_capability,
|
||||
Vcpu_id);
|
||||
void _run(Vcpu_id);
|
||||
void _pause(Vcpu_id);
|
||||
};
|
||||
|
||||
#endif /* _CORE__SPEC__ARM_V7__VIRTUALIZATION__VM_SESSION_COMPONENT_H_ */
|
||||
#endif /* _CORE__VM_SESSION_COMPONENT_H_ */
|
@ -30,6 +30,7 @@ namespace Hw {
|
||||
Memory_region const core_heap();
|
||||
Memory_region const system_exception_vector();
|
||||
Memory_region const hypervisor_exception_vector();
|
||||
Memory_region const hypervisor_stack();
|
||||
Memory_region const supervisor_exception_vector();
|
||||
Memory_region const boot_info();
|
||||
}
|
||||
|
@ -35,11 +35,31 @@ namespace Hw { struct Arm_64_cpu; }
|
||||
|
||||
struct Hw::Arm_64_cpu
|
||||
{
|
||||
SYSTEM_REGISTER(64, Id_pfr0, id_aa64pfr0_el1,
|
||||
struct El2 : Bitfield<8, 4> {};
|
||||
struct El3 : Bitfield<8, 4> {};
|
||||
SYSTEM_REGISTER(64, Actlr_el1, actlr_el1);
|
||||
SYSTEM_REGISTER(64, Amair_el1, amair_el1);
|
||||
|
||||
SYSTEM_REGISTER(32, Ccsidr_el1, ccsidr_el1);
|
||||
|
||||
SYSTEM_REGISTER(64, Clidr_el1, clidr_el1,
|
||||
enum Cache_type {
|
||||
NO_CACHE,
|
||||
INSTRUCTION_CACHE,
|
||||
DATA_CACHE,
|
||||
SEPARATE_CACHE,
|
||||
UNIFIED_CACHE
|
||||
};
|
||||
);
|
||||
|
||||
SYSTEM_REGISTER(32, Csselr_el1, csselr_el1,
|
||||
struct Instr : Bitfield<0, 1> {};
|
||||
struct Level : Bitfield<1, 3> {};
|
||||
);
|
||||
|
||||
SYSTEM_REGISTER(32, Cpacr_el1, cpacr_el1);
|
||||
|
||||
SYSTEM_REGISTER(32, Cptr_el2, cptr_el2,
|
||||
struct Tta : Bitfield<20, 1> {}; );
|
||||
|
||||
SYSTEM_REGISTER(64, Current_el, currentel,
|
||||
enum Level { EL0, EL1, EL2, EL3 };
|
||||
struct El : Bitfield<2, 2> {};
|
||||
@ -80,12 +100,27 @@ struct Hw::Arm_64_cpu
|
||||
|
||||
SYSTEM_REGISTER(64, Esr_el1, esr_el1);
|
||||
SYSTEM_REGISTER(64, Far_el1, far_el1);
|
||||
SYSTEM_REGISTER(32, Fpcr, fpcr);
|
||||
|
||||
SYSTEM_REGISTER(64, Hcr, hcr_el2,
|
||||
SYSTEM_REGISTER(64, Hcr_el2, hcr_el2,
|
||||
struct Rw : Bitfield<31, 1> {};
|
||||
);
|
||||
|
||||
SYSTEM_REGISTER(64, Mair, mair_el1,
|
||||
SYSTEM_REGISTER(32, Hstr_el2, hstr_el2);
|
||||
|
||||
SYSTEM_REGISTER(64, Id_aa64isar0_el1, id_aa64isar0_el1);
|
||||
SYSTEM_REGISTER(64, Id_aa64isar1_el1, id_aa64isar1_el1);
|
||||
SYSTEM_REGISTER(64, Id_aa64mmfr0_el1, id_aa64mmfr0_el1);
|
||||
SYSTEM_REGISTER(64, Id_aa64mmfr1_el1, id_aa64mmfr1_el1);
|
||||
SYSTEM_REGISTER(64, Id_aa64mmfr2_el1, id_aa64mmfr2_el1);
|
||||
|
||||
SYSTEM_REGISTER(64, Id_pfr0, id_aa64pfr0_el1,
|
||||
struct El2 : Bitfield<8, 4> {};
|
||||
struct El3 : Bitfield<8, 4> {};
|
||||
);
|
||||
|
||||
struct Mair : Genode::Register<64>
|
||||
{
|
||||
enum Attributes {
|
||||
DEVICE_MEMORY = 0x04,
|
||||
NORMAL_MEMORY_UNCACHED = 0x44,
|
||||
@ -95,7 +130,10 @@ struct Hw::Arm_64_cpu
|
||||
struct Attr1 : Bitfield<8, 8> {};
|
||||
struct Attr2 : Bitfield<16, 8> {};
|
||||
struct Attr3 : Bitfield<24, 8> {};
|
||||
);
|
||||
};
|
||||
|
||||
SYSTEM_REGISTER(64, Mair_el1, mair_el1);
|
||||
SYSTEM_REGISTER(64, Mair_el2, mair_el2);
|
||||
|
||||
SYSTEM_REGISTER(64, Mpidr, mpidr_el1);
|
||||
|
||||
@ -107,14 +145,20 @@ struct Hw::Arm_64_cpu
|
||||
struct Rw : Bitfield<10, 1> {};
|
||||
);
|
||||
|
||||
SYSTEM_REGISTER(64, Sctlr_el1, sctlr_el1,
|
||||
struct Sctlr : Genode::Register<64>
|
||||
{
|
||||
struct M : Bitfield<0, 1> { };
|
||||
struct A : Bitfield<1, 1> { };
|
||||
struct C : Bitfield<2, 1> { };
|
||||
struct Sa : Bitfield<3, 1> { };
|
||||
struct Sa0 : Bitfield<4, 1> { };
|
||||
struct I : Bitfield<12, 1> { };
|
||||
);
|
||||
struct Uct : Bitfield<15, 1> { };
|
||||
struct Wxn : Bitfield<19, 1> { };
|
||||
};
|
||||
|
||||
SYSTEM_REGISTER(64, Sctlr_el1, sctlr_el1);
|
||||
SYSTEM_REGISTER(64, Sctlr_el2, sctlr_el2);
|
||||
|
||||
struct Spsr : Genode::Register<64>
|
||||
{
|
||||
@ -147,6 +191,13 @@ struct Hw::Arm_64_cpu
|
||||
struct As : Bitfield<36, 1> { };
|
||||
);
|
||||
|
||||
SYSTEM_REGISTER(64, Tcr_el2, tcr_el2,
|
||||
struct T0sz : Bitfield<0, 6> { };
|
||||
struct Irgn0 : Bitfield<8, 2> { };
|
||||
struct Orgn0 : Bitfield<10, 2> { };
|
||||
struct Sh0 : Bitfield<12, 2> { };
|
||||
);
|
||||
|
||||
struct Ttbr : Genode::Register<64>
|
||||
{
|
||||
struct Baddr : Bitfield<0, 48> { };
|
||||
@ -154,10 +205,24 @@ struct Hw::Arm_64_cpu
|
||||
};
|
||||
|
||||
SYSTEM_REGISTER(64, Ttbr0_el1, ttbr0_el1);
|
||||
SYSTEM_REGISTER(64, Ttbr0_el2, ttbr0_el2);
|
||||
SYSTEM_REGISTER(64, Ttbr1_el1, ttbr1_el1);
|
||||
|
||||
SYSTEM_REGISTER(64, Vbar_el1, vbar_el1);
|
||||
|
||||
SYSTEM_REGISTER(64, Vbar_el2, vbar_el2);
|
||||
|
||||
SYSTEM_REGISTER(32, Vtcr_el2, vtcr_el2,
|
||||
struct T0sz : Bitfield<0, 6> {};
|
||||
struct Sl0 : Bitfield<6, 2> {};
|
||||
);
|
||||
|
||||
SYSTEM_REGISTER(64, Vttbr_el2, vttbr_el2,
|
||||
struct CnP : Bitfield<0, 1> { };
|
||||
struct Ba : Bitfield<1, 47> { };
|
||||
struct Asid : Bitfield<48, 8> { };
|
||||
);
|
||||
|
||||
static inline unsigned current_privilege_level() {
|
||||
return Current_el::El::get(Current_el::read()); }
|
||||
|
||||
@ -175,6 +240,8 @@ struct Hw::Arm_64_cpu
|
||||
|
||||
SYSTEM_REGISTER(64, Cntpct_el0, cntpct_el0);
|
||||
SYSTEM_REGISTER(32, Cntp_tval_el0, cntp_tval_el0);
|
||||
SYSTEM_REGISTER(32, Cntkctl_el1, cntkctl_el1);
|
||||
SYSTEM_REGISTER(32, Cnthctl_el2, cnthctl_el2);
|
||||
|
||||
using Cntfrq = Cntfrq_el0;
|
||||
using Cntp_ctl = Cntp_ctl_el0;
|
||||
|
@ -35,6 +35,8 @@ namespace Hw::Imx8q_evk_board {
|
||||
enum {
|
||||
IRQ_CONTROLLER_DISTR_BASE = 0x38800000,
|
||||
IRQ_CONTROLLER_DISTR_SIZE = 0x10000,
|
||||
IRQ_CONTROLLER_VT_CPU_BASE = 0x31020000,
|
||||
IRQ_CONTROLLER_VT_CPU_SIZE = 0x2000,
|
||||
IRQ_CONTROLLER_REDIST_BASE = 0x38880000,
|
||||
IRQ_CONTROLLER_REDIST_SIZE = 0xc0000,
|
||||
};
|
||||
|
31
repos/base-hw/src/include/hw/spec/arm_64/memory_map.h
Normal file
31
repos/base-hw/src/include/hw/spec/arm_64/memory_map.h
Normal file
@ -0,0 +1,31 @@
|
||||
/*
|
||||
* \brief Memory map specific to ARM 64
|
||||
* \author Stefan Kalkowski
|
||||
* \date 2019-09-02
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2016-2017 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU Affero General Public License version 3.
|
||||
*/
|
||||
|
||||
#ifndef _SRC__LIB__HW__SPEC__ARM_64__MEMORY_MAP_H_
|
||||
#define _SRC__LIB__HW__SPEC__ARM_64__MEMORY_MAP_H_
|
||||
|
||||
#include <hw/util.h>
|
||||
|
||||
namespace Hw {
|
||||
namespace Mm {
|
||||
|
||||
template <typename T>
|
||||
Genode::addr_t el2_addr(T t)
|
||||
{
|
||||
static constexpr Genode::addr_t OFF = 0xffffff8000000000UL;
|
||||
return (Genode::addr_t)t - OFF;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
#endif /* _SRC__LIB__HW__SPEC__ARM_64__MEMORY_MAP_H_ */
|
@ -45,6 +45,9 @@ Memory_region const Hw::Mm::system_exception_vector() {
|
||||
Memory_region const Hw::Mm::hypervisor_exception_vector() {
|
||||
return Memory_region(0xfff10000UL, 0x1000UL); }
|
||||
|
||||
Memory_region const Hw::Mm::hypervisor_stack() {
|
||||
return Memory_region(0xfff12000UL, 0x1000UL); }
|
||||
|
||||
Memory_region const Hw::Mm::boot_info() {
|
||||
return Memory_region(0xfffe0000UL, 0x1000UL); }
|
||||
|
||||
|
@ -20,12 +20,14 @@ using Hw::Memory_region;
|
||||
using Genode::addr_t;
|
||||
using Genode::Native_utcb;
|
||||
|
||||
static constexpr addr_t USER_START = Genode::user_utcb_main_thread()
|
||||
+ sizeof(Native_utcb);
|
||||
static constexpr addr_t USER_START = Genode::user_utcb_main_thread()
|
||||
+ sizeof(Native_utcb);
|
||||
static constexpr addr_t USER_END = (1ULL << (39 - 1));
|
||||
static constexpr addr_t KERNEL_START = 0xffffffc000000000UL;
|
||||
|
||||
|
||||
Memory_region const Hw::Mm::user() {
|
||||
return Memory_region(USER_START, 0x800000000000 - USER_START); }
|
||||
return Memory_region(USER_START, USER_END - USER_START); }
|
||||
|
||||
Memory_region const Hw::Mm::core_heap() {
|
||||
return Memory_region(0xffffffd000000000UL, 0x1000000000UL); }
|
||||
@ -45,5 +47,11 @@ Memory_region const Hw::Mm::core_mmio() {
|
||||
Memory_region const Hw::Mm::boot_info() {
|
||||
return Memory_region(0xffffffe040000000UL, 0x1000UL); }
|
||||
|
||||
Memory_region const Hw::Mm::hypervisor_exception_vector() {
|
||||
return Memory_region(0xffffffe050000000UL, 0x2000UL); }
|
||||
|
||||
Memory_region const Hw::Mm::hypervisor_stack() {
|
||||
return Memory_region(0xffffffe050003000UL, 0x1000UL); }
|
||||
|
||||
Memory_region const Hw::Mm::supervisor_exception_vector() {
|
||||
return Memory_region(KERNEL_START, 0x1000UL); }
|
||||
|
Loading…
Reference in New Issue
Block a user