diff --git a/repos/base-hw/include/spec/arm_64/cpu/vm_state_virtualization.h b/repos/base-hw/include/spec/arm_64/cpu/vm_state_virtualization.h new file mode 100644 index 0000000000..ef0a8ac143 --- /dev/null +++ b/repos/base-hw/include/spec/arm_64/cpu/vm_state_virtualization.h @@ -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 + +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_ */ diff --git a/repos/base-hw/lib/mk/spec/arm_v7/core-hw-arndale.mk b/repos/base-hw/lib/mk/spec/arm_v7/core-hw-arndale.mk index 473c82e530..81304cc359 100644 --- a/repos/base-hw/lib/mk/spec/arm_v7/core-hw-arndale.mk +++ b/repos/base-hw/lib/mk/spec/arm_v7/core-hw-arndale.mk @@ -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 diff --git a/repos/base-hw/lib/mk/spec/arm_v7/core-hw-imx53_qsb_tz.mk b/repos/base-hw/lib/mk/spec/arm_v7/core-hw-imx53_qsb_tz.mk index 734243c2bf..c738b6b82e 100644 --- a/repos/base-hw/lib/mk/spec/arm_v7/core-hw-imx53_qsb_tz.mk +++ b/repos/base-hw/lib/mk/spec/arm_v7/core-hw-imx53_qsb_tz.mk @@ -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 diff --git a/repos/base-hw/lib/mk/spec/arm_v7/core-hw-imx7d_sabre.mk b/repos/base-hw/lib/mk/spec/arm_v7/core-hw-imx7d_sabre.mk index 04bb2060d0..47dfa94393 100644 --- a/repos/base-hw/lib/mk/spec/arm_v7/core-hw-imx7d_sabre.mk +++ b/repos/base-hw/lib/mk/spec/arm_v7/core-hw-imx7d_sabre.mk @@ -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 diff --git a/repos/base-hw/lib/mk/spec/arm_v7/core-hw-usb_armory.mk b/repos/base-hw/lib/mk/spec/arm_v7/core-hw-usb_armory.mk index 0a86704d2e..fd18a9476f 100644 --- a/repos/base-hw/lib/mk/spec/arm_v7/core-hw-usb_armory.mk +++ b/repos/base-hw/lib/mk/spec/arm_v7/core-hw-usb_armory.mk @@ -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 diff --git a/repos/base-hw/lib/mk/spec/arm_v8/core-hw-imx8q_evk.mk b/repos/base-hw/lib/mk/spec/arm_v8/core-hw-imx8q_evk.mk index c02cd907db..48df73c8e9 100644 --- a/repos/base-hw/lib/mk/spec/arm_v8/core-hw-imx8q_evk.mk +++ b/repos/base-hw/lib/mk/spec/arm_v8/core-hw-imx8q_evk.mk @@ -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 diff --git a/repos/base-hw/lib/mk/spec/x86_64/core-hw-muen.mk b/repos/base-hw/lib/mk/spec/x86_64/core-hw-muen.mk index 1eb9c661d0..d4c7550a48 100644 --- a/repos/base-hw/lib/mk/spec/x86_64/core-hw-muen.mk +++ b/repos/base-hw/lib/mk/spec/x86_64/core-hw-muen.mk @@ -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 diff --git a/repos/base-hw/src/bootstrap/spec/arm_64/cortex_a53_mmu.cc b/repos/base-hw/src/bootstrap/spec/arm_64/cortex_a53_mmu.cc index 1cc2a02a73..f8d9536e0f 100644 --- a/repos/base-hw/src/bootstrap/spec/arm_64/cortex_a53_mmu.cc +++ b/repos/base-hw/src/bootstrap/spec/arm_64/cortex_a53_mmu.cc @@ -11,6 +11,7 @@ * under the terms of the GNU Affero General Public License version 3. */ +#include #include 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; diff --git a/repos/base-hw/src/core/kernel/vm.h b/repos/base-hw/src/core/kernel/vm.h index fdedadedcf..94472bedee 100644 --- a/repos/base-hw/src/core/kernel/vm.h +++ b/repos/base-hw/src/core/kernel/vm.h @@ -22,6 +22,8 @@ namespace Genode { class Vm_state; } #include #include +#include + 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, + 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); } /** diff --git a/repos/base-hw/src/core/kernel/vm_thread_on.cc b/repos/base-hw/src/core/kernel/vm_thread_on.cc index dc178d4ed0..4407ea6189 100644 --- a/repos/base-hw/src/core/kernel/vm_thread_on.cc +++ b/repos/base-hw/src/core/kernel/vm_thread_on.cc @@ -18,13 +18,14 @@ void Kernel::Thread::_call_new_vm() { Signal_context * context = - pd().cap_tree().find(user_arg_4()); + pd().cap_tree().find(user_arg_5()); if (!context) { user_arg_0(cap_id_invalid()); return; } - _call_new((void*)user_arg_2(), context, (void*)user_arg_3()); + _call_new((unsigned)user_arg_2(), *(Board::Vm_state*)user_arg_3(), + *context, (void*)user_arg_4()); } diff --git a/repos/base-hw/src/core/spec/arm/trustzone_board.h b/repos/base-hw/src/core/spec/arm/trustzone_board.h new file mode 100644 index 0000000000..6f589b4269 --- /dev/null +++ b/repos/base-hw/src/core/spec/arm/trustzone_board.h @@ -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 + +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_ */ diff --git a/repos/base-hw/src/core/spec/arm/virtualization/gicv2.cc b/repos/base-hw/src/core/spec/arm/virtualization/gicv2.cc new file mode 100644 index 0000000000..9d3cb8fe22 --- /dev/null +++ b/repos/base-hw/src/core/spec/arm/virtualization/gicv2.cc @@ -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 + +#include +#include + +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(); + c.vmcr = _gich.read(); + c.apr = _gich.read(); + c.eisr = _gich.read(); + c.elrsr = _gich.read(); + c.lr = _gich.read(); + _gich.write(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(c.misr); + _gich.write(c.vmcr); + _gich.write(c.apr); + _gich.write(c.elrsr); + _gich.write(c.lr); + _gich.write(0b1); +} diff --git a/repos/base-hw/src/core/spec/arm/virtualization/gicv2.h b/repos/base-hw/src/core/spec/arm/virtualization/gicv2.h new file mode 100644 index 0000000000..c1bfb78420 --- /dev/null +++ b/repos/base-hw/src/core/spec/arm/virtualization/gicv2.h @@ -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 + +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_ */ diff --git a/repos/base-hw/src/core/spec/arm/virtualization/gicv3.h b/repos/base-hw/src/core/spec/arm/virtualization/gicv3.h new file mode 100644 index 0000000000..0302bf3348 --- /dev/null +++ b/repos/base-hw/src/core/spec/arm/virtualization/gicv3.h @@ -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 + +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_ */ + diff --git a/repos/base-hw/src/core/spec/arm/virtualization/platform_services.cc b/repos/base-hw/src/core/spec/arm/virtualization/platform_services.cc index 43e3757a8d..78fd3176d2 100644 --- a/repos/base-hw/src/core/spec/arm/virtualization/platform_services.cc +++ b/repos/base-hw/src/core/spec/arm/virtualization/platform_services.cc @@ -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_service(services, vm_root); diff --git a/repos/base-hw/src/core/spec/arm/virtualization/vm_session_component.cc b/repos/base-hw/src/core/spec/arm/virtualization/vm_session_component.cc index 032acb592e..c80d4dc47a 100644 --- a/repos/base-hw/src/core/spec/arm/virtualization/vm_session_component.cc +++ b/repos/base-hw/src/core/spec/arm/virtualization/vm_session_component.cc @@ -16,8 +16,9 @@ /* core includes */ #include -#include +#include #include +#include #include using namespace Genode; @@ -26,14 +27,6 @@ static Core_mem_allocator & cma() { return static_cast(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(_alloc_table())), - _table_array(*(new (cma()) Array([this] (void * virt) { + _table(*construct_at(_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 */ diff --git a/repos/base-hw/src/core/spec/arm/vm_session_component.cc b/repos/base-hw/src/core/spec/arm/vm_session_component.cc deleted file mode 100644 index f587815683..0000000000 --- a/repos/base-hw/src/core/spec/arm/vm_session_component.cc +++ /dev/null @@ -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 -#include -#include - -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); -} diff --git a/repos/base-hw/src/core/spec/arm_v7/trustzone/kernel/vm.cc b/repos/base-hw/src/core/spec/arm_v7/trustzone/kernel/vm.cc index c10b345f7b..4d7957d0cd 100644 --- a/repos/base-hw/src/core/spec/arm_v7/trustzone/kernel/vm.cc +++ b/repos/base-hw/src/core/spec/arm_v7/trustzone/kernel/vm.cc @@ -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(_state), - (void*) cpu.stack_start()); + monitor_mode_enter_normal_world(_state, (void*) cpu.stack_start()); } diff --git a/repos/base-hw/src/core/spec/arm_v7/trustzone/vm_session_component.cc b/repos/base-hw/src/core/spec/arm_v7/trustzone/vm_session_component.cc index 93647a655f..08ec48d9d9 100644 --- a/repos/base-hw/src/core/spec/arm_v7/trustzone/vm_session_component.cc +++ b/repos/base-hw/src/core/spec/arm_v7/trustzone/vm_session_component.cc @@ -11,23 +11,44 @@ * under the terms of the GNU Affero General Public License version 3. */ -#include +/* Genode includes */ +#include + +/* core includes */ #include -#include +#include 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(_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); + } } } diff --git a/repos/base-hw/src/core/spec/arm_v7/trustzone/vm_session_component.h b/repos/base-hw/src/core/spec/arm_v7/trustzone/vm_session_component.h deleted file mode 100644 index e8ea2e3af8..0000000000 --- a/repos/base-hw/src/core/spec/arm_v7/trustzone/vm_session_component.h +++ /dev/null @@ -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 -#include -#include -#include -#include - -/* Core includes */ -#include -#include - -namespace Genode { - class Vm_session_component; -} - -class Genode::Vm_session_component -: - private Ram_quota_guard, - private Cap_quota_guard, - public Rpc_object -{ - 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 _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::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_ */ diff --git a/repos/base-hw/src/core/spec/arm_v7/virtualization/kernel/vm.cc b/repos/base-hw/src/core/spec/arm_v7/virtualization/kernel/vm.cc index a256d366b8..255236c26e 100644 --- a/repos/base-hw/src/core/spec/arm_v7/virtualization/kernel/vm.cc +++ b/repos/base-hw/src/core/spec/arm_v7/virtualization/kernel/vm.cc @@ -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(); - s->gic_misr = pic().read(); - s->gic_vmcr = pic().read(); - s->gic_apr = pic().read(); - s->gic_eisr = pic().read(); - s->gic_elrsr0 = pic().read(); - s->gic_lr[0] = pic().read >(); - s->gic_lr[1] = pic().read >(); - s->gic_lr[2] = pic().read >(); - s->gic_lr[3] = pic().read >(); + s.gic_hcr = pic().read(); + s.gic_misr = pic().read(); + s.gic_vmcr = pic().read(); + s.gic_apr = pic().read(); + s.gic_eisr = pic().read(); + s.gic_elrsr0 = pic().read(); + s.gic_lr[0] = pic().read >(); + s.gic_lr[1] = pic().read >(); + s.gic_lr[2] = pic().read >(); + s.gic_lr[3] = pic().read >(); /* disable virtual PIC CPU interface */ pic().write(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(s->gic_hcr ); - pic().write(s->gic_misr); - pic().write(s->gic_vmcr); - pic().write(s->gic_apr ); - pic().write(s->gic_elrsr0); - pic().write >(s->gic_lr[0]); - pic().write >(s->gic_lr[1]); - pic().write >(s->gic_lr[2]); - pic().write >(s->gic_lr[3]); + pic().write(s.gic_hcr ); + pic().write(s.gic_misr); + pic().write(s.gic_vmcr); + pic().write(s.gic_apr ); + pic().write(s.gic_elrsr0); + pic().write >(s.gic_lr[0]); + pic().write >(s.gic_lr[1]); + pic().write >(s.gic_lr[2]); + pic().write >(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(_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); } diff --git a/repos/base-hw/src/core/spec/arm_v8/virtualization/exception_vector.s b/repos/base-hw/src/core/spec/arm_v8/virtualization/exception_vector.s new file mode 100644 index 0000000000..8011bfeead --- /dev/null +++ b/repos/base-hw/src/core/spec/arm_v8/virtualization/exception_vector.s @@ -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 diff --git a/repos/base-hw/src/core/spec/arm_v8/virtualization/kernel/vm.cc b/repos/base-hw/src/core/spec/arm_v8/virtualization/kernel/vm.cc new file mode 100644 index 0000000000..58810fcdb5 --- /dev/null +++ b/repos/base-hw/src/core/spec/arm_v8/virtualization/kernel/vm.cc @@ -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 +#include +#include + +#include +#include +#include +#include +#include +#include + +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 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(&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(); + + /* 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); +} diff --git a/repos/base-hw/src/core/spec/arndale/board.h b/repos/base-hw/src/core/spec/arndale/board.h index 2bcc730581..f45c010b7a 100644 --- a/repos/base-hw/src/core/spec/arndale/board.h +++ b/repos/base-hw/src/core/spec/arndale/board.h @@ -17,11 +17,25 @@ #include #include #include +#include +#include +#include + +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; + + struct Vcpu_context { Vcpu_context(Kernel::Cpu &) {} }; } #endif /* _CORE__SPEC__ARNDALE__BOARD_H_ */ diff --git a/repos/base-hw/src/core/spec/imx53_qsb/board.h b/repos/base-hw/src/core/spec/imx53_qsb/board.h index 018e076fa3..241b84955f 100644 --- a/repos/base-hw/src/core/spec/imx53_qsb/board.h +++ b/repos/base-hw/src/core/spec/imx53_qsb/board.h @@ -18,10 +18,8 @@ #include #include #include +#include -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_ */ diff --git a/repos/base-hw/src/core/spec/imx7d_sabre/board.h b/repos/base-hw/src/core/spec/imx7d_sabre/board.h index e5bb0a636c..b5a32cb208 100644 --- a/repos/base-hw/src/core/spec/imx7d_sabre/board.h +++ b/repos/base-hw/src/core/spec/imx7d_sabre/board.h @@ -14,16 +14,28 @@ #ifndef _CORE__SPEC__IMX7D_SABRE__BOARD_H_ #define _CORE__SPEC__IMX7D_SABRE__BOARD_H_ -#include #include +#include #include +#include +#include +#include + +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; + + struct Vcpu_context { Vcpu_context(Kernel::Cpu &) {} }; } #endif /* _CORE__SPEC__IMX7_SABRELITE__BOARD_H_ */ diff --git a/repos/base-hw/src/core/spec/imx8q_evk/board.h b/repos/base-hw/src/core/spec/imx8q_evk/board.h index 35a58c8269..805e5287c7 100644 --- a/repos/base-hw/src/core/spec/imx8q_evk/board.h +++ b/repos/base-hw/src/core/spec/imx8q_evk/board.h @@ -15,14 +15,73 @@ #define _CORE__SPEC__IMX8Q_EVK__BOARD_H_ #include -#include #include +#include +#include +#include +#include +#include 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; + + 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_ */ diff --git a/repos/base-hw/src/core/spec/usb_armory/board.h b/repos/base-hw/src/core/spec/usb_armory/board.h index 9a4c30f6cb..adb4446ec6 100644 --- a/repos/base-hw/src/core/spec/usb_armory/board.h +++ b/repos/base-hw/src/core/spec/usb_armory/board.h @@ -18,10 +18,8 @@ #include #include #include +#include -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_ */ diff --git a/repos/base-hw/src/core/spec/x86_64/muen/board.h b/repos/base-hw/src/core/spec/x86_64/muen/board.h index a9d9392540..76eb31c96e 100644 --- a/repos/base-hw/src/core/spec/x86_64/muen/board.h +++ b/repos/base-hw/src/core/spec/x86_64/muen/board.h @@ -17,6 +17,9 @@ #include #include #include +#include + +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_ */ diff --git a/repos/base-hw/src/core/spec/x86_64/muen/kernel/vm.cc b/repos/base-hw/src/core/spec/x86_64/muen/kernel/vm.cc index f3a32bd349..4f73871d27 100644 --- a/repos/base-hw/src/core/spec/x86_64/muen/kernel/vm.cc +++ b/repos/base-hw/src/core/spec/x86_64/muen/kernel/vm.cc @@ -17,14 +17,16 @@ #include #include #include -#include -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" diff --git a/repos/base-hw/src/core/spec/x86_64/muen/kernel/vm_state.h b/repos/base-hw/src/core/spec/x86_64/muen/kernel/vm_state.h deleted file mode 100644 index f9db21c7f5..0000000000 --- a/repos/base-hw/src/core/spec/x86_64/muen/kernel/vm_state.h +++ /dev/null @@ -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_ */ diff --git a/repos/base-hw/src/core/spec/x86_64/muen/pic.h b/repos/base-hw/src/core/spec/x86_64/muen/pic.h index ef28aee6a9..00f859138d 100644 --- a/repos/base-hw/src/core/spec/x86_64/muen/pic.h +++ b/repos/base-hw/src/core/spec/x86_64/muen/pic.h @@ -26,6 +26,8 @@ class Board::Pic { public: + struct Virtual_context {}; + enum { /* * FIXME: dummy ipi value on non-SMP platform, should be removed diff --git a/repos/base-hw/src/core/spec/x86_64/muen/vm_session_component.cc b/repos/base-hw/src/core/spec/x86_64/muen/vm_session_component.cc new file mode 100644 index 0000000000..265bf60972 --- /dev/null +++ b/repos/base-hw/src/core/spec/x86_64/muen/vm_session_component.cc @@ -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 + +/* core includes */ +#include +#include + +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(_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); + } + } +} diff --git a/repos/base-hw/src/core/spec/x86_64/muen/vm_session_component.h b/repos/base-hw/src/core/spec/x86_64/muen/vm_session_component.h deleted file mode 100644 index 1e66a43e02..0000000000 --- a/repos/base-hw/src/core/spec/x86_64/muen/vm_session_component.h +++ /dev/null @@ -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 -#include -#include -#include -#include - -/* Core includes */ -#include -#include -#include -#include - -namespace Genode { - class Vm_session_component; -} - -class Genode::Vm_session_component -: - private Ram_quota_guard, - private Cap_quota_guard, - public Rpc_object -{ - private: - - Kernel_object _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::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_ */ diff --git a/repos/base-hw/src/core/vm_session_component.cc b/repos/base-hw/src/core/vm_session_component.cc new file mode 100644 index 0000000000..4f7aa91533 --- /dev/null +++ b/repos/base-hw/src/core/vm_session_component.cc @@ -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 + +/* core includes */ +#include +#include +#include +#include +#include + +using namespace Genode; + +static Core_mem_allocator & cma() { + return static_cast(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(); +} diff --git a/repos/base-hw/src/core/spec/arm/virtualization/vm_session_component.h b/repos/base-hw/src/core/vm_session_component.h similarity index 56% rename from repos/base-hw/src/core/spec/arm/virtualization/vm_session_component.h rename to repos/base-hw/src/core/vm_session_component.h index 6d507d2e18..19dcc15061 100644 --- a/repos/base-hw/src/core/spec/arm/virtualization/vm_session_component.h +++ b/repos/base-hw/src/core/vm_session_component.h @@ -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 @@ -20,14 +20,12 @@ #include #include #include -#include /* Core includes */ #include #include #include #include -#include #include @@ -39,8 +37,8 @@ class Genode::Vm_session_component : private Ram_quota_guard, private Cap_quota_guard, - public Rpc_object, - public Region_map_detach + public Rpc_object, + 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; + struct Vcpu + { + Ram_dataspace_capability ds_cap { }; + Region_map::Local_addr ds_addr { nullptr }; + Kernel_object 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 _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_ */ diff --git a/repos/base-hw/src/include/hw/memory_map.h b/repos/base-hw/src/include/hw/memory_map.h index 7ed0773096..377ee74226 100644 --- a/repos/base-hw/src/include/hw/memory_map.h +++ b/repos/base-hw/src/include/hw/memory_map.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(); } diff --git a/repos/base-hw/src/include/hw/spec/arm_64/cpu.h b/repos/base-hw/src/include/hw/spec/arm_64/cpu.h index 0c02b23333..5dee63eb5d 100644 --- a/repos/base-hw/src/include/hw/spec/arm_64/cpu.h +++ b/repos/base-hw/src/include/hw/spec/arm_64/cpu.h @@ -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; diff --git a/repos/base-hw/src/include/hw/spec/arm_64/imx8q_evk_board.h b/repos/base-hw/src/include/hw/spec/arm_64/imx8q_evk_board.h index df5e86667c..0554651066 100644 --- a/repos/base-hw/src/include/hw/spec/arm_64/imx8q_evk_board.h +++ b/repos/base-hw/src/include/hw/spec/arm_64/imx8q_evk_board.h @@ -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, }; diff --git a/repos/base-hw/src/include/hw/spec/arm_64/memory_map.h b/repos/base-hw/src/include/hw/spec/arm_64/memory_map.h new file mode 100644 index 0000000000..e6ec5afda1 --- /dev/null +++ b/repos/base-hw/src/include/hw/spec/arm_64/memory_map.h @@ -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 + +namespace Hw { + namespace Mm { + + template + 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_ */ diff --git a/repos/base-hw/src/lib/hw/spec/32bit/memory_map.cc b/repos/base-hw/src/lib/hw/spec/32bit/memory_map.cc index 223d7ead42..a572e3f4b2 100644 --- a/repos/base-hw/src/lib/hw/spec/32bit/memory_map.cc +++ b/repos/base-hw/src/lib/hw/spec/32bit/memory_map.cc @@ -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); } diff --git a/repos/base-hw/src/lib/hw/spec/64bit/memory_map.cc b/repos/base-hw/src/lib/hw/spec/64bit/memory_map.cc index ef846ef810..cf5c8a8c10 100644 --- a/repos/base-hw/src/lib/hw/spec/64bit/memory_map.cc +++ b/repos/base-hw/src/lib/hw/spec/64bit/memory_map.cc @@ -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); }