From 941e918b466f13622f13dba0290a3f5800461bd6 Mon Sep 17 00:00:00 2001 From: Stefan Kalkowski Date: Thu, 14 Nov 2019 10:52:20 +0100 Subject: [PATCH] vmm: unify armv7/v8 virtualization Fix #3638 --- .../spec/arm/cpu/vm_state_virtualization.h | 80 +- .../lib/mk/spec/arm_v7/core-hw-arndale.mk | 1 + .../spec/arm/cortex_a7_a15_virtualization.h | 115 ++ .../src/bootstrap/spec/arndale/platform.cc | 115 +- .../bootstrap/spec/imx7d_sabre/platform.cc | 103 +- .../src/bootstrap/spec/virt_qemu/platform.cc | 107 +- .../src/core/spec/arm/virtualization/board.h | 74 + .../arm_v7/virtualization/exception_vector.s | 48 +- .../spec/arm_v7/virtualization/kernel/vm.cc | 185 +-- repos/base-hw/src/core/spec/arndale/board.h | 14 +- repos/base-hw/src/core/spec/cortex_a15/cpu.h | 12 +- .../base-hw/src/core/spec/imx7d_sabre/board.h | 12 +- repos/base-hw/src/core/spec/imx8q_evk/board.h | 57 +- repos/base-hw/src/core/spec/virt_qemu/board.h | 10 +- repos/base-hw/src/include/hw/spec/arm/lpae.h | 4 +- repos/os/run/vmm_arm.run | 57 +- .../vmm/{spec/arm_v8 => }/address_space.cc | 0 .../vmm/{spec/arm_v8 => }/address_space.h | 0 repos/os/src/server/vmm/cpu_base.cc | 203 +++ repos/os/src/server/vmm/cpu_base.h | 225 +++ .../server/vmm/{spec/arm_v8 => }/exception.h | 0 repos/os/src/server/vmm/generic_timer.cc | 93 ++ .../vmm/{spec/arm_v8 => }/generic_timer.h | 6 +- .../vmm/{spec/arm_v8/gicv2.cc => gic.cc} | 39 +- .../os/src/server/vmm/{spec/arm_v8 => }/gic.h | 26 +- .../server/vmm/{spec/arm_v8 => }/hw_device.h | 0 .../src/server/vmm/{spec/arm_v8 => }/main.cc | 0 .../src/server/vmm/{spec/arm_v8 => }/mmio.cc | 6 +- .../src/server/vmm/{spec/arm_v8 => }/mmio.h | 0 .../src/server/vmm/{spec/arm_v8 => }/pl011.cc | 0 .../src/server/vmm/{spec/arm_v8 => }/pl011.h | 0 .../src/server/vmm/{spec/arm_v8 => }/psci.h | 0 .../os/src/server/vmm/{spec/arm_v8 => }/ram.h | 0 repos/os/src/server/vmm/spec/arm_v7/board.h | 90 +- repos/os/src/server/vmm/spec/arm_v7/cpu.cc | 189 +++ repos/os/src/server/vmm/spec/arm_v7/cpu.h | 91 ++ .../server/vmm/spec/arm_v7/generic_timer.cc | 41 + repos/os/src/server/vmm/spec/arm_v7/main.cc | 1379 ----------------- repos/os/src/server/vmm/spec/arm_v7/target.mk | 16 +- .../os/src/server/vmm/spec/arm_v7/test/main.s | 30 - .../src/server/vmm/spec/arm_v7/test/target.mk | 4 - repos/os/src/server/vmm/spec/arm_v7/virt.dts | 80 + repos/os/src/server/vmm/spec/arm_v8/board.h | 53 + repos/os/src/server/vmm/spec/arm_v8/cpu.cc | 326 +--- repos/os/src/server/vmm/spec/arm_v8/cpu.h | 175 +-- .../server/vmm/spec/arm_v8/generic_timer.cc | 77 - repos/os/src/server/vmm/spec/arm_v8/target.mk | 8 +- .../vmm/{spec/arm_v8 => }/virtio_console.h | 0 .../vmm/{spec/arm_v8 => }/virtio_device.cc | 0 .../vmm/{spec/arm_v8 => }/virtio_device.h | 19 +- .../server/vmm/{spec/arm_v8 => }/virtio_net.h | 0 .../os/src/server/vmm/{spec/arm_v8 => }/vm.cc | 20 +- .../os/src/server/vmm/{spec/arm_v8 => }/vm.h | 13 +- 53 files changed, 1555 insertions(+), 2648 deletions(-) create mode 100644 repos/base-hw/src/bootstrap/spec/arm/cortex_a7_a15_virtualization.h create mode 100644 repos/base-hw/src/core/spec/arm/virtualization/board.h rename repos/os/src/server/vmm/{spec/arm_v8 => }/address_space.cc (100%) rename repos/os/src/server/vmm/{spec/arm_v8 => }/address_space.h (100%) create mode 100644 repos/os/src/server/vmm/cpu_base.cc create mode 100644 repos/os/src/server/vmm/cpu_base.h rename repos/os/src/server/vmm/{spec/arm_v8 => }/exception.h (100%) create mode 100644 repos/os/src/server/vmm/generic_timer.cc rename repos/os/src/server/vmm/{spec/arm_v8 => }/generic_timer.h (93%) rename repos/os/src/server/vmm/{spec/arm_v8/gicv2.cc => gic.cc} (82%) rename repos/os/src/server/vmm/{spec/arm_v8 => }/gic.h (94%) rename repos/os/src/server/vmm/{spec/arm_v8 => }/hw_device.h (100%) rename repos/os/src/server/vmm/{spec/arm_v8 => }/main.cc (100%) rename repos/os/src/server/vmm/{spec/arm_v8 => }/mmio.cc (94%) rename repos/os/src/server/vmm/{spec/arm_v8 => }/mmio.h (100%) rename repos/os/src/server/vmm/{spec/arm_v8 => }/pl011.cc (100%) rename repos/os/src/server/vmm/{spec/arm_v8 => }/pl011.h (100%) rename repos/os/src/server/vmm/{spec/arm_v8 => }/psci.h (100%) rename repos/os/src/server/vmm/{spec/arm_v8 => }/ram.h (100%) create mode 100644 repos/os/src/server/vmm/spec/arm_v7/cpu.cc create mode 100644 repos/os/src/server/vmm/spec/arm_v7/cpu.h create mode 100644 repos/os/src/server/vmm/spec/arm_v7/generic_timer.cc delete mode 100644 repos/os/src/server/vmm/spec/arm_v7/main.cc delete mode 100644 repos/os/src/server/vmm/spec/arm_v7/test/main.s delete mode 100644 repos/os/src/server/vmm/spec/arm_v7/test/target.mk create mode 100755 repos/os/src/server/vmm/spec/arm_v7/virt.dts create mode 100644 repos/os/src/server/vmm/spec/arm_v8/board.h rename repos/os/src/server/vmm/{spec/arm_v8 => }/virtio_console.h (100%) rename repos/os/src/server/vmm/{spec/arm_v8 => }/virtio_device.cc (100%) rename repos/os/src/server/vmm/{spec/arm_v8 => }/virtio_device.h (96%) rename repos/os/src/server/vmm/{spec/arm_v8 => }/virtio_net.h (100%) rename repos/os/src/server/vmm/{spec/arm_v8 => }/vm.cc (70%) rename repos/os/src/server/vmm/{spec/arm_v8 => }/vm.h (86%) diff --git a/repos/base-hw/include/spec/arm/cpu/vm_state_virtualization.h b/repos/base-hw/include/spec/arm/cpu/vm_state_virtualization.h index 1bcb22e9e..3fce06d50 100644 --- a/repos/base-hw/include/spec/arm/cpu/vm_state_virtualization.h +++ b/repos/base-hw/include/spec/arm/cpu/vm_state_virtualization.h @@ -27,59 +27,55 @@ namespace Genode struct Genode::Vm_state : Genode::Cpu_state_modes { - Genode::uint64_t vttbr; - Genode::uint32_t sctrl; - Genode::uint32_t hsr; - Genode::uint32_t hpfar; - Genode::uint32_t hdfar; - Genode::uint32_t hifar; - Genode::uint32_t ttbcr; - Genode::uint32_t ttbr0; - Genode::uint32_t ttbr1; - Genode::uint32_t prrr; - Genode::uint32_t nmrr; - Genode::uint32_t dacr; - Genode::uint32_t dfsr; - Genode::uint32_t ifsr; - Genode::uint32_t adfsr; - Genode::uint32_t aifsr; - Genode::uint32_t dfar; - Genode::uint32_t ifar; - Genode::uint32_t cidr; - Genode::uint32_t tls1; - Genode::uint32_t tls2; - Genode::uint32_t tls3; - Genode::uint32_t cpacr; + Genode::uint64_t vttbr { 0 }; + Genode::uint32_t sctrl { 0 }; + Genode::uint32_t esr_el2 { 0 }; + Genode::uint32_t hpfar_el2 { 0 }; + Genode::uint32_t far_el2 { 0 }; + Genode::uint32_t hifar { 0 }; + Genode::uint32_t ttbcr { 0 }; + Genode::uint32_t ttbr0 { 0 }; + Genode::uint32_t ttbr1 { 0 }; + Genode::uint32_t prrr { 0 }; + Genode::uint32_t nmrr { 0 }; + Genode::uint32_t dacr { 0 }; + Genode::uint32_t dfsr { 0 }; + Genode::uint32_t ifsr { 0 }; + Genode::uint32_t adfsr { 0 }; + Genode::uint32_t aifsr { 0 }; + Genode::uint32_t dfar { 0 }; + Genode::uint32_t ifar { 0 }; + Genode::uint32_t cidr { 0 }; + Genode::uint32_t tls1 { 0 }; + Genode::uint32_t tls2 { 0 }; + Genode::uint32_t tls3 { 0 }; + Genode::uint32_t cpacr { 0 }; /** * Fpu registers */ - Genode::uint32_t fpscr; - Genode::uint64_t d0_d31[32]; + Genode::uint32_t fpscr { 0 }; + Genode::uint64_t d0_d31[32]{ 0 }; /** * Timer related registers */ - - Genode::uint32_t timer_ctrl; - Genode::uint32_t timer_val; - bool timer_irq; - + 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 {}; /** - * PIC related registers + * Interrupt related values */ - - enum { NR_IRQ = 4 }; - - Genode::uint32_t gic_hcr; - Genode::uint32_t gic_vmcr; - Genode::uint32_t gic_misr; - Genode::uint32_t gic_apr; - Genode::uint32_t gic_eisr; - Genode::uint32_t gic_elrsr0; - Genode::uint32_t gic_lr[4]; - unsigned gic_irq; + struct Pic + { + unsigned last_irq { 1023 }; + unsigned virtual_irq { 1023 }; + } irqs {}; }; #endif /* _INCLUDE__SPEC__ARNDALE__VM_STATE_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 81304cc35..3b054fe0c 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 @@ -11,6 +11,7 @@ INC_DIR += $(REP_DIR)/src/core/spec/arm/virtualization # add C++ sources SRC_CC += kernel/vm_thread_on.cc SRC_CC += spec/arm/gicv2.cc +SRC_CC += spec/arm/virtualization/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 diff --git a/repos/base-hw/src/bootstrap/spec/arm/cortex_a7_a15_virtualization.h b/repos/base-hw/src/bootstrap/spec/arm/cortex_a7_a15_virtualization.h new file mode 100644 index 000000000..afec871d9 --- /dev/null +++ b/repos/base-hw/src/bootstrap/spec/arm/cortex_a7_a15_virtualization.h @@ -0,0 +1,115 @@ +/* + * \brief Parts of platform that are specific to ARM virtualization + * \author Martin Stein + * \author Stefan Kalkowski + * \date 2020-04-02 + */ + +/* + * Copyright (C) 2020 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 + +static inline void prepare_nonsecure_world(unsigned long timer_freq) +{ + using Cpu = Hw::Arm_cpu; + + /* if we are already in HYP mode we're done (depends on u-boot version) */ + if (Cpu::Psr::M::get(Cpu::Cpsr::read()) == Cpu::Psr::M::HYP) + return; + + /* ARM generic timer counter freq needs to be set in secure mode */ + Cpu::Cntfrq::write(timer_freq); + + /* + * enable coprocessor 10 + 11 access and SMP bit access in auxiliary control + * register for non-secure world + */ + Cpu::Nsacr::access_t nsacr = 0; + Cpu::Nsacr::Cpnsae10::set(nsacr, 1); + Cpu::Nsacr::Cpnsae11::set(nsacr, 1); + Cpu::Nsacr::Ns_smp::set(nsacr, 1); + Cpu::Nsacr::write(nsacr); + + asm volatile ( + "msr sp_mon, sp \n" /* copy current mode's sp */ + "msr lr_mon, lr \n" /* copy current mode's lr */ + "cps #22 \n" /* switch to monitor mode */ + ); + + Cpu::Scr::access_t scr = 0; + Cpu::Scr::Ns::set(scr, 1); + Cpu::Scr::Fw::set(scr, 1); + Cpu::Scr::Aw::set(scr, 1); + Cpu::Scr::Scd::set(scr, 1); + Cpu::Scr::Hce::set(scr, 1); + Cpu::Scr::Sif::set(scr, 1); + Cpu::Scr::write(scr); +} + + +static inline void prepare_hypervisor(Genode::addr_t table) +{ + using Cpu = Hw::Arm_cpu; + + /* set hypervisor exception vector */ + Cpu::Hvbar::write(Hw::Mm::hypervisor_exception_vector().base); + + /* set hypervisor's translation table */ + Cpu::Httbr_64bit::write(table); + + Cpu::Ttbcr::access_t ttbcr = 0; + Cpu::Ttbcr::Irgn0::set(ttbcr, 1); + Cpu::Ttbcr::Orgn0::set(ttbcr, 1); + Cpu::Ttbcr::Sh0::set(ttbcr, 2); + Cpu::Ttbcr::Eae::set(ttbcr, 1); + + /* prepare MMU usage by hypervisor code */ + Cpu::Htcr::write(ttbcr); + + /* don't trap on cporocessor 10 + 11, but all others */ + Cpu::Hcptr::access_t hcptr = 0; + Cpu::Hcptr::Tcp<0>::set(hcptr, 1); + Cpu::Hcptr::Tcp<1>::set(hcptr, 1); + Cpu::Hcptr::Tcp<2>::set(hcptr, 1); + Cpu::Hcptr::Tcp<3>::set(hcptr, 1); + Cpu::Hcptr::Tcp<4>::set(hcptr, 1); + Cpu::Hcptr::Tcp<5>::set(hcptr, 1); + Cpu::Hcptr::Tcp<6>::set(hcptr, 1); + Cpu::Hcptr::Tcp<7>::set(hcptr, 1); + Cpu::Hcptr::Tcp<8>::set(hcptr, 1); + Cpu::Hcptr::Tcp<9>::set(hcptr, 1); + Cpu::Hcptr::Tcp<12>::set(hcptr, 1); + Cpu::Hcptr::Tcp<13>::set(hcptr, 1); + Cpu::Hcptr::Tta::set(hcptr, 1); + Cpu::Hcptr::write(hcptr); + + enum Memory_attributes { + DEVICE_MEMORY = 0x04, + NORMAL_MEMORY_UNCACHED = 0x44, + NORMAL_MEMORY_CACHED = 0xff, + }; + + Cpu::Mair0::access_t mair0 = 0; + Cpu::Mair0::Attr0::set(mair0, NORMAL_MEMORY_UNCACHED); + Cpu::Mair0::Attr1::set(mair0, DEVICE_MEMORY); + Cpu::Mair0::Attr2::set(mair0, NORMAL_MEMORY_CACHED); + Cpu::Mair0::Attr3::set(mair0, DEVICE_MEMORY); + Cpu::Hmair0::write(mair0); + + Cpu::Vtcr::access_t vtcr = ttbcr; + Cpu::Vtcr::Sl0::set(vtcr, 1); /* set to starting level 1 */ + Cpu::Vtcr::write(vtcr); + + Cpu::Sctlr::access_t sctlr = Cpu::Sctlr::read(); + Cpu::Sctlr::C::set(sctlr, 1); + Cpu::Sctlr::I::set(sctlr, 1); + Cpu::Sctlr::V::set(sctlr, 1); + Cpu::Sctlr::M::set(sctlr, 1); + Cpu::Sctlr::Z::set(sctlr, 1); + Cpu::Hsctlr::write(sctlr); +} diff --git a/repos/base-hw/src/bootstrap/spec/arndale/platform.cc b/repos/base-hw/src/bootstrap/spec/arndale/platform.cc index 7913055f6..669bc6547 100644 --- a/repos/base-hw/src/bootstrap/spec/arndale/platform.cc +++ b/repos/base-hw/src/bootstrap/spec/arndale/platform.cc @@ -11,6 +11,7 @@ * under the terms of the GNU Affero General Public License version 3. */ +#include #include extern "C" void * _start_setup_stack; /* entrypoint for non-boot CPUs */ @@ -25,110 +26,6 @@ Bootstrap::Platform::Board::Board() Memory_region { UART_2_MMIO_BASE, UART_2_MMIO_SIZE }) { } -static inline void prepare_nonsecure_world() -{ - using Cpu = Hw::Arm_cpu; - - /* if we are already in HYP mode we're done (depends on u-boot version) */ - if (Cpu::Psr::M::get(Cpu::Cpsr::read()) == Cpu::Psr::M::HYP) - return; - - /* ARM generic timer counter freq needs to be set in secure mode */ - volatile unsigned long * mct_control = (unsigned long*) 0x101C0240; - *mct_control = 0x100; - Cpu::Cntfrq::write(24000000); - - /* - * enable coprocessor 10 + 11 access and SMP bit access in auxiliary control - * register for non-secure world - */ - Cpu::Nsacr::access_t nsacr = 0; - Cpu::Nsacr::Cpnsae10::set(nsacr, 1); - Cpu::Nsacr::Cpnsae11::set(nsacr, 1); - Cpu::Nsacr::Ns_smp::set(nsacr, 1); - Cpu::Nsacr::write(nsacr); - - asm volatile ( - "msr sp_mon, sp \n" /* copy current mode's sp */ - "msr lr_mon, lr \n" /* copy current mode's lr */ - "cps #22 \n" /* switch to monitor mode */ - ); - - Cpu::Scr::access_t scr = 0; - Cpu::Scr::Ns::set(scr, 1); - Cpu::Scr::Fw::set(scr, 1); - Cpu::Scr::Aw::set(scr, 1); - Cpu::Scr::Scd::set(scr, 1); - Cpu::Scr::Hce::set(scr, 1); - Cpu::Scr::Sif::set(scr, 1); - Cpu::Scr::write(scr); -} - - -static inline void prepare_hypervisor(Genode::addr_t table) -{ - using Cpu = Hw::Arm_cpu; - - /* set hypervisor exception vector */ - Cpu::Hvbar::write(Hw::Mm::hypervisor_exception_vector().base); - - /* set hypervisor's translation table */ - Cpu::Httbr_64bit::write(table); - - Cpu::Ttbcr::access_t ttbcr = 0; - Cpu::Ttbcr::Irgn0::set(ttbcr, 1); - Cpu::Ttbcr::Orgn0::set(ttbcr, 1); - Cpu::Ttbcr::Sh0::set(ttbcr, 2); - Cpu::Ttbcr::Eae::set(ttbcr, 1); - - /* prepare MMU usage by hypervisor code */ - Cpu::Htcr::write(ttbcr); - - /* don't trap on cporocessor 10 + 11, but all others */ - Cpu::Hcptr::access_t hcptr = 0; - Cpu::Hcptr::Tcp<0>::set(hcptr, 1); - Cpu::Hcptr::Tcp<1>::set(hcptr, 1); - Cpu::Hcptr::Tcp<2>::set(hcptr, 1); - Cpu::Hcptr::Tcp<3>::set(hcptr, 1); - Cpu::Hcptr::Tcp<4>::set(hcptr, 1); - Cpu::Hcptr::Tcp<5>::set(hcptr, 1); - Cpu::Hcptr::Tcp<6>::set(hcptr, 1); - Cpu::Hcptr::Tcp<7>::set(hcptr, 1); - Cpu::Hcptr::Tcp<8>::set(hcptr, 1); - Cpu::Hcptr::Tcp<9>::set(hcptr, 1); - Cpu::Hcptr::Tcp<12>::set(hcptr, 1); - Cpu::Hcptr::Tcp<13>::set(hcptr, 1); - Cpu::Hcptr::Tta::set(hcptr, 1); - Cpu::Hcptr::Tcpac::set(hcptr, 1); - Cpu::Hcptr::write(hcptr); - - enum Memory_attributes { - DEVICE_MEMORY = 0x04, - NORMAL_MEMORY_UNCACHED = 0x44, - NORMAL_MEMORY_CACHED = 0xff, - }; - - Cpu::Mair0::access_t mair0 = 0; - Cpu::Mair0::Attr0::set(mair0, NORMAL_MEMORY_UNCACHED); - Cpu::Mair0::Attr1::set(mair0, DEVICE_MEMORY); - Cpu::Mair0::Attr2::set(mair0, NORMAL_MEMORY_CACHED); - Cpu::Mair0::Attr3::set(mair0, DEVICE_MEMORY); - Cpu::Hmair0::write(mair0); - - Cpu::Vtcr::access_t vtcr = ttbcr; - Cpu::Vtcr::Sl0::set(vtcr, 1); /* set to starting level 1 */ - Cpu::Vtcr::write(vtcr); - - Cpu::Sctlr::access_t sctlr = Cpu::Sctlr::read(); - Cpu::Sctlr::C::set(sctlr, 1); - Cpu::Sctlr::I::set(sctlr, 1); - Cpu::Sctlr::V::set(sctlr, 1); - Cpu::Sctlr::M::set(sctlr, 1); - Cpu::Sctlr::Z::set(sctlr, 1); - Cpu::Hsctlr::write(sctlr); -} - - static inline void switch_to_supervisor_mode() { using Cpsr = Hw::Arm_cpu::Psr; @@ -152,24 +49,24 @@ static inline void switch_to_supervisor_mode() unsigned Bootstrap::Platform::enable_mmu() { - using namespace ::Board; - static volatile bool primary_cpu = true; + static unsigned long timer_freq = 24000000; /* locally initialize interrupt controller */ ::Board::Pic pic { }; - prepare_nonsecure_world(); + volatile unsigned long * mct_control = (unsigned long*) 0x101C0240; + *mct_control = 0x100; + prepare_nonsecure_world(timer_freq); prepare_hypervisor((addr_t)core_pd->table_base); switch_to_supervisor_mode(); Cpu::Sctlr::init(); Cpu::Cpsr::init(); - Cpu::invalidate_data_cache(); - /* primary cpu wakes up all others */ if (primary_cpu && NR_OF_CPUS > 1) { + Cpu::invalidate_data_cache(); primary_cpu = false; Cpu::wake_up_all_cpus(&_start_setup_stack); } diff --git a/repos/base-hw/src/bootstrap/spec/imx7d_sabre/platform.cc b/repos/base-hw/src/bootstrap/spec/imx7d_sabre/platform.cc index cf65b6969..e8c251531 100644 --- a/repos/base-hw/src/bootstrap/spec/imx7d_sabre/platform.cc +++ b/repos/base-hw/src/bootstrap/spec/imx7d_sabre/platform.cc @@ -13,6 +13,7 @@ #include #include +#include extern "C" void * _start_setup_stack; /* entrypoint for non-boot CPUs */ static unsigned char hyp_mode_stack[1024]; /* hypervisor mode's kernel stack */ @@ -160,108 +161,6 @@ Bootstrap::Platform::Board::Board() } -static inline void prepare_nonsecure_world(unsigned long timer_freq) -{ - using Cpu = Hw::Arm_cpu; - - /* if we are already in HYP mode we're done (depends on u-boot version) */ - if (Cpu::Psr::M::get(Cpu::Cpsr::read()) == Cpu::Psr::M::HYP) - return; - - /* ARM generic timer counter freq needs to be set in secure mode */ - Cpu::Cntfrq::write(timer_freq); - - /* - * enable coprocessor 10 + 11 access and SMP bit access in auxiliary control - * register for non-secure world - */ - Cpu::Nsacr::access_t nsacr = 0; - Cpu::Nsacr::Cpnsae10::set(nsacr, 1); - Cpu::Nsacr::Cpnsae11::set(nsacr, 1); - Cpu::Nsacr::Ns_smp::set(nsacr, 1); - Cpu::Nsacr::write(nsacr); - - asm volatile ( - "msr sp_mon, sp \n" /* copy current mode's sp */ - "msr lr_mon, lr \n" /* copy current mode's lr */ - "cps #22 \n" /* switch to monitor mode */ - ); - - Cpu::Scr::access_t scr = 0; - Cpu::Scr::Ns::set(scr, 1); - Cpu::Scr::Fw::set(scr, 1); - Cpu::Scr::Aw::set(scr, 1); - Cpu::Scr::Scd::set(scr, 1); - Cpu::Scr::Hce::set(scr, 1); - Cpu::Scr::Sif::set(scr, 1); - Cpu::Scr::write(scr); -} - - -static inline void prepare_hypervisor(Genode::addr_t table) -{ - using Cpu = Hw::Arm_cpu; - - /* set hypervisor exception vector */ - Cpu::Hvbar::write(Hw::Mm::hypervisor_exception_vector().base); - - /* set hypervisor's translation table */ - Cpu::Httbr_64bit::write(table); - - Cpu::Ttbcr::access_t ttbcr = 0; - Cpu::Ttbcr::Irgn0::set(ttbcr, 1); - Cpu::Ttbcr::Orgn0::set(ttbcr, 1); - Cpu::Ttbcr::Sh0::set(ttbcr, 2); - Cpu::Ttbcr::Eae::set(ttbcr, 1); - - /* prepare MMU usage by hypervisor code */ - Cpu::Htcr::write(ttbcr); - - /* don't trap on cporocessor 10 + 11, but all others */ - Cpu::Hcptr::access_t hcptr = 0; - Cpu::Hcptr::Tcp<0>::set(hcptr, 1); - Cpu::Hcptr::Tcp<1>::set(hcptr, 1); - Cpu::Hcptr::Tcp<2>::set(hcptr, 1); - Cpu::Hcptr::Tcp<3>::set(hcptr, 1); - Cpu::Hcptr::Tcp<4>::set(hcptr, 1); - Cpu::Hcptr::Tcp<5>::set(hcptr, 1); - Cpu::Hcptr::Tcp<6>::set(hcptr, 1); - Cpu::Hcptr::Tcp<7>::set(hcptr, 1); - Cpu::Hcptr::Tcp<8>::set(hcptr, 1); - Cpu::Hcptr::Tcp<9>::set(hcptr, 1); - Cpu::Hcptr::Tcp<12>::set(hcptr, 1); - Cpu::Hcptr::Tcp<13>::set(hcptr, 1); - Cpu::Hcptr::Tta::set(hcptr, 1); - Cpu::Hcptr::Tcpac::set(hcptr, 1); - Cpu::Hcptr::write(hcptr); - - enum Memory_attributes { - DEVICE_MEMORY = 0x04, - NORMAL_MEMORY_UNCACHED = 0x44, - NORMAL_MEMORY_CACHED = 0xff, - }; - - Cpu::Mair0::access_t mair0 = 0; - Cpu::Mair0::Attr0::set(mair0, NORMAL_MEMORY_UNCACHED); - Cpu::Mair0::Attr1::set(mair0, DEVICE_MEMORY); - Cpu::Mair0::Attr2::set(mair0, NORMAL_MEMORY_CACHED); - Cpu::Mair0::Attr3::set(mair0, DEVICE_MEMORY); - Cpu::Hmair0::write(mair0); - - Cpu::Vtcr::access_t vtcr = ttbcr; - Cpu::Vtcr::Sl0::set(vtcr, 1); /* set to starting level 1 */ - Cpu::Vtcr::write(vtcr); - - Cpu::Sctlr::access_t sctlr = Cpu::Sctlr::read(); - Cpu::Sctlr::C::set(sctlr, 1); - Cpu::Sctlr::I::set(sctlr, 1); - Cpu::Sctlr::V::set(sctlr, 1); - Cpu::Sctlr::M::set(sctlr, 1); - Cpu::Sctlr::Z::set(sctlr, 1); - Cpu::Hsctlr::write(sctlr); -} - - static inline void switch_to_supervisor_mode() { using Cpsr = Hw::Arm_cpu::Psr; diff --git a/repos/base-hw/src/bootstrap/spec/virt_qemu/platform.cc b/repos/base-hw/src/bootstrap/spec/virt_qemu/platform.cc index acd29e694..0ee53b746 100644 --- a/repos/base-hw/src/bootstrap/spec/virt_qemu/platform.cc +++ b/repos/base-hw/src/bootstrap/spec/virt_qemu/platform.cc @@ -12,6 +12,7 @@ */ #include +#include extern "C" void * _start_setup_stack; /* entrypoint for non-boot CPUs */ static unsigned char hyp_mode_stack[1024]; /* hypervisor mode's kernel stack */ @@ -30,108 +31,6 @@ Bootstrap::Platform::Board::Board() Cpu_mmio::IRQ_CONTROLLER_VT_CTRL_SIZE }) {} -static inline void prepare_nonsecure_world(unsigned long timer_freq) -{ - using Cpu = Hw::Arm_cpu; - - /* if we are already in HYP mode we're done (depends on u-boot version) */ - if (Cpu::Psr::M::get(Cpu::Cpsr::read()) == Cpu::Psr::M::HYP) - return; - - /* ARM generic timer counter freq needs to be set in secure mode */ - Cpu::Cntfrq::write(timer_freq); - - /* - * enable coprocessor 10 + 11 access and SMP bit access in auxiliary control - * register for non-secure world - */ - Cpu::Nsacr::access_t nsacr = 0; - Cpu::Nsacr::Cpnsae10::set(nsacr, 1); - Cpu::Nsacr::Cpnsae11::set(nsacr, 1); - Cpu::Nsacr::Ns_smp::set(nsacr, 1); - Cpu::Nsacr::write(nsacr); - - asm volatile ( - "msr sp_mon, sp \n" /* copy current mode's sp */ - "msr lr_mon, lr \n" /* copy current mode's lr */ - "cps #22 \n" /* switch to monitor mode */ - ); - - Cpu::Scr::access_t scr = 0; - Cpu::Scr::Ns::set(scr, 1); - Cpu::Scr::Fw::set(scr, 1); - Cpu::Scr::Aw::set(scr, 1); - Cpu::Scr::Scd::set(scr, 1); - Cpu::Scr::Hce::set(scr, 1); - Cpu::Scr::Sif::set(scr, 1); - Cpu::Scr::write(scr); -} - - -static inline void prepare_hypervisor(Genode::addr_t table) -{ - using Cpu = Hw::Arm_cpu; - - /* set hypervisor exception vector */ - Cpu::Hvbar::write(Hw::Mm::hypervisor_exception_vector().base); - - /* set hypervisor's translation table */ - Cpu::Httbr_64bit::write(table); - - Cpu::Ttbcr::access_t ttbcr = 0; - Cpu::Ttbcr::Irgn0::set(ttbcr, 1); - Cpu::Ttbcr::Orgn0::set(ttbcr, 1); - Cpu::Ttbcr::Sh0::set(ttbcr, 2); - Cpu::Ttbcr::Eae::set(ttbcr, 1); - - /* prepare MMU usage by hypervisor code */ - Cpu::Htcr::write(ttbcr); - - /* don't trap on cporocessor 10 + 11, but all others */ - Cpu::Hcptr::access_t hcptr = 0; - Cpu::Hcptr::Tcp<0>::set(hcptr, 1); - Cpu::Hcptr::Tcp<1>::set(hcptr, 1); - Cpu::Hcptr::Tcp<2>::set(hcptr, 1); - Cpu::Hcptr::Tcp<3>::set(hcptr, 1); - Cpu::Hcptr::Tcp<4>::set(hcptr, 1); - Cpu::Hcptr::Tcp<5>::set(hcptr, 1); - Cpu::Hcptr::Tcp<6>::set(hcptr, 1); - Cpu::Hcptr::Tcp<7>::set(hcptr, 1); - Cpu::Hcptr::Tcp<8>::set(hcptr, 1); - Cpu::Hcptr::Tcp<9>::set(hcptr, 1); - Cpu::Hcptr::Tcp<12>::set(hcptr, 1); - Cpu::Hcptr::Tcp<13>::set(hcptr, 1); - Cpu::Hcptr::Tta::set(hcptr, 1); - Cpu::Hcptr::Tcpac::set(hcptr, 1); - Cpu::Hcptr::write(hcptr); - - enum Memory_attributes { - DEVICE_MEMORY = 0x04, - NORMAL_MEMORY_UNCACHED = 0x44, - NORMAL_MEMORY_CACHED = 0xff, - }; - - Cpu::Mair0::access_t mair0 = 0; - Cpu::Mair0::Attr0::set(mair0, NORMAL_MEMORY_UNCACHED); - Cpu::Mair0::Attr1::set(mair0, DEVICE_MEMORY); - Cpu::Mair0::Attr2::set(mair0, NORMAL_MEMORY_CACHED); - Cpu::Mair0::Attr3::set(mair0, DEVICE_MEMORY); - Cpu::Hmair0::write(mair0); - - Cpu::Vtcr::access_t vtcr = ttbcr; - Cpu::Vtcr::Sl0::set(vtcr, 1); /* set to starting level 1 */ - Cpu::Vtcr::write(vtcr); - - Cpu::Sctlr::access_t sctlr = Cpu::Sctlr::read(); - Cpu::Sctlr::C::set(sctlr, 1); - Cpu::Sctlr::I::set(sctlr, 1); - Cpu::Sctlr::V::set(sctlr, 1); - Cpu::Sctlr::M::set(sctlr, 1); - Cpu::Sctlr::Z::set(sctlr, 1); - Cpu::Hsctlr::write(sctlr); -} - - static inline void switch_to_supervisor_mode() { using Cpsr = Hw::Arm_cpu::Psr; @@ -146,7 +45,7 @@ static inline void switch_to_supervisor_mode() "msr lr_svc, lr \n" /* copy current mode's lr */ "adr lr, 1f \n" /* load exception return address */ "msr elr_hyp, lr \n" /* copy current mode's lr to hyp lr */ - "mov sp, %[stack] \n" /* copy to hyp stack pointer */ + "mov sp, %[stack] \n" /* copy to hyp stack pointer */ "msr spsr_cxfs, %[cpsr] \n" /* set psr for supervisor mode */ "eret \n" /* exception return */ "1:":: [cpsr] "r" (cpsr), [stack] "r" (&hyp_mode_stack)); @@ -156,7 +55,6 @@ static inline void switch_to_supervisor_mode() unsigned Bootstrap::Platform::enable_mmu() { static volatile bool primary_cpu = true; - static unsigned long timer_freq = Cpu::Cntfrq::read(); /* locally initialize interrupt controller */ ::Board::Pic pic { }; @@ -168,7 +66,6 @@ unsigned Bootstrap::Platform::enable_mmu() Cpu::wake_up_all_cpus(&_start_setup_stack); } - if (false) prepare_nonsecure_world(timer_freq); prepare_hypervisor((addr_t)core_pd->table_base); switch_to_supervisor_mode(); diff --git a/repos/base-hw/src/core/spec/arm/virtualization/board.h b/repos/base-hw/src/core/spec/arm/virtualization/board.h new file mode 100644 index 000000000..9c4803013 --- /dev/null +++ b/repos/base-hw/src/core/spec/arm/virtualization/board.h @@ -0,0 +1,74 @@ +/* + * \brief Board wirh ARM virtualization support + * \author Stefan Kalkowski + * \date 2019-11-12 + */ + +/* + * 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__BOARD_H_ +#define _CORE__SPEC__ARM__VIRTUALIZATION__BOARD_H_ + +#include +#include +#include + +namespace Board { + 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__ARM__VIRTUALIZATION__BOARD_H_ */ diff --git a/repos/base-hw/src/core/spec/arm_v7/virtualization/exception_vector.s b/repos/base-hw/src/core/spec/arm_v7/virtualization/exception_vector.s index 30bccc730..c10498891 100644 --- a/repos/base-hw/src/core/spec/arm_v7/virtualization/exception_vector.s +++ b/repos/base-hw/src/core/spec/arm_v7/virtualization/exception_vector.s @@ -101,6 +101,11 @@ _host_to_vm: add r1, r0, #4 vldm r1!, {d0-d15} vldm r1!, {d16-d31} + ldm r1!, {r2-r7} + mcrr p15, 4, r2, r3, c14 /* write cntvoff */ + mcrr p15, 3, r4, r5, c14 /* write cntv_cval */ + mcr p15, 0, r6, c14, c3, 1 /* write cntv_ctl */ + mcr p15, 0, r7, c14, c1, 0 /* write cntkctl */ ldmia sp, {r0-r12} /* load vm's r0-r12 */ eret @@ -111,9 +116,7 @@ _vm_to_host: mcrr p15, 6, r1, r1, c2 /* write VTTBR */ mcr p15, 4, r1, c1, c1, 0 /* write HCR register */ mcr p15, 4, r1, c1, c1, 3 /* write HSTR register */ - mov r1, #0xf - lsl r1, #20 - mcr p15, 0, r1, c1, c0, 2 /* write CPACR */ + mrs r1, ELR_hyp /* read ip */ mrs r2, spsr /* read cpsr */ mrc p15, 0, r3, c1, c0, 0 /* read SCTRL */ @@ -124,21 +127,29 @@ _vm_to_host: mrc p15, 0, r8, c2, c0, 2 /* read TTBRC */ mrc p15, 0, r9, c2, c0, 0 /* read TTBR0 */ mrc p15, 0, r10, c2, c0, 1 /* read TTBR1 */ + mrc p15, 0, r11, c10, c2, 0 /* read PRRR */ + mrc p15, 0, r12, c10, c2, 1 /* read NMRR */ add r0, sp, #40*4 /* offset SCTRL */ - stm r0!, {r3-r10} - add r0, r0, #3*4 - mrc p15, 0, r3, c5, c0, 0 /* read DFSR */ - mrc p15, 0, r4, c5, c0, 1 /* read IFSR */ - mrc p15, 0, r5, c5, c1, 0 /* read ADFSR */ - mrc p15, 0, r6, c5, c1, 1 /* read AIFSR */ - mrc p15, 0, r7, c6, c0, 0 /* read DFAR */ - mrc p15, 0, r8, c6, c0, 2 /* read IFAR */ - mrc p15, 0, r9, c13, c0, 1 /* read CIDR */ - mrc p15, 0, r10, c13, c0, 2 /* read TLS1 */ - mrc p15, 0, r11, c13, c0, 3 /* read TLS2 */ - mrc p15, 0, r12, c13, c0, 4 /* read TLS3 */ stm r0!, {r3-r12} - add r0, r0, #4 + mrc p15, 0, r3, c3, c0, 0 /* read DACR */ + mrc p15, 0, r4, c5, c0, 0 /* read DFSR */ + mrc p15, 0, r5, c5, c0, 1 /* read IFSR */ + mrc p15, 0, r6, c5, c1, 0 /* read ADFSR */ + mrc p15, 0, r7, c5, c1, 1 /* read AIFSR */ + mrc p15, 0, r8, c6, c0, 0 /* read DFAR */ + mrc p15, 0, r9, c6, c0, 2 /* read IFAR */ + mrc p15, 0, r10, c13, c0, 1 /* read CIDR */ + mrc p15, 0, r11, c13, c0, 2 /* read TLS1 */ + mrc p15, 0, r12, c13, c0, 3 /* read TLS2 */ + stm r0!, {r3-r12} + mrc p15, 0, r3, c13, c0, 4 /* read TLS3 */ + mrc p15, 0, r4, c1, c0, 2 /* read CPACR */ + stm r0!, {r3, r4} + + mov r3, #0xf + lsl r3, #20 + mcr p15, 0, r3, c1, c0, 2 /* write CPACR */ + mov r3, #1 /* clear fpu exception state */ lsl r3, #30 vmsr fpexc, r3 @@ -146,6 +157,11 @@ _vm_to_host: stmia r0!, {r4} vstm r0!, {d0-d15} vstm r0!, {d16-d31} + mrrc p15, 4, r3, r4, c14 /* read cntvoff */ + mrrc p15, 3, r5, r6, c14 /* read cntv_cval */ + mrc p15, 0, r7, c14, c3, 1 /* write cntv_ctl */ + mrc p15, 0, r8, c14, c1, 0 /* write cntkctl */ + stm r0!, {r3-r8} add r0, sp, #13*4 ldr r3, _vt_host_context_ptr ldr sp, [r3] 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 255236c26..9126c2baf 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 @@ -55,139 +55,42 @@ struct Host_context { } vt_host_context; -struct Kernel::Vm_irq : Kernel::Irq +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() { - Vm_irq(unsigned const irq) - : - Kernel::Irq(irq, cpu_pool().executing_cpu().irq_pool()) - { } - - /** - * A VM interrupt gets injected into the VM scheduled on the current CPU - */ - void occurred() override - { - Cpu_job & job = cpu_pool().executing_cpu().scheduled_job(); - Vm *vm = dynamic_cast(&job); - if (!vm) - Genode::raw("VM timer interrupt while VM is not runnning!"); - else - vm->inject_irq(_irq_nr); - } -}; + 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); +} -struct Kernel::Virtual_pic : Genode::Mmio +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() { - struct Gich_hcr : Register<0x00, 32> { }; - struct Gich_vmcr : Register<0x08, 32> { }; - struct Gich_misr : Register<0x10, 32> { }; - struct Gich_eisr0 : Register<0x20, 32> { }; - struct Gich_elrsr0 : Register<0x30, 32> { }; - struct Gich_apr : Register<0xf0, 32> { }; - - template - struct Gich_lr : Register<0x100 + SLOT*4, 32> { }; - - Vm_irq irq { Board::VT_MAINTAINANCE_IRQ }; - - Virtual_pic() - : Genode::Mmio(Genode::Platform::mmio_to_virt(Board::Cpu_mmio::IRQ_CONTROLLER_VT_CTRL_BASE)) { } - - static Virtual_pic& pic() - { - static Virtual_pic vgic; - return vgic; - } - - /** - * Save the virtual interrupt controller state to VM state - */ - static void save (Genode::Vm_state &s) - { - s.gic_hcr = pic().read(); - 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); - } - - /** - * Load the virtual interrupt controller state from VM state - */ - 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]); - } -}; - - -struct Kernel::Virtual_timer -{ - Vm_irq irq { Board::VT_TIMER_IRQ }; - - /** - * Return virtual timer object of currently executing cpu - * - * FIXME: remove this when re-designing the CPU (issue #1252) - */ - static Virtual_timer& timer() - { - static Virtual_timer timer[NR_OF_CPUS]; - return timer[Cpu::executing_id()]; - } - - /** - * Resets the virtual timer, thereby it disables its interrupt - */ - static void reset() - { - timer().irq.disable(); - asm volatile("mcr p15, 0, %0, c14, c3, 1 \n" - "mcr p15, 0, %0, c14, c3, 0" :: "r" (0)); - } - - /** - * Save the virtual timer state to VM state - */ - static void save(Genode::Vm_state &s) - { - asm volatile("mrc p15, 0, %0, c14, c3, 0 \n" - "mrc p15, 0, %1, c14, c3, 1" : - "=r" (s.timer_val), "=r" (s.timer_ctrl)); - } - - /** - * Load the virtual timer state from VM state - */ - static void load(Genode::Vm_state &s) - { - 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)); - } -}; - + irq.disable(); + asm volatile("mcr p15, 0, %0, c14, c3, 1" :: "r" (0)); + asm volatile("mcr p15, 0, %0, c14, c1, 0" :: "r" (0b11)); +} using Vmid_allocator = Genode::Bit_allocator<256>; @@ -217,7 +120,6 @@ Kernel::Vm::Vm(unsigned, /* FIXME: smp support */ _vcpu_context(cpu_pool().primary_cpu()) { affinity(cpu_pool().primary_cpu()); - Virtual_pic::pic().irq.enable(); vt_host_context.sp = _cpu->stack_start(); vt_host_context.ttbr0 = Cpu::Ttbr0_64bit::read(); @@ -235,12 +137,9 @@ Kernel::Vm::~Vm() { alloc().free(_id); } void Kernel::Vm::exception(Cpu & cpu) { - Virtual_timer::save(_state); - switch(_state.cpu_exception) { case Genode::Cpu_state::INTERRUPT_REQUEST: case Genode::Cpu_state::FAST_INTERRUPT_REQUEST: - _state.gic_irq = Board::VT_MAINTAINANCE_IRQ; _interrupt(cpu.id()); break; default: @@ -248,13 +147,18 @@ void Kernel::Vm::exception(Cpu & cpu) _context.submit(1); } - Virtual_pic::save(_state); - Virtual_timer::reset(); + if (cpu.pic().ack_virtual_irq(_vcpu_context.pic)) + inject_irq(Board::VT_MAINTAINANCE_IRQ); + _vcpu_context.vtimer_irq.disable(); } -void Kernel::Vm::proceed(Cpu &) +void Kernel::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 */ @@ -266,11 +170,8 @@ void Kernel::Vm::proceed(Cpu &) * to transport the HSTR and HCR register descriptions into the assembler * path in a dense way */ - _state.hsr = Cpu::Hstr::init(); - _state.hpfar = Cpu::Hcr::init(); - - Virtual_pic::load(_state); - Virtual_timer::load(_state); + _state.esr_el2 = Cpu::Hstr::init(); + _state.hpfar_el2 = Cpu::Hcr::init(); hypervisor_enter_vm(_state); } @@ -278,7 +179,7 @@ void Kernel::Vm::proceed(Cpu &) void Vm::inject_irq(unsigned irq) { - _state.gic_irq = 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 f45c010b7..65e8778ff 100644 --- a/repos/base-hw/src/core/spec/arndale/board.h +++ b/repos/base-hw/src/core/spec/arndale/board.h @@ -14,28 +14,20 @@ #ifndef _CORE__SPEC__ARNDALE__BOARD_H_ #define _CORE__SPEC__ARNDALE__BOARD_H_ -#include +#include #include #include #include -#include -#include +#include namespace Kernel { class Cpu; } namespace Board { using namespace Hw::Arndale_board; - using Pic = Hw::Gicv2; + struct Virtual_local_pic {}; 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/cortex_a15/cpu.h b/repos/base-hw/src/core/spec/cortex_a15/cpu.h index 75e329d70..ed48c320b 100644 --- a/repos/base-hw/src/core/spec/cortex_a15/cpu.h +++ b/repos/base-hw/src/core/spec/cortex_a15/cpu.h @@ -41,18 +41,10 @@ class Genode::Cpu : public Arm_v7_cpu static access_t init() { /* - * allow cache (7), TLB (8) maintenance, and performance - * monitor (9), process/thread ID register (13) and timer (14) - * access. + * allow everything except c0, c11, c12, and c15 accesses. */ access_t v = 0; T<0>::set(v, 1); - T<1>::set(v, 1); - T<2>::set(v, 1); - T<3>::set(v, 1); - T<5>::set(v, 1); - T<6>::set(v, 1); - T<10>::set(v, 1); T<11>::set(v, 1); T<12>::set(v, 1); T<15>::set(v, 1); @@ -73,7 +65,6 @@ class Genode::Cpu : public Arm_v7_cpu struct Twe : Bitfield<14, 1> {}; /* trap on WFE instruction */ struct Tidcp : Bitfield<20, 1> {}; /* trap lockdown */ struct Tac : Bitfield<21, 1> {}; /* trap ACTLR accesses */ - struct Tvm : Bitfield<26, 1> {}; /* trap virtual memory ctrls */ static access_t init() { @@ -86,7 +77,6 @@ class Genode::Cpu : public Arm_v7_cpu Twe::set(v, 1); Tidcp::set(v, 1); Tac::set(v, 1); - Tvm::set(v, 1); return v; }; }; 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 b5a32cb20..8fce4163a 100644 --- a/repos/base-hw/src/core/spec/imx7d_sabre/board.h +++ b/repos/base-hw/src/core/spec/imx7d_sabre/board.h @@ -18,10 +18,7 @@ #include #include #include -#include -#include - -namespace Kernel { class Cpu; } +#include namespace Board { using namespace Hw::Imx7d_sabre_board; @@ -29,13 +26,6 @@ namespace Board { struct Virtual_local_pic {}; 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 805e5287c..7f34b0f92 100644 --- a/repos/base-hw/src/core/spec/imx8q_evk/board.h +++ b/repos/base-hw/src/core/spec/imx8q_evk/board.h @@ -18,9 +18,7 @@ #include #include #include -#include -#include -#include +#include namespace Board { using namespace Hw::Imx8q_evk_board; @@ -29,59 +27,8 @@ namespace Board { TIMER_IRQ = 14 + 16, VT_TIMER_IRQ = 11 + 16, VT_MAINTAINANCE_IRQ = 9 + 16, - VCPU_MAX = 16 + VCPU_MAX = 4 }; - - 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/virt_qemu/board.h b/repos/base-hw/src/core/spec/virt_qemu/board.h index f3d68001e..48cce8e3e 100644 --- a/repos/base-hw/src/core/spec/virt_qemu/board.h +++ b/repos/base-hw/src/core/spec/virt_qemu/board.h @@ -18,8 +18,7 @@ #include #include #include -#include -#include +#include namespace Kernel { class Cpu; } @@ -34,13 +33,6 @@ namespace Board { VT_MAINTAINANCE_IRQ = 25, 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 /* _SRC__CORE__SPEC__VIRT__QEMU_H_ */ diff --git a/repos/base-hw/src/include/hw/spec/arm/lpae.h b/repos/base-hw/src/include/hw/spec/arm/lpae.h index ef5671a16..f3956816b 100644 --- a/repos/base-hw/src/include/hw/spec/arm/lpae.h +++ b/repos/base-hw/src/include/hw/spec/arm/lpae.h @@ -250,7 +250,7 @@ class Hw::Long_translation_table | Attribute_index::create(f) | Not_global::bits(!f.global) | Base::Shareability::bits( - Base::Shareability::OUTER_SHAREABLE) + Base::Shareability::INNER_SHAREABLE) | Base::Output_address::masked(pa) | Base::Access_flag::bits(1) | Descriptor::Valid::bits(1) @@ -270,7 +270,7 @@ class Hw::Long_translation_table addr_t const pa) { return Base::Shareability::bits( - Base::Shareability::NON_SHAREABLE) + Base::Shareability::INNER_SHAREABLE) | Base::Output_address::masked(pa) | Base::Access_flag::bits(1) | Descriptor::Valid::bits(1) diff --git a/repos/os/run/vmm_arm.run b/repos/os/run/vmm_arm.run index 47f44a5da..940708661 100644 --- a/repos/os/run/vmm_arm.run +++ b/repos/os/run/vmm_arm.run @@ -87,33 +87,56 @@ if { [have_spec arm] } { if {![file exists bin/linux]} { puts "Download linux kernel ..." - exec >& /dev/null wget -c -O bin/linux http://genode.org/files/release-15.02/arm_vt/linux + exec >& /dev/null wget -c -O bin/linux http://genode.org/files/release-20.05/linux-arm32 } if {![file exists bin/dtb]} { puts "Download device tree blob ..." - exec >& /dev/null wget -c -O bin/dtb http://genode.org/files/release-15.02/arm_vt/dtb + exec >& /dev/null wget -c -O bin/dtb http://genode.org/files/release-20.05/dtb-arm32-virt + } + + if {![file exists bin/initrd]} { + puts "Download initramfs ..." + exec >& /dev/null wget -c -O bin/initrd http://genode.org/files/release-20.05/initrd-arm32 } # -# This test uses a Linux kernel built from unmodified vanilla kernel sources -# but using a slightly simplified kernel configuration, as well as device tree -# for a minimal Versatile Express Cortex A15 like emulated board. +# To obtain the linux kernel, do the following steps: +# +# wget https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.3.10.tar.xz +# +# tar -xJf linux-5.3.10.tar.xz +# cd linux-5.3.10 +# +# make O=../build-linux-aarch32 ARCH=arm CROSS_COMPILE=/usr/local/genode/tool/current/bin/genode-arm- defconfig +# make O=../build-linux-aarch32 ARCH=arm CROSS_COMPILE=/usr/local/genode/tool/current/bin/genode-arm- -j32 +# +# copy ../build-linux-aarch32/arch/arm/boot/zImage to your build directory in 'bin/linux' # -# The used sources, including the modified device tree and configuration file -# can be found in the following git repository/branch: # -# https://github.com/skalk/linux/tree/vexpress-vt +# To get the dtb (device-tree-binary), you have to compile the file: +# repos/os/src/server/vmm/spec/arm_v7/virt.dts with the dtc compiler: +# dtc repos/os/src/server/vmm/spec/arm_v7/virt.dts > bin/dtb # -# To compile the kernel and device tree blob used in this script, do the -# following steps: # -# ! git checkout https://github.com/skalk/linux.git -# ! cd linux -# ! git checkout origin/vexpress-vt -# ! make ARCH=arm CROSS_COMPILE= vexpress_config -# ! make ARCH=arm CROSS_COMPILE= -j8 Image -# ! make ARCH=arm CROSS_COMPILE= vexpress-v2p-ca15-tc1.dtb +# To construct the initrd do the following: +# * get and install gcc from bootlin: +# (https://toolchains.bootlin.com/downloads/releases/toolchains/armv7-eabihf/tarballs/) +# * build busybox +# wget https://busybox.net/downloads/busybox-1.31.1.tar.bz2 +# tar xjf busybox-1.31.1.tar.bz2 +# mkdir build-busybox-aarch32 +# cd busybox-1.31.1 +# make O=../build-busybox-aarch32 defconfig +# make O=../build-busybox-aarch32 menuconfig +# +# [*] Setting -> Build static binary (no shared libs) +# +# cd ../build-busybox-aarch32 +# make CROSS_COMPILE=/opt/armv7-eabihf--uclibc--stable-2020.02-1/bin/arm-buildroot-linux-uclibcgnueabihf- install -j6 +# * create ramdisk +# cd _install +# find . | cpio -H newc -o | gzip > ../initrd # } @@ -183,8 +206,8 @@ set boot_modules { vmm linux dtb + initrd } -append_if [have_spec arm_64] boot_modules initrd build_boot_image $boot_modules # diff --git a/repos/os/src/server/vmm/spec/arm_v8/address_space.cc b/repos/os/src/server/vmm/address_space.cc similarity index 100% rename from repos/os/src/server/vmm/spec/arm_v8/address_space.cc rename to repos/os/src/server/vmm/address_space.cc diff --git a/repos/os/src/server/vmm/spec/arm_v8/address_space.h b/repos/os/src/server/vmm/address_space.h similarity index 100% rename from repos/os/src/server/vmm/spec/arm_v8/address_space.h rename to repos/os/src/server/vmm/address_space.h diff --git a/repos/os/src/server/vmm/cpu_base.cc b/repos/os/src/server/vmm/cpu_base.cc new file mode 100644 index 000000000..dbf2a265d --- /dev/null +++ b/repos/os/src/server/vmm/cpu_base.cc @@ -0,0 +1,203 @@ +/* + * \brief VMM cpu object + * \author Stefan Kalkowski + * \date 2019-07-18 + */ + +/* + * 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 Vmm::Cpu_base; +using Vmm::Cpu; +using Vmm::Gic; + +Genode::Lock & Vmm::lock() { static Genode::Lock l {}; return l; } + + +Cpu_base::System_register::System_register(unsigned op0, + unsigned crn, + unsigned op1, + unsigned crm, + unsigned op2, + const char * name, + bool writeable, + Genode::addr_t v, + Genode::Avl_tree & tree) +: _encoding(Iss::value(op0, crn, op1, crm, op2)), + _name(name), + _writeable(writeable), + _value(v) +{ + tree.insert(this); +} + + +bool Cpu_base::_handle_sys_reg() +{ + using Iss = System_register::Iss; + + Iss::access_t v = _state.esr_el2; + System_register * reg = _reg_tree.first(); + if (reg) reg = reg->find_by_encoding(Iss::mask_encoding(v)); + + if (!reg) { + Genode::error("ignore unknown system register access @ ip=", (void*)_state.ip, ":"); + Genode::error(Iss::Direction::get(v) ? "read" : "write", + ": " + "op0=", Iss::Opcode0::get(v), " " + "op1=", Iss::Opcode1::get(v), " " + "r", Iss::Register::get(v), " " + "crn=", Iss::Crn::get(v), " " + "crm=", Iss::Crm::get(v), " ", + "op2=", Iss::Opcode2::get(v)); + if (Iss::Direction::get(v)) _state.reg(Iss::Register::get(v), 0); + _state.ip += sizeof(Genode::uint32_t); + return false; + } + + if (Iss::Direction::get(v)) { /* read access */ + _state.reg(Iss::Register::get(v), reg->read()); + } else { /* write access */ + if (!reg->writeable()) { + Genode::error("writing to system register ", + reg->name(), " not allowed!"); + return false; + } + reg->write(_state.reg(Iss::Register::get(v))); + } + _state.ip += sizeof(Genode::uint32_t); + return true; +} + + +void Cpu_base::_handle_wfi() +{ + _state.ip += sizeof(Genode::uint32_t); + + if (_state.esr_el2 & 1) return; /* WFE */ + + _active = false; + _timer.schedule_timeout(); +} + + +void Cpu_base::_handle_sync() +{ + /* check device number*/ + switch (Esr::Ec::get(_state.esr_el2)) { + case Esr::Ec::HVC: + _handle_hyper_call(); + break; + case Esr::Ec::MRC_MCR: [[fallthrough]]; + case Esr::Ec::MRS_MSR: + _handle_sys_reg(); + break; + case Esr::Ec::DA: + _handle_data_abort(); + break; + case Esr::Ec::WFI: + _handle_wfi(); + return; + case Esr::Ec::BRK: + _handle_brk(); + return; + default: + throw Exception("Unknown trap: ", + Esr::Ec::get(_state.esr_el2)); + }; +} + + +void Cpu_base::_handle_irq() +{ + switch (_state.irqs.last_irq) { + case VTIMER_IRQ: + _timer.handle_irq(); + break; + default: + _gic.handle_irq(); + }; +} + + +void Cpu_base::_handle_hyper_call() +{ + switch(_state.reg(0)) { + case Psci::PSCI_VERSION: + _state.reg(0, Psci::VERSION); + return; + case Psci::MIGRATE_INFO_TYPE: + _state.reg(0, Psci::NOT_SUPPORTED); + return; + case Psci::PSCI_FEATURES: + _state.reg(0, Psci::NOT_SUPPORTED); + return; + case Psci::CPU_ON: + _vm.cpu((unsigned)_state.reg(1), [&] (Cpu & cpu) { + cpu.state().ip = _state.reg(2); + cpu.state().reg(0, _state.reg(3)); + cpu.run(); + }); + _state.reg(0, Psci::SUCCESS); + return; + default: + Genode::warning("unknown hypercall! ", cpu_id()); + dump(); + }; +} + + +void Cpu_base::_handle_data_abort() +{ + _vm.bus().handle_memory_access(*static_cast(this)); + _state.ip += sizeof(Genode::uint32_t); +} + + +void Cpu_base::_update_state() +{ + if (!_gic.pending_irq()) return; + + _active = true; + _timer.cancel_timeout(); +} + + +unsigned Cpu_base::cpu_id() const { return _vcpu_id.id; } +void Cpu_base::run() { _vm_session.run(_vcpu_id); } +void Cpu_base::pause() { _vm_session.pause(_vcpu_id); } +bool Cpu_base::active() const { return _active; } +Cpu_base::State & Cpu_base::state() const { return _state; } +Gic::Gicd_banked & Cpu_base::gic() { return _gic; } + + +void Cpu_base::recall() +{ + Genode::Signal_transmitter(_vm_handler).submit(); +}; + + +Cpu_base::Cpu_base(Vm & vm, + Genode::Vm_connection & vm_session, + Mmio_bus & bus, + Gic & gic, + Genode::Env & env, + Genode::Heap & heap, + Genode::Entrypoint & ep) +: _vm(vm), + _vm_session(vm_session), + _heap(heap), + _vm_handler(*this, ep, *this, &Cpu_base::_handle_nothing), + _vcpu_id(_vm_session.with_upgrade([&]() { + return _vm_session.create_vcpu(heap, env, _vm_handler); + })), + _state(*((State*)env.rm().attach(_vm_session.cpu_state(_vcpu_id)))), + _gic(*this, gic, bus), + _timer(env, ep, _gic.irq(VTIMER_IRQ), *this) { } diff --git a/repos/os/src/server/vmm/cpu_base.h b/repos/os/src/server/vmm/cpu_base.h new file mode 100644 index 000000000..13b73207e --- /dev/null +++ b/repos/os/src/server/vmm/cpu_base.h @@ -0,0 +1,225 @@ +/* + * \brief VMM cpu object + * \author Stefan Kalkowski + * \date 2019-07-18 + */ + +/* + * 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 _SRC__SERVER__VMM__CPU_BASE_H_ +#define _SRC__SERVER__VMM__CPU_BASE_H_ + +#include +#include + +#include +#include +#include +#include +#include + +namespace Vmm { + class Vm; + class Cpu_base; + Genode::Lock & lock(); +} + +class Vmm::Cpu_base +{ + public: + + struct State : Genode::Vm_state + { + Genode::uint64_t reg(unsigned idx) const; + void reg(unsigned idx, Genode::uint64_t v); + }; + + struct Esr : Genode::Register<32> + { + struct Ec : Bitfield<26, 6> + { + enum { + WFI = 0x1, + MRC_MCR = 0x3, + HVC = 0x16, + MRS_MSR = 0x18, + DA = 0x24, + BRK = 0x3c + }; + }; + }; + + Cpu_base(Vm & vm, + Genode::Vm_connection & vm_session, + Mmio_bus & bus, + Gic & gic, + Genode::Env & env, + Genode::Heap & heap, + Genode::Entrypoint & ep); + + unsigned cpu_id() const; + void run(); + void pause(); + bool active() const; + State & state() const; + Gic::Gicd_banked & gic(); + void dump(); + void handle_exception(); + void recall(); + void initialize_boot(Genode::addr_t ip, + Genode::addr_t dtb); + + template + void handle_signal(FUNC handler) + { + if (active()) { + pause(); + handle_exception(); + } + + handler(); + _update_state(); + if (active()) run(); + } + + template + struct Signal_handler : Genode::Vm_handler> + { + using Base = Genode::Vm_handler>; + + Cpu_base & cpu; + T & obj; + void (T::*member)(); + + void handle() + { + try { + cpu.handle_signal([this] () { (obj.*member)(); }); + } catch(Exception &e) { + Genode::error(e); + cpu.dump(); + } + } + + Signal_handler(Cpu_base & cpu, + Genode::Entrypoint & ep, + T & o, + void (T::*f)()) + : Base(ep, *this, &Signal_handler::handle), + cpu(cpu), obj(o), member(f) {} + }; + + protected: + + class System_register : public Genode::Avl_node + { + private: + + const Esr::access_t _encoding; + const char *_name; + const bool _writeable; + Genode::uint64_t _value; + + public: + + struct Iss : Esr + { + struct Direction : Bitfield<0, 1> {}; + struct Crm : Bitfield<1, 4> {}; + struct Register : Bitfield<5, 5> {}; + struct Crn : Bitfield<10, 4> {}; + struct Opcode1 : Bitfield<14, 3> {}; + struct Opcode2 : Bitfield<17, 3> {}; + struct Opcode0 : Bitfield<20, 2> {}; + + static access_t value(unsigned op0, + unsigned crn, + unsigned op1, + unsigned crm, + unsigned op2); + + static access_t mask_encoding(access_t v); + }; + + System_register(unsigned op0, + unsigned crn, + unsigned op1, + unsigned crm, + unsigned op2, + const char * name, + bool writeable, + Genode::addr_t v, + Genode::Avl_tree & tree); + + System_register(unsigned crn, + unsigned op1, + unsigned crm, + unsigned op2, + const char * name, + bool writeable, + Genode::addr_t v, + Genode::Avl_tree & tree) + : System_register(0, crn, op1, crm, op2, + name, writeable, v, tree) {} + + const char * name() const { return _name; } + const bool writeable() const { return _writeable; } + + System_register * find_by_encoding(Iss::access_t e) + { + if (e == _encoding) return this; + + System_register * r = + Avl_node::child(e > _encoding); + return r ? r->find_by_encoding(e) : nullptr; + } + + virtual void write(Genode::addr_t v) { + _value = (Genode::addr_t)v; } + + virtual Genode::addr_t read() const { + return (Genode::addr_t)(_value); } + + + /************************ + ** Avl node interface ** + ************************/ + + bool higher(System_register *r) { + return (r->_encoding > _encoding); } + }; + + bool _active { true }; + Vm & _vm; + Genode::Vm_connection & _vm_session; + Genode::Heap & _heap; + Signal_handler _vm_handler; + Genode::Vm_session::Vcpu_id _vcpu_id; + State & _state; + Genode::Avl_tree _reg_tree; + + + /*********************** + ** Local peripherals ** + ***********************/ + + Gic::Gicd_banked _gic; + Generic_timer _timer; + + void _handle_nothing() {} + bool _handle_sys_reg(); + void _handle_brk(); + void _handle_wfi(); + void _handle_sync(); + void _handle_irq(); + void _handle_data_abort(); + void _handle_hyper_call(); + void _update_state(); +}; + +#endif /* _SRC__SERVER__VMM__CPU_BASE_H_ */ diff --git a/repos/os/src/server/vmm/spec/arm_v8/exception.h b/repos/os/src/server/vmm/exception.h similarity index 100% rename from repos/os/src/server/vmm/spec/arm_v8/exception.h rename to repos/os/src/server/vmm/exception.h diff --git a/repos/os/src/server/vmm/generic_timer.cc b/repos/os/src/server/vmm/generic_timer.cc new file mode 100644 index 000000000..c2eb4377a --- /dev/null +++ b/repos/os/src/server/vmm/generic_timer.cc @@ -0,0 +1,93 @@ +/* + * \brief VMM ARM Generic timer device model + * \author Stefan Kalkowski + * \date 2019-08-20 + */ + +/* + * 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 + +using Vmm::Generic_timer; + +bool Generic_timer::_enabled() { + return Ctrl::Enabled::get(_cpu.state().timer.control); } + + +bool Generic_timer::_masked() { + return Ctrl::Imask::get(_cpu.state().timer.control); } + + +bool Generic_timer::_pending() { + return Ctrl::Istatus::get(_cpu.state().timer.control); } + + +void Generic_timer::_handle_timeout(Genode::Duration) +{ + _cpu.handle_signal([this] (void) { + if (_enabled() && !_masked()) handle_irq(); + }); +} + + +Generic_timer::Generic_timer(Genode::Env & env, + Genode::Entrypoint & ep, + Gic::Irq & irq, + Cpu_base & cpu) +: _timer(env, ep), + _timeout(_timer, *this, &Generic_timer::_handle_timeout), + _irq(irq), + _cpu(cpu) +{ + _cpu.state().timer.irq = true; + _irq.handler(*this); +} + + +void Generic_timer::schedule_timeout() +{ + if (_pending()) { + handle_irq(); + return; + } + + if (_enabled()) { + if (_usecs_left()) { + _timeout.schedule(Genode::Microseconds(_usecs_left())); + } else _handle_timeout(Genode::Duration(Genode::Microseconds(0))); + } +} + + +void Generic_timer::cancel_timeout() +{ + if (_timeout.scheduled()) _timeout.discard(); +} + + +void Generic_timer::handle_irq() +{ + _irq.assert(); + _cpu.state().timer.irq = false; +} + + +void Generic_timer::eoi() +{ + _cpu.state().timer.irq = true; +}; + + +void Generic_timer::dump() +{ + using namespace Genode; + + log(" timer.ctl = ", Hex(_cpu.state().timer.control, Hex::PREFIX, Hex::PAD)); + log(" timer.cmp = ", Hex(_cpu.state().timer.compare, Hex::PREFIX, Hex::PAD)); +} diff --git a/repos/os/src/server/vmm/spec/arm_v8/generic_timer.h b/repos/os/src/server/vmm/generic_timer.h similarity index 93% rename from repos/os/src/server/vmm/spec/arm_v8/generic_timer.h rename to repos/os/src/server/vmm/generic_timer.h index 09ccacc36..3f0d7fba2 100644 --- a/repos/os/src/server/vmm/spec/arm_v8/generic_timer.h +++ b/repos/os/src/server/vmm/generic_timer.h @@ -22,7 +22,7 @@ #include namespace Vmm { - class Cpu; + class Cpu_base; class Generic_timer; } @@ -33,7 +33,7 @@ class Vmm::Generic_timer : Gic::Irq::Irq_handler Timer::Connection _timer; Timer::One_shot_timeout _timeout; Gic::Irq & _irq; - Cpu & _cpu; + Cpu_base & _cpu; struct Ctrl : Genode::Register<32> { @@ -56,7 +56,7 @@ class Vmm::Generic_timer : Gic::Irq::Irq_handler Generic_timer(Genode::Env & env, Genode::Entrypoint & ep, Gic::Irq & irq, - Cpu & cpu); + Cpu_base & cpu); void schedule_timeout(); void cancel_timeout(); diff --git a/repos/os/src/server/vmm/spec/arm_v8/gicv2.cc b/repos/os/src/server/vmm/gic.cc similarity index 82% rename from repos/os/src/server/vmm/spec/arm_v8/gicv2.cc rename to repos/os/src/server/vmm/gic.cc index 98cddd0d2..a8671de8f 100644 --- a/repos/os/src/server/vmm/spec/arm_v8/gicv2.cc +++ b/repos/os/src/server/vmm/gic.cc @@ -159,13 +159,13 @@ void Gic::Gicd_banked::handle_irq() irq(i).deassert(); - _cpu.state().irqs.virtual_irq = 1023; + _cpu.state().irqs.virtual_irq = SPURIOUS; } bool Gic::Gicd_banked::pending_irq() { - if (_cpu.state().irqs.virtual_irq != 1023) return true; + if (_cpu.state().irqs.virtual_irq != SPURIOUS) return true; Irq * i = _gic._pending_list.highest_enabled(); Irq * j = _pending_list.highest_enabled(); @@ -178,7 +178,7 @@ bool Gic::Gicd_banked::pending_irq() } -Gic::Gicd_banked::Gicd_banked(Cpu & cpu, Gic & gic, Mmio_bus & bus) +Gic::Gicd_banked::Gicd_banked(Cpu_base & cpu, Gic & gic, Mmio_bus & bus) : _cpu(cpu), _gic(gic) { for (unsigned i = 0; i < MAX_SGI; i++) @@ -187,11 +187,16 @@ Gic::Gicd_banked::Gicd_banked(Cpu & cpu, Gic & gic, Mmio_bus & bus) for (unsigned i = 0; i < MAX_PPI; i++) _ppi[i].construct(i+MAX_SGI, Irq::PPI, _pending_list); - _cpu.state().irqs.last_irq = 1023; - _cpu.state().irqs.virtual_irq = 1023; + _cpu.state().irqs.last_irq = SPURIOUS; + _cpu.state().irqs.virtual_irq = SPURIOUS; - _rdist.construct(0x80a0000 + (cpu.cpu_id()*0x20000), 0x20000, cpu.cpu_id(), Vm::last_cpu() == cpu.cpu_id()); - bus.add(*_rdist); + if (gic.version() >= 3) { + _rdist.construct(GICR_MMIO_START + + (cpu.cpu_id()*0x20000), 0x20000, + cpu.cpu_id(), + Vm::last_cpu() == cpu.cpu_id()); + bus.add(*_rdist); + } } @@ -218,12 +223,18 @@ void Gic::Irq_reg::write(Address_range & access, Cpu & cpu, Register value) } -Gic::Gic(const char * const name, - const Genode::uint64_t addr, - const Genode::uint64_t size, - Mmio_bus & bus, - Genode::Env & env) -: Mmio_device(name, addr, size) +unsigned Gic::version() { return _version; } + + +Gic::Gic(const char * const name, + const Genode::uint64_t addr, + const Genode::uint64_t size, + unsigned cpus, + unsigned version, + Genode::Vm_connection & vm, + Mmio_bus & bus, + Genode::Env & env) +: Mmio_device(name, addr, size), _cpu_cnt(cpus), _version(version) { add(_ctrl); add(_typer); @@ -248,4 +259,6 @@ Gic::Gic(const char * const name, _spi[i].construct(i+MAX_SGI+MAX_PPI, Irq::SPI, _pending_list); bus.add(*this); + + if (version < 3) vm.attach_pic(GICC_MMIO_START); } diff --git a/repos/os/src/server/vmm/spec/arm_v8/gic.h b/repos/os/src/server/vmm/gic.h similarity index 94% rename from repos/os/src/server/vmm/spec/arm_v8/gic.h rename to repos/os/src/server/vmm/gic.h index c8bda7bba..c7487d558 100644 --- a/repos/os/src/server/vmm/spec/arm_v8/gic.h +++ b/repos/os/src/server/vmm/gic.h @@ -18,11 +18,15 @@ #include #include +#include #include #include #include -namespace Vmm { class Gic; } +namespace Vmm { + class Cpu_base; + class Gic; +} class Vmm::Gic : public Vmm::Mmio_device { @@ -120,11 +124,11 @@ class Vmm::Gic : public Vmm::Mmio_device void handle_irq(); bool pending_irq(); - Gicd_banked(Cpu & cpu, Gic & gic, Mmio_bus & bus); + Gicd_banked(Cpu_base & cpu, Gic & gic, Mmio_bus & bus); private: - Cpu & _cpu; + Cpu_base & _cpu; Gic & _gic; Genode::Constructible _sgi[MAX_SGI]; Genode::Constructible _ppi[MAX_PPI]; @@ -137,7 +141,9 @@ class Vmm::Gic : public Vmm::Mmio_device Mmio_register gicr_ctlr { "GICR_CTLR", Mmio_register::RO, 0x0, 4, 0b10010 }; Mmio_register gicr_typer { "GICR_TYPER", Mmio_register::RO, - 0x8, 8, (Genode::uint64_t)cpu_id<<32 | cpu_id<<8 | (last ? 1<<4 : 0) }; + 0x8, 8, + (Genode::uint64_t)cpu_id<<32 | + cpu_id<<8 | (last ? 1<<4 : 0) }; Mmio_register gicr_waker { "GICR_WAKER", Mmio_register::RO, 0x14, 4, 0 }; Mmio_register gicr_pidr2 { "GICR_PIDR2", Mmio_register::RO, @@ -242,9 +248,14 @@ class Vmm::Gic : public Vmm::Mmio_device Genode::Constructible _rdist; }; + unsigned version(); + Gic(const char * const name, const Genode::uint64_t addr, const Genode::uint64_t size, + unsigned cpus, + unsigned version, + Genode::Vm_connection & vm, Mmio_bus & bus, Genode::Env & env); @@ -254,8 +265,8 @@ class Vmm::Gic : public Vmm::Mmio_device Genode::Constructible _spi[MAX_SPI]; Irq::List _pending_list; - unsigned _cpu_cnt { 2 }; /* FIXME: smp support */ - unsigned _version { 3 }; /* FIXME: version support */ + unsigned _cpu_cnt; + unsigned _version; struct Gicd_ctlr : Genode::Register<32>, Mmio_register { @@ -282,7 +293,8 @@ class Vmm::Gic : public Vmm::Mmio_device Gicd_typer(unsigned cpus) : Mmio_register("GICD_TYPER", Mmio_register::RO, 0x4, 4, - It_lines_number::bits(31) | Cpu_number::bits(cpus-1) | Id_bits::bits(9)) {} + It_lines_number::bits(31) | + Cpu_number::bits(cpus-1) | Id_bits::bits(9)) {} } _typer { _cpu_cnt }; struct Gicd_iidr : Genode::Register<32>, Mmio_register diff --git a/repos/os/src/server/vmm/spec/arm_v8/hw_device.h b/repos/os/src/server/vmm/hw_device.h similarity index 100% rename from repos/os/src/server/vmm/spec/arm_v8/hw_device.h rename to repos/os/src/server/vmm/hw_device.h diff --git a/repos/os/src/server/vmm/spec/arm_v8/main.cc b/repos/os/src/server/vmm/main.cc similarity index 100% rename from repos/os/src/server/vmm/spec/arm_v8/main.cc rename to repos/os/src/server/vmm/main.cc diff --git a/repos/os/src/server/vmm/spec/arm_v8/mmio.cc b/repos/os/src/server/vmm/mmio.cc similarity index 94% rename from repos/os/src/server/vmm/spec/arm_v8/mmio.cc rename to repos/os/src/server/vmm/mmio.cc index c7a1eb7fb..55f816b84 100644 --- a/repos/os/src/server/vmm/spec/arm_v8/mmio.cc +++ b/repos/os/src/server/vmm/mmio.cc @@ -112,11 +112,9 @@ void Vmm::Mmio_bus::handle_memory_access(Vmm::Cpu & cpu) Mmio_device & dev = get(bus_range); Address_range dev_range(ipa - dev.start,width); if (wr) { - dev.write(dev_range, cpu, (idx == 31) ? 0 : state.r[idx]); + dev.write(dev_range, cpu, state.reg(idx)); } else { - if (idx > 30) - throw Exception("Wrong register index when reading ", bus_range); - state.r[idx] = dev.read(dev_range, cpu); + state.reg(idx, dev.read(dev_range, cpu)); } } catch(Exception & e) { Genode::warning(e); diff --git a/repos/os/src/server/vmm/spec/arm_v8/mmio.h b/repos/os/src/server/vmm/mmio.h similarity index 100% rename from repos/os/src/server/vmm/spec/arm_v8/mmio.h rename to repos/os/src/server/vmm/mmio.h diff --git a/repos/os/src/server/vmm/spec/arm_v8/pl011.cc b/repos/os/src/server/vmm/pl011.cc similarity index 100% rename from repos/os/src/server/vmm/spec/arm_v8/pl011.cc rename to repos/os/src/server/vmm/pl011.cc diff --git a/repos/os/src/server/vmm/spec/arm_v8/pl011.h b/repos/os/src/server/vmm/pl011.h similarity index 100% rename from repos/os/src/server/vmm/spec/arm_v8/pl011.h rename to repos/os/src/server/vmm/pl011.h diff --git a/repos/os/src/server/vmm/spec/arm_v8/psci.h b/repos/os/src/server/vmm/psci.h similarity index 100% rename from repos/os/src/server/vmm/spec/arm_v8/psci.h rename to repos/os/src/server/vmm/psci.h diff --git a/repos/os/src/server/vmm/spec/arm_v8/ram.h b/repos/os/src/server/vmm/ram.h similarity index 100% rename from repos/os/src/server/vmm/spec/arm_v8/ram.h rename to repos/os/src/server/vmm/ram.h diff --git a/repos/os/src/server/vmm/spec/arm_v7/board.h b/repos/os/src/server/vmm/spec/arm_v7/board.h index eeea70fc3..da0a55784 100644 --- a/repos/os/src/server/vmm/spec/arm_v7/board.h +++ b/repos/os/src/server/vmm/spec/arm_v7/board.h @@ -1,77 +1,53 @@ /* - * \brief Driver for the Versatile Express A9X4 board - * \author Martin stein - * \date 2011-11-03 + * \brief VMM address space utility + * \author Stefan Kalkowski + * \date 2019-11-13 */ /* - * Copyright (C) 2011-2017 Genode Labs GmbH + * 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 _INCLUDE__PLATFORM__VEA9X4__DRIVERS__BOARD_BASE_H_ -#define _INCLUDE__PLATFORM__VEA9X4__DRIVERS__BOARD_BASE_H_ +#ifndef _SRC__SERVER__VMM__BOARD_H_ +#define _SRC__SERVER__VMM__BOARD_H_ -namespace Vea9x4 { struct Board; } +namespace Vmm { + enum { + SIZE_1_MB = 1024 * 1024, + KERNEL_OFFSET = 54 * SIZE_1_MB, + DTB_OFFSET = 64 * SIZE_1_MB, + INITRD_OFFSET = 96 * SIZE_1_MB, -/** - * Driver for the Versatile Express A9X4 board - * - * Implies the uATX motherboard and the CoreTile Express A9X4 daughterboard - */ -struct Vea9x4::Board -{ - enum - { - /* MMIO */ - MMIO_0_BASE = 0x10000000, - MMIO_0_SIZE = 0x10000000, - MMIO_1_BASE = 0x4C000000, - MMIO_1_SIZE = 0x04000000, + GIC_VERSION = 2, + GICD_MMIO_START = 0x8000000, + GICD_MMIO_SIZE = 0x10000, + GICC_MMIO_START = 0x8010000, + GICR_MMIO_START = 0x80a0000, + GICR_MMIO_SIZE = 0xf60000, - /* RAM */ - RAM_0_BASE = 0x60000000, - RAM_0_SIZE = 0x20000000, - RAM_1_BASE = 0x84000000, - RAM_1_SIZE = 0x1c000000, - RAM_2_BASE = 0x48000000, - RAM_2_SIZE = 0x02000000, + PL011_MMIO_START = 0x9000000, + PL011_MMIO_SIZE = 0x1000, + PL011_IRQ = 33, - /* UART */ - PL011_0_MMIO_BASE = MMIO_0_BASE + 0x9000, - PL011_0_MMIO_SIZE = 0x1000, - PL011_0_CLOCK = 24*1000*1000, - PL011_0_IRQ = 37, - PL011_1_IRQ = 38, - PL011_2_IRQ = 39, - PL011_3_IRQ = 40, + VIRTIO_CONSOLE_MMIO_START = 0xa000000, + VIRTIO_CONSOLE_MMIO_SIZE = 0x200, + VIRTIO_CONSOLE_IRQ = 48, - /* timer/counter */ - SP804_0_1_MMIO_BASE = MMIO_0_BASE + 0x11000, - SP804_0_1_MMIO_SIZE = 0x1000, - SP804_0_1_CLOCK = 1000*1000, - SP804_0_1_IRQ = 34, + VIRTIO_NET_MMIO_START = 0xa000200, + VIRTIO_NET_MMIO_SIZE = 0x200, + VIRTIO_NET_IRQ = 49, - /* PS2 */ - KMI_0_IRQ = 44, - KMI_1_IRQ = 45, + RAM_START = 0x40000000, + RAM_SIZE = 128 * 1024 *1024, - /* LAN */ - LAN9118_IRQ = 47, + VTIMER_IRQ = 27, - /* card reader */ - PL180_0_IRQ = 9, - PL180_1_IRQ = 10, - - /* CPU */ - CORTEX_A9_PRIVATE_MEM_BASE = 0x1e000000, - CORTEX_A9_PRIVATE_MEM_SIZE = 0x2000, - CORTEX_A9_PRIVATE_TIMER_CLK = 200010000, + MAX_CPUS = 1, }; -}; - -#endif /* _INCLUDE__PLATFORM__VEA9X4__DRIVERS__BOARD_BASE_H_ */ +} +#endif /* _SRC__SERVER__VMM__BOARD_H_ */ diff --git a/repos/os/src/server/vmm/spec/arm_v7/cpu.cc b/repos/os/src/server/vmm/spec/arm_v7/cpu.cc new file mode 100644 index 000000000..7b3f80fa5 --- /dev/null +++ b/repos/os/src/server/vmm/spec/arm_v7/cpu.cc @@ -0,0 +1,189 @@ +/* + * \brief VMM cpu object + * \author Stefan Kalkowski + * \date 2019-07-18 + */ + +/* + * 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 Vmm::Cpu_base; +using Vmm::Cpu; +using Vmm::Gic; + +Genode::uint64_t Cpu_base::State::reg(unsigned idx) const +{ + if (idx > 15) return 0; + + Genode::uint32_t * r = (Genode::uint32_t*)this; + r += idx; + return *r; +} + + +void Cpu_base::State::reg(unsigned idx, Genode::uint64_t v) +{ + if (idx > 15) return; + + Genode::uint32_t * r = (Genode::uint32_t*)this; + r += idx; + *r = v; +} + + +Cpu_base::System_register::Iss::access_t +Cpu_base::System_register::Iss::value(unsigned op0, unsigned crn, unsigned op1, + unsigned crm, unsigned op2) +{ + access_t v = 0; + Crn::set(v, crn); + Crm::set(v, crm); + Opcode1::set(v, op1); + Opcode2::set(v, op2); + return v; +}; + + +Cpu_base::System_register::Iss::access_t +Cpu_base::System_register::Iss::mask_encoding(access_t v) +{ + return Crm::masked(v) | + Crn::masked(v) | + Opcode1::masked(v) | + Opcode2::masked(v); +} + + +void Cpu_base::_handle_brk() +{ + Genode::error(__func__, " not implemented yet"); +} + + +void Cpu_base::handle_exception() +{ + /* check exception reason */ + switch (_state.cpu_exception) { + case Cpu::NO_EXCEPTION: break; + case Cpu::FIQ: [[fallthrough]]; + case Cpu::IRQ: _handle_irq(); break; + case Cpu::TRAP: _handle_sync(); break; + default: + throw Exception("Curious exception ", + _state.cpu_exception, " occured"); + } + _state.cpu_exception = Cpu::NO_EXCEPTION; +} + + +void Cpu_base::dump() +{ + using namespace Genode; + + auto lambda = [] (unsigned i) { + switch (i) { + case 0: return "und"; + case 1: return "svc"; + case 2: return "abt"; + case 3: return "irq"; + case 4: return "fiq"; + default: return "unknown"; + }; + }; + + log("VM state (", _active ? "active" : "inactive", ") :"); + for (unsigned i = 0; i < 13; i++) { + log(" r", i, " = ", + Hex(_state.reg(i), Hex::PREFIX, Hex::PAD)); + } + log(" sp = ", Hex(_state.sp, Hex::PREFIX, Hex::PAD)); + log(" lr = ", Hex(_state.lr, Hex::PREFIX, Hex::PAD)); + log(" ip = ", Hex(_state.ip, Hex::PREFIX, Hex::PAD)); + log(" cpsr = ", Hex(_state.cpsr, Hex::PREFIX, Hex::PAD)); + for (unsigned i = 0; i < State::Mode_state::MAX; i++) { + log(" sp_", lambda(i), " = ", + Hex(_state.mode[i].sp, Hex::PREFIX, Hex::PAD)); + log(" lr_", lambda(i), " = ", + Hex(_state.mode[i].lr, Hex::PREFIX, Hex::PAD)); + log(" spsr_", lambda(i), " = ", + Hex(_state.mode[i].spsr, Hex::PREFIX, Hex::PAD)); + } + log(" exception = ", _state.cpu_exception); + log(" esr_el2 = ", Hex(_state.esr_el2, Hex::PREFIX, Hex::PAD)); + log(" hpfar_el2 = ", Hex(_state.hpfar_el2, Hex::PREFIX, Hex::PAD)); + log(" far_el2 = ", Hex(_state.far_el2, Hex::PREFIX, Hex::PAD)); + log(" hifar = ", Hex(_state.hifar, Hex::PREFIX, Hex::PAD)); + log(" dfsr = ", Hex(_state.dfsr, Hex::PREFIX, Hex::PAD)); + log(" ifsr = ", Hex(_state.ifsr, Hex::PREFIX, Hex::PAD)); + log(" sctrl = ", Hex(_state.sctrl, Hex::PREFIX, Hex::PAD)); + _timer.dump(); +} + + +void Cpu_base::initialize_boot(Genode::addr_t ip, Genode::addr_t dtb) +{ + state().reg(1, 0xffffffff); /* invalid machine type */ + state().reg(2, dtb); + state().ip = ip; +} + + +Genode::addr_t Cpu::Ccsidr::read() const +{ + struct Csselr : Genode::Register<32> + { + struct Level : Bitfield<1, 4> {}; + }; + + enum { INVALID = 0xffffffff }; + + unsigned level = Csselr::Level::get(csselr.read()); + + if (level > 6) { + Genode::warning("Invalid Csselr value!"); + return INVALID; + } + + return 0; +} + + +Cpu::Cpu(Vm & vm, + Genode::Vm_connection & vm_session, + Mmio_bus & bus, + Gic & gic, + Genode::Env & env, + Genode::Heap & heap, + Genode::Entrypoint & ep) +: Cpu_base(vm, vm_session, bus, gic, env, heap, ep), + _sr_midr (0, 0, 0, 0, "MIDR", false, 0x412fc0f1, _reg_tree), + _sr_mpidr (0, 0, 0, 5, "MPIDR", false, 1<<31|cpu_id(), _reg_tree), + _sr_mmfr0 (0, 0, 1, 4, "MMFR0", false, 0x10201105, _reg_tree), + _sr_mmfr1 (0, 0, 1, 5, "MMFR1", false, 0x20000000, _reg_tree), + _sr_mmfr2 (0, 0, 1, 6, "MMFR2", false, 0x01240000, _reg_tree), + _sr_mmfr3 (0, 0, 1, 7, "MMFR3", false, 0x02102211, _reg_tree), + _sr_isar0 (0, 0, 2, 0, "ISAR0", false, 0x02101110, _reg_tree), + _sr_isar1 (0, 0, 2, 1, "ISAR1", false, 0x13112111, _reg_tree), + _sr_isar2 (0, 0, 2, 2, "ISAR2", false, 0x21232041, _reg_tree), + _sr_isar3 (0, 0, 2, 3, "ISAR3", false, 0x11112131, _reg_tree), + _sr_isar4 (0, 0, 2, 4, "ISAR4", false, 0x10011142, _reg_tree), + _sr_isar5 (0, 0, 2, 5, "ISAR5", false, 0x0, _reg_tree), + _sr_pfr0 (0, 0, 1, 0, "PFR0", false, 0x00001131, _reg_tree), + _sr_pfr1 (0, 0, 1, 1, "PFR1", false, 0x00011011, _reg_tree), + _sr_clidr (0, 1, 0, 1, "CLIDR", false, 0xa200023, _reg_tree), + _sr_csselr (0, 2, 0, 0, "CSSELR", true, 0x0, _reg_tree), + _sr_ctr (0, 0, 0, 1, "CTR", true, 0x8444c004, _reg_tree), + _sr_revidr (0, 0, 0, 6, "REVIDR", true, 0x0, _reg_tree), + _sr_ccsidr (_sr_csselr, _reg_tree), + _sr_actlr (1, 0, 0, 1, "ACTLR", true, 0x0, _reg_tree) +{ + _state.cpsr = 0x93; /* el1 mode and IRQs disabled */ + _state.sctrl = 0xc50078; +} diff --git a/repos/os/src/server/vmm/spec/arm_v7/cpu.h b/repos/os/src/server/vmm/spec/arm_v7/cpu.h new file mode 100644 index 000000000..4177fd82c --- /dev/null +++ b/repos/os/src/server/vmm/spec/arm_v7/cpu.h @@ -0,0 +1,91 @@ +/* + * \brief VMM cpu object + * \author Stefan Kalkowski + * \date 2019-07-18 + */ + +/* + * 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 _SRC__SERVER__VMM__CPU_H_ +#define _SRC__SERVER__VMM__CPU_H_ + +#include + +namespace Vmm { class Cpu; } + +class Vmm::Cpu : public Vmm::Cpu_base +{ + public: + + Cpu(Vm & vm, + Genode::Vm_connection & vm_session, + Mmio_bus & bus, + Gic & gic, + Genode::Env & env, + Genode::Heap & heap, + Genode::Entrypoint & ep); + + enum Exception_type { + NO_EXCEPTION, + RESET, + UNDEFINED, + HVC, + PF_ABORT, + DATA_ABORT, + IRQ, + FIQ, + TRAP + }; + + private: + + struct Ccsidr : System_register + { + System_register & csselr; + + Ccsidr(System_register &csselr, + Genode::Avl_tree & tree) + : System_register(0, 1, 0, 0, "CCSIDR", false, 0x0, tree), + csselr(csselr) {} + + virtual Genode::addr_t read() const override; + }; + + /****************************** + ** Identification registers ** + ******************************/ + + System_register _sr_midr; + System_register _sr_mpidr; + System_register _sr_mmfr0; + System_register _sr_mmfr1; + System_register _sr_mmfr2; + System_register _sr_mmfr3; + System_register _sr_isar0; + System_register _sr_isar1; + System_register _sr_isar2; + System_register _sr_isar3; + System_register _sr_isar4; + System_register _sr_isar5; + System_register _sr_pfr0; + System_register _sr_pfr1; + System_register _sr_clidr; + System_register _sr_csselr; + System_register _sr_ctr; + System_register _sr_revidr; + Ccsidr _sr_ccsidr; + + + /********************* + ** System register ** + *********************/ + + System_register _sr_actlr; +}; + +#endif /* _SRC__SERVER__VMM__CPU_H_ */ diff --git a/repos/os/src/server/vmm/spec/arm_v7/generic_timer.cc b/repos/os/src/server/vmm/spec/arm_v7/generic_timer.cc new file mode 100644 index 000000000..a5c78d866 --- /dev/null +++ b/repos/os/src/server/vmm/spec/arm_v7/generic_timer.cc @@ -0,0 +1,41 @@ +/* + * \brief VMM ARM Generic timer device model + * \author Stefan Kalkowski + * \date 2019-08-20 + */ + +/* + * 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 + +using Vmm::Generic_timer; + +Genode::uint64_t Generic_timer::_ticks_per_ms() +{ + static Genode::uint64_t ticks_per_ms = 0; + if (!ticks_per_ms) { + Genode::uint32_t freq = 0; + asm volatile("mrc p15, 0, %0, c14, c0, 0" : "=r" (freq)); + ticks_per_ms = freq / 1000; + } + return ticks_per_ms; +} + + +Genode::uint64_t Generic_timer::_usecs_left() +{ + Genode::uint64_t count; + Genode::uint32_t low, high; + asm volatile("mrrc p15, 0, %0, %1, c14" : "=r" (low), "=r" (high)); + count = (Genode::uint64_t)high << 32 | (Genode::uint64_t)low; + count -= _cpu.state().timer.offset; + if (count > _cpu.state().timer.compare) return 0; + return Genode::timer_ticks_to_us(_cpu.state().timer.compare - count, + _ticks_per_ms()); +} diff --git a/repos/os/src/server/vmm/spec/arm_v7/main.cc b/repos/os/src/server/vmm/spec/arm_v7/main.cc deleted file mode 100644 index d9cf55c9b..000000000 --- a/repos/os/src/server/vmm/spec/arm_v7/main.cc +++ /dev/null @@ -1,1379 +0,0 @@ -/* - * \brief VMM example for ARM Virtualization - * \author Stefan Kalkowski - * \date 2014-07-08 - */ - -/* - * Copyright (C) 2014-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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - - -struct State : Genode::Vm_state -{ - Genode::uint32_t midr; - Genode::uint32_t mpidr; - Genode::uint32_t ctr; - Genode::uint32_t ccsidr; - Genode::uint32_t clidr; - Genode::uint32_t pfr0; - Genode::uint32_t mmfr0; - Genode::uint32_t isar0; - Genode::uint32_t isar3; - Genode::uint32_t isar4; - Genode::uint32_t csselr; - Genode::uint32_t actrl; - - class Invalid_register : Genode::Exception {}; - - struct Gp_register { Genode::addr_t r[16]; }; - - struct Psr : Genode::Register<32> - { - struct Mode : Bitfield<0,5> - { - enum { - USR = 16, - FIQ = 17, - IRQ = 18, - SVC = 19, - ABORT = 23, - UND = 27 - }; - }; - - static int mode_offset(access_t v) - { - switch(Mode::get(v)) { - case Mode::FIQ: return Mode_state::Mode::FIQ; - case Mode::IRQ: return Mode_state::Mode::IRQ; - case Mode::SVC: return Mode_state::Mode::SVC; - case Mode::ABORT: return Mode_state::Mode::ABORT; - case Mode::UND: return Mode_state::Mode::UND; - default: return -1; - }; - } - }; - - Genode::addr_t * r(unsigned i) - { - unsigned mo = Psr::mode_offset(cpsr); - switch (i) { - case 13: return (mo < 0) ? &sp : &(mode[mo].sp); - case 14: return (mo < 0) ? &lr : &(mode[mo].lr); - default: return &(reinterpret_cast(this)->r[i]); - }; - } -}; - - -class Ram { - - private: - - Genode::addr_t const _base; - Genode::size_t const _size; - Genode::addr_t const _local; - - public: - - Ram(Genode::addr_t const addr, Genode::size_t const sz, - Genode::addr_t const local) - : _base(addr), _size(sz), _local(local) { } - - Genode::addr_t base() const { return _base; } - Genode::size_t size() const { return _size; } - Genode::addr_t local() const { return _local; } -}; - - -class Vm { - - private: - - enum { - RAM_ADDRESS = 0x80000000, - MACH_TYPE = 2272, /* ARNDALE = 4274; VEXPRESS = 2272 */ - KERNEL_OFFSET = 0x8000, - DTB_OFFSET = 64 * 1024 * 1024, - }; - - Genode::Vm_connection _vm; - Genode::Attached_rom_dataspace _kernel_rom; - Genode::Attached_rom_dataspace _dtb_rom; - Genode::Attached_ram_dataspace _vm_ram; - Ram _ram; - Genode::Heap _heap; - Genode::Vm_session::Vcpu_id _vcpu_id; - State & _state; - bool _active = true; - - void _load_kernel() - { - Genode::memcpy((void*)(_ram.local() + KERNEL_OFFSET), - _kernel_rom.local_addr(), - _kernel_rom.size()); - _state.ip = _ram.base() + KERNEL_OFFSET; - } - - void _load_dtb() - { - Genode::memcpy((void*)(_ram.local() + DTB_OFFSET), - _dtb_rom.local_addr(), - _dtb_rom.size()); - _state.r2 = _ram.base() + DTB_OFFSET; - } - - public: - - class Exception : Genode::Exception - { - private: - - enum { BUF_SIZE = 128 }; - char _buf[BUF_SIZE]; - - public: - - Exception(const char *fmt, ...) - { - va_list args; - va_start(args, fmt); - Genode::String_console sc(_buf, BUF_SIZE); - sc.vprintf(fmt, args); - va_end(args); - } - - Exception() : Exception("undefined") {} - - void print() { Genode::error(Genode::Cstring(_buf)); } - }; - - - Vm(const char *kernel, const char *dtb, Genode::size_t const ram_size, - Genode::Vm_handler_base &handler, Genode::Env & env) - : _vm(env), - _kernel_rom(env, kernel), - _dtb_rom(env, dtb), - _vm_ram(env.ram(), env.rm(), ram_size, Genode::UNCACHED), - _ram(RAM_ADDRESS, ram_size, (Genode::addr_t)_vm_ram.local_addr()), - _heap(env.ram(), env.rm()), - _vcpu_id(_vm.create_vcpu(_heap, env, handler)), - _state(*((State*)env.rm().attach(_vm.cpu_state(_vcpu_id)))) - { - Genode::log("ram is at ", - Genode::Hex(Genode::Dataspace_client(_vm_ram.cap()).phys_addr())); - - _vm.attach(_vm_ram.cap(), RAM_ADDRESS); - _vm.attach_pic(0x2C002000); - } - - void start() - { - Genode::memset((void*)&_state, 0, sizeof(Genode::Cpu_state_modes)); - _load_kernel(); - _load_dtb(); - _state.r1 = MACH_TYPE; - _state.cpsr = 0x93; /* SVC mode and IRQs disabled */ - - _state.timer_ctrl = 0; - _state.timer_val = 0; - _state.timer_irq = false; - - _state.gic_hcr = 0b101; - _state.gic_vmcr = 0x4c0000; - _state.gic_apr = 0; - _state.gic_lr[0] = 0; - _state.gic_lr[1] = 0; - _state.gic_lr[2] = 0; - _state.gic_lr[3] = 0; - - Genode::log("ready to run"); - } - - void run() { if (_active) _vm.run(_vcpu_id); } - void pause() { _vm.pause(_vcpu_id); } - void wait_for_interrupt() { _active = false; } - void interrupt() { _active = true; } - bool active() { return _active; } - - void dump() - { - using namespace Genode; - - const char * const modes[] = - { "und", "svc", "abt", "irq", "fiq" }; - const char * const exc[] = - { "nope", "reset", "undefined", "svc", "pf_abort", - "data_abort", "irq", "fiq", "trap" }; - - log("Cpu state:"); - log(" r0 = ", Hex(_state.r0, Hex::PREFIX, Hex::PAD)); - log(" r1 = ", Hex(_state.r1, Hex::PREFIX, Hex::PAD)); - log(" r2 = ", Hex(_state.r2, Hex::PREFIX, Hex::PAD)); - log(" r3 = ", Hex(_state.r3, Hex::PREFIX, Hex::PAD)); - log(" r4 = ", Hex(_state.r4, Hex::PREFIX, Hex::PAD)); - log(" r5 = ", Hex(_state.r5, Hex::PREFIX, Hex::PAD)); - log(" r6 = ", Hex(_state.r6, Hex::PREFIX, Hex::PAD)); - log(" r7 = ", Hex(_state.r7, Hex::PREFIX, Hex::PAD)); - log(" r8 = ", Hex(_state.r8, Hex::PREFIX, Hex::PAD)); - log(" r9 = ", Hex(_state.r9, Hex::PREFIX, Hex::PAD)); - log(" r10 = ", Hex(_state.r10, Hex::PREFIX, Hex::PAD)); - log(" r11 = ", Hex(_state.r11, Hex::PREFIX, Hex::PAD)); - log(" r12 = ", Hex(_state.r12, Hex::PREFIX, Hex::PAD)); - log(" sp = ", Hex(_state.sp, Hex::PREFIX, Hex::PAD)); - log(" lr = ", Hex(_state.lr, Hex::PREFIX, Hex::PAD)); - log(" ip = ", Hex(_state.ip, Hex::PREFIX, Hex::PAD)); - log(" cpsr = ", Hex(_state.cpsr, Hex::PREFIX, Hex::PAD)); - for (unsigned i = 0; - i < State::Mode_state::MAX; i++) { - log(" sp_", modes[i], " = ", - Hex(_state.mode[i].sp, Hex::PREFIX, Hex::PAD)); - log(" lr_", modes[i], " = ", - Hex(_state.mode[i].lr, Hex::PREFIX, Hex::PAD)); - log(" spsr_", modes[i], " = ", - Hex(_state.mode[i].spsr, Hex::PREFIX, Hex::PAD)); - } - log(" exception = ", exc[_state.cpu_exception]); - } - - State & state() const { return _state; } -}; - - - -class Vmm -{ - private: - - template - struct Signal_handler : Genode::Vm_handler> - { - using Base = Genode::Vm_handler>; - - Vmm & vmm; - T & obj; - void (T::*member)(); - - void handle() - { - try { - vmm.handle_vm([this] () { (obj.*member)(); }); - } catch(Vm::Exception &e) { - e.print(); - vmm.vm().dump(); - } - } - - Signal_handler(Vmm & vmm, Genode::Entrypoint &ep, T & o, - void (T::*f)()) - : Base(ep, *this, &Signal_handler::handle), - vmm(vmm), obj(o), member(f) {} - }; - - struct Hsr : Genode::Register<32> - { - struct Ec : Bitfield<26, 6> - { - enum { - WFI = 0x1, - CP15 = 0x3, - HVC = 0x12, - DA = 0x24 - }; - }; - }; - - class Coprocessor - { - protected: - - struct Iss : Hsr - { - struct Direction : Bitfield<0, 1> {}; - struct Crm : Bitfield<1, 4> {}; - struct Register : Bitfield<5, 4> {}; - struct Crn : Bitfield<10, 4> {}; - struct Opcode1 : Bitfield<14, 3> {}; - struct Opcode2 : Bitfield<17, 3> {}; - - static access_t value(unsigned crn, unsigned op1, - unsigned crm, unsigned op2) - { - access_t v = 0; - Crn::set(v, crn); - Crm::set(v, crm); - Opcode1::set(v, op1); - Opcode2::set(v, op2); - return v; - }; - - static access_t mask_encoding(access_t v) - { - return Crm::masked(v) | - Crn::masked(v) | - Opcode1::masked(v) | - Opcode2::masked(v); - } - }; - - - class Register : public Genode::Avl_node - { - private: - - const Iss::access_t _encoding; - const char *_name; - const bool _writeable; - Genode::uint32_t State::*_r; - const Genode::addr_t _init_value; - - public: - - Register(unsigned crn, unsigned op1, - unsigned crm, unsigned op2, - const char * name, - bool writeable, - Genode::uint32_t State::*r, - Genode::addr_t v) - : _encoding(Iss::value(crn, op1, crm, op2)), - _name(name), - _writeable(writeable), _r(r), _init_value(v) {} - - const char * name() const { return _name; } - const bool writeable() const { return _writeable; } - const Genode::addr_t init_value() const { - return _init_value; } - - Register * find_by_encoding(Iss::access_t e) - { - if (e == _encoding) return this; - - Register * r = - Avl_node::child(e > _encoding); - return r ? r->find_by_encoding(e) : nullptr; - } - - void write(State & state, Genode::addr_t v) { - state.*_r = (Genode::uint32_t)v; } - - Genode::addr_t read(State & state) const { - return (Genode::addr_t)(state.*_r); } - - - /************************ - ** Avl node interface ** - ************************/ - - bool higher(Register *r) { - return (r->_encoding > _encoding); } - }; - - Genode::Avl_tree _reg_tree; - - public: - - bool handle_trap(State & state) - { - Iss::access_t v = state.hsr; - Register * reg = _reg_tree.first(); - if (reg) reg = reg->find_by_encoding(Iss::mask_encoding(v)); - - if (!reg) { - Genode::error("unknown cp15 access @ ip=", state.ip, ":"); - Genode::error(Iss::Direction::get(v) ? "read" : "write", - ": " - "c15 ", Iss::Opcode1::get(v), " " - "r", Iss::Register::get(v), " " - "c", Iss::Crn::get(v), " " - "c", Iss::Crm::get(v), " ", - Iss::Opcode2::get(v)); - return false; - } - - if (Iss::Direction::get(v)) { /* read access */ - *(state.r(Iss::Register::get(v))) = reg->read(state); - } else { /* write access */ - if (!reg->writeable()) { - Genode::error("writing to cp15 register ", - reg->name(), " not allowed!"); - return false; - } - reg->write(state, *(state.r(Iss::Register::get(v)))); - } - state.ip += sizeof(Genode::addr_t); - return true; - } - }; - - - class Cp15 : public Coprocessor - { - private: - - Register _regs_0 { 0, 0, 0, 0, "MIDR", false, &State::midr, 0x412fc0f1 }; - Register _regs_1 { 0, 0, 0, 5, "MPIDR", false, &State::mpidr, 0x40000000 }; - Register _regs_2 { 0, 0, 0, 1, "CTR", false, &State::ctr, 0x8444c004 }; - Register _regs_3 { 0, 1, 0, 0, "CCSIDR", false, &State::ccsidr, 0x701fe00a }; - Register _regs_4 { 0, 1, 0, 1, "CLIDR", false, &State::clidr, 0x0a200023 }; - Register _regs_5 { 0, 0, 1, 0, "PFR0", false, &State::pfr0, 0x00001031 }; - Register _regs_6 { 0, 0, 1, 4, "MMFR0", false, &State::mmfr0, 0x10201105 }; - Register _regs_7 { 0, 0, 2, 0, "ISAR0", false, &State::isar0, 0x02101110 }; - Register _regs_8 { 0, 0, 2, 3, "ISAR3", false, &State::isar3, 0x11112131 }; - Register _regs_9 { 0, 0, 2, 4, "ISAR4", false, &State::isar4, 0x10011142 }; - Register _regs_10 { 0, 2, 0, 0, "CSSELR", true, &State::csselr, 0x00000000 }; - Register _regs_11 { 1, 0, 0, 0, "SCTRL", true, &State::sctrl, 0 /* 0xc5007a 0x00c5187a*/ }; - Register _regs_12 { 1, 0, 0, 1, "ACTRL", true, &State::actrl, 0x00000040 }; - Register _regs_13 { 1, 0, 0, 2, "CPACR", true, &State::cpacr, 0x00000000 }; - Register _regs_14 { 2, 0, 0, 0, "TTBR0", true, &State::ttbr0, 0x00000000 }; - Register _regs_15 { 2, 0, 0, 1, "TTBR1", true, &State::ttbr1, 0x00000000 }; - Register _regs_16 { 2, 0, 0, 2, "TTBCR", true, &State::ttbcr, 0x00000000 }; - Register _regs_17 { 3, 0, 0, 0, "DACR", true, &State::dacr, 0x55555555 }; - Register _regs_18 { 5, 0, 0, 0, "DFSR", true, &State::dfsr, 0x00000000 }; - Register _regs_19 { 5, 0, 0, 1, "IFSR", true, &State::ifsr, 0x00000000 }; - Register _regs_20 { 5, 0, 1, 0, "ADFSR", true, &State::adfsr, 0x00000000 }; - Register _regs_21 { 5, 0, 1, 1, "AIFSR", true, &State::aifsr, 0x00000000 }; - Register _regs_22 { 6, 0, 0, 0, "DFAR", true, &State::dfar, 0x00000000 }; - Register _regs_23 { 6, 0, 0, 2, "IFAR", true, &State::ifar, 0x00000000 }; - Register _regs_24 { 10, 0, 2, 0, "PRRR", true, &State::prrr, 0x00098aa4 }; - Register _regs_25 { 10, 0, 2, 1, "NMRR", true, &State::nmrr, 0x44e048e0 }; - Register _regs_26 { 13, 0, 0, 1, "CONTEXTIDR", true, &State::cidr, 0x00000000 }; - - void _init_reg(Register ®, State &state) - { - _reg_tree.insert(®); - reg.write(state, reg.init_value()); - } - - public: - - Cp15(State & state) - { - _init_reg(_regs_0, state); - _init_reg(_regs_1, state); - _init_reg(_regs_2, state); - _init_reg(_regs_3, state); - _init_reg(_regs_4, state); - _init_reg(_regs_5, state); - _init_reg(_regs_6, state); - _init_reg(_regs_7, state); - _init_reg(_regs_8, state); - _init_reg(_regs_9, state); - _init_reg(_regs_10, state); - _init_reg(_regs_11, state); - _init_reg(_regs_12, state); - _init_reg(_regs_13, state); - _init_reg(_regs_14, state); - _init_reg(_regs_15, state); - _init_reg(_regs_16, state); - _init_reg(_regs_17, state); - _init_reg(_regs_18, state); - _init_reg(_regs_19, state); - _init_reg(_regs_20, state); - _init_reg(_regs_21, state); - _init_reg(_regs_22, state); - _init_reg(_regs_23, state); - _init_reg(_regs_24, state); - _init_reg(_regs_25, state); - _init_reg(_regs_26, state); - } - }; - - - class Device : public Genode::Avl_node - { - protected: - - struct Iss : Hsr - { - struct Write : Bitfield<6, 1> {}; - struct Register : Bitfield<16, 4> {}; - struct Sign_extend : Bitfield<21, 1> {}; - struct Access_size : Bitfield<22, 2> { - enum { BYTE, HALFWORD, WORD }; }; - struct Valid : Bitfield<24, 1> {}; - - static bool valid(access_t v) { - return Valid::get(v) && !Sign_extend::get(v); } - - static bool write(access_t v) { return Write::get(v); } - static unsigned r(access_t v) { return Register::get(v); } - }; - - const char * const _name; - const Genode::uint64_t _addr; - const Genode::uint64_t _size; - Vm & _vm; - - using Error = Vm::Exception; - - public: - - Device(const char * const name, - const Genode::uint64_t addr, - const Genode::uint64_t size, - Vm & vm) - : _name(name), _addr(addr), _size(size), _vm(vm) { } - - Genode::uint64_t addr() { return _addr; } - Genode::uint64_t size() { return _size; } - const char * name() { return _name; } - - virtual void read (Genode::uint32_t * reg, - Genode::uint64_t off) { - throw Error("Device %s: word-wise read of %llx not allowed", - name(), off); } - - virtual void write (Genode::uint32_t * reg, - Genode::uint64_t off) { - throw Error("Device %s: word-wise write of %llx not allowed", - name(), off); } - - virtual void read (Genode::uint16_t * reg, - Genode::uint64_t off) { - throw Error("Device %s: halfword read of %llx not allowed", - name(), off); } - - virtual void write (Genode::uint16_t * reg, - Genode::uint64_t off) { - throw Error("Device %s: halfword write of %llx not allowed", - name(), off); } - - virtual void read (Genode::uint8_t * reg, - Genode::uint64_t off) { - throw Error("Device %s: byte-wise read of %llx not allowed", - name(), off); } - - virtual void write (Genode::uint8_t * reg, - Genode::uint64_t off) { - throw Error("Device %s: byte-wise write of %llx not allowed", - name(), off); } - - virtual void irq_enabled (unsigned irq) { } - virtual void irq_disabled(unsigned irq) { } - virtual void irq_handled (unsigned irq) { } - - void handle_memory_access(State & state) - { - using namespace Genode; - - if (!Iss::valid(state.hsr)) - throw Error("Device %s: unknown HSR=%lx", - name(), state.hsr); - - bool wr = Iss::Write::get(state.hsr); - unsigned idx = Iss::Register::get(state.hsr); - uint64_t ipa = (uint64_t)state.hpfar << 8; - uint64_t off = ipa - addr() + (state.hdfar & ((1 << 13) - 1)); - - switch (Iss::Access_size::get(state.hsr)) { - case Iss::Access_size::BYTE: - { - uint8_t * p = (uint8_t*)state.r(idx) + (off & 0b11); - wr ? write(p, off) : read(p, off); - break; - } - case Iss::Access_size::HALFWORD: - { - uint16_t * p = (uint16_t*) state.r(idx) + (off & 0b1); - wr ? write(p, off) : read(p, off); - break; - } - case Iss::Access_size::WORD: - { - uint32_t * p = (uint32_t*) state.r(idx); - wr ? write(p, off) : read(p, off); - break; - } - default: - throw Error("Device %s: invalid alignment", name()); - }; - } - - /************************ - ** Avl node interface ** - ************************/ - - bool higher(Device *d) { return d->addr() > addr(); } - - Device *find_by_addr(Genode::uint64_t a) - { - if ((a >= addr()) && (a < (addr()+size()))) - return this; - - Device *d = Avl_node::child(a > addr()); - return d ? d->find_by_addr(a) : nullptr; - } - }; - - - class Gic : public Device - { - enum { - GICD_CTLR = 0, - GICD_TYPER = 0x4, - GICD_ISENABLER0 = 0x100, - GICD_ISENABLERL = 0x17c, - GICD_ICENABLER0 = 0x180, - GICD_ICENABLERL = 0x1fc, - GICD_IPRIORITYR0 = 0x400, - GICD_IPRIORITYRL = 0x7f8, - GICD_ITARGETSR0 = 0x800, - GICD_ITARGETSRL = 0xbf8, - GICD_ICFGR2 = 0xc08, - GICD_ICFGRL = 0xcfc, - }; - - enum Irqs { - SGI_MAX = 15, - TIMER = Arm_v7::VT_TIMER_IRQ, - MAX_IRQ = 256, - }; - - struct Irq { - - enum Cpu_state { INACTIVE, PENDING }; - enum Distr_state { ENABLED, DISABLED }; - - Cpu_state cpu_state = INACTIVE; - Distr_state distr_state = DISABLED; - Device * device = nullptr; - bool eoi = false; - }; - - Irq _irqs[MAX_IRQ+1]; - bool _distr_enabled = false; - - using Error = Vm::Exception; - - - /********************** - ** GICH interface ** - **********************/ - - struct Gich_lr : Genode::Register<32> - { - struct Virt_id : Bitfield<0, 10> { }; - struct Phys_id : Bitfield<10, 10> { }; - struct Prio : Bitfield<23, 5> { }; - struct State : Bitfield<28, 2> { }; - struct Hw : Bitfield<31, 1> { }; - }; - - void _handle_eoi() - { - if (!(_vm.state().gic_misr & 1)) return; - - for (unsigned i = 0; i < State::NR_IRQ; i++) { - if (_vm.state().gic_eisr & (1 << i)) { - unsigned irq = Gich_lr::Virt_id::get(_vm.state().gic_lr[i]); - if (irq > MAX_IRQ) - throw Error("IRQ out of bounds"); - _vm.state().gic_lr[i] = 0; - _vm.state().gic_elrsr0 |= 1 << i; - if (irq == TIMER && - _irqs[irq].distr_state == Irq::ENABLED) - _vm.state().timer_irq = true; - _irqs[irq].cpu_state = Irq::INACTIVE; - } - } - - _vm.state().gic_misr = 0; - } - - void _inject_irq(unsigned irq, bool eoi) - { - if (irq == TIMER) - _vm.state().timer_irq = false; - - for (unsigned i = 0; i < State::NR_IRQ; i++) { - if (!(_vm.state().gic_elrsr0 & (1 << i))) { - Gich_lr::access_t v = _vm.state().gic_lr[i]; - if (Gich_lr::Virt_id::get(v) == irq) - return; - } - } - - for (unsigned i = 0; i < State::NR_IRQ; i++) { - if (!(_vm.state().gic_elrsr0 & (1 << i))) - continue; - - _vm.state().gic_elrsr0 &= ~(1 << i); - Gich_lr::access_t v = 0; - Gich_lr::Virt_id::set(v, irq); - Gich_lr::Phys_id::set(v, eoi ? 1 << 9 : 0); - Gich_lr::Prio::set(v, 0); - Gich_lr::State::set(v, 0b1); - _vm.state().gic_lr[i] = v; - return; - } - - throw Error("IRQ queue full, can't inject irq %u", irq); - } - - void _enable_irq(unsigned irq) - { - if (irq > MAX_IRQ || !_irqs[irq].device) - throw Error("GIC: can't enable unknown IRQ %d", irq); - - if (_irqs[irq].distr_state == Irq::ENABLED) - return; - - _irqs[irq].distr_state = Irq::ENABLED; - _irqs[irq].device->irq_enabled(irq); - - if (irq == TIMER) - _vm.state().timer_irq = true; - } - - void _disable_irq(unsigned irq) - { - if (irq > MAX_IRQ) - throw Error("IRQ out of bounds"); - - if (_irqs[irq].distr_state == Irq::DISABLED) - return; - - _irqs[irq].distr_state = Irq::DISABLED; - _irqs[irq].device->irq_disabled(irq); - - if (irq == TIMER) - _vm.state().timer_irq = false; - } - - public: - - Gic(const char * const name, - const Genode::uint64_t addr, - const Genode::uint64_t size, - Vm & vm) - : Device(name, addr, size, vm) - { - for (unsigned i = 0; i <= MAX_IRQ; i++) { - _irqs[i] = Irq(); - if (i <= SGI_MAX) - _irqs[i].device = this; - } - } - - void read (Genode::uint32_t * reg, Genode::uint64_t off) - { - if (off >= GICD_ICFGR2 && off <= GICD_ICFGRL) { - *reg = 0; - return; - } - - /* read enable registers */ - if (off >= GICD_ISENABLER0 && off <= GICD_ISENABLERL) { - *reg = 0; - Genode::addr_t idx = ((Genode::addr_t)off - GICD_ISENABLER0) * 8; - for (unsigned i = 0; i < 32; i++) { - if (_irqs[idx + i].distr_state == Irq::ENABLED) - *reg |= 1 << i; - } - return; - } - - if (off >= GICD_ITARGETSR0 && off <= GICD_ITARGETSRL) { - *reg = 0x01010101; - return; - } - - switch (off) { - case GICD_CTLR: - *reg = _distr_enabled ? 1 : 0; - return; - case GICD_TYPER: - *reg = 0b101; - return; - default: - throw Error("GIC: unsupported read offset %llx", off); - }; - } - - void write(Genode::uint32_t * reg, Genode::uint64_t off) - { - using namespace Genode; - - /* only allow cpu0 as target by now */ - if (off >= GICD_ITARGETSR0 && off <= GICD_ITARGETSRL && - *reg == 0x01010101) - return; - - /* only allow level triggered && active low */ - if (off >= GICD_ICFGR2 && off <= GICD_ICFGRL && - *reg == 0) - return; - - /* ignore priority settings */ - if (off >= GICD_IPRIORITYR0 && off <= GICD_IPRIORITYRL) - return; - - /* set enable registers */ - if (off >= GICD_ISENABLER0 && off <= GICD_ISENABLERL) { - addr_t idx = ((addr_t)off - GICD_ISENABLER0) * 8; - for (unsigned i = 0; i < 32; i++) - if (((*reg >> i) & 1)) - _enable_irq(idx+i); - return; - } - - /* clear enable registers */ - if (off >= GICD_ICENABLER0 && off <= GICD_ICENABLERL) { - addr_t idx = ((addr_t)off - GICD_ICENABLER0) * 8; - for (unsigned i = 0; i < 32; i++) - if (((*reg >> i) & 1)) - _disable_irq(idx+i); - return; - } - - switch (off) { - case GICD_CTLR: - _distr_enabled = (*reg & 0b1); - return; - default: - throw Error("GIC: unsupported write offset %llx", off); - }; - } - - void register_irq(unsigned irq, Device * d, bool eoi) - { - _irqs[irq].device = d; - _irqs[irq].eoi = eoi; - } - - void inject_irq(unsigned irq) - { - if (!_irqs[irq].device) - throw Error("No device registered for IRQ %u", irq); - - if (_irqs[irq].cpu_state == Irq::PENDING) - throw Error("Pending IRQ should not trigger again");; - - if (_irqs[irq].eoi) - _irqs[irq].cpu_state = Irq::PENDING; - - if (_irqs[irq].distr_state == Irq::DISABLED) { - Genode::warning("disabled irq ", irq, " injected"); - return; - } - - _inject_irq(irq, _irqs[irq].eoi); - _vm.interrupt(); - } - - void irq_occured() - { - switch(_vm.state().gic_irq) { - case Arm_v7::VT_MAINTAINANCE_IRQ: - _handle_eoi(); - return; - case TIMER: - inject_irq(TIMER); - return; - default: - throw Error("Unknown IRQ %u occured", - _vm.state().gic_irq); - }; - } - }; - - - class Generic_timer : public Device - { - private: - - Timer::Connection _timer; - Signal_handler _handler; - Gic &_gic; - - void _timeout() - { - _vm.state().timer_ctrl = 5; - _vm.state().timer_val = 0xffffffff; - _gic.inject_irq(Arm_v7::VT_TIMER_IRQ); - } - - public: - - Generic_timer(const char * const name, - const Genode::uint64_t addr, - const Genode::uint64_t size, - Vmm &vmm, - Genode::Env &env, - Gic &gic) - : Device(name, addr, size, vmm.vm()), - _timer(env), - _handler(vmm, env.ep(), *this, &Generic_timer::_timeout), - _gic(gic) - { - _timer.sigh(_handler); - _gic.register_irq(Arm_v7::VT_TIMER_IRQ, this, true); - } - - void schedule_timeout() - { - if ((_vm.state().timer_ctrl & 0b101) != 0b101) - _timer.trigger_once(_vm.state().timer_val / 24); - } - }; - - - class System_register : public Device - { - private: - - enum { - SYS_LED = 0x8, - SYS_FLASH = 0x4c, - SYS_24MHZ = 0x5c, - SYS_MCI = 0x48, - SYS_MISC = 0x60, - SYS_PROCID0 = 0x84, - SYS_CFGDATA = 0xa0, - SYS_CFGCTRL = 0xa4, - SYS_CFGSTAT = 0xa8, - }; - - struct Sys_cfgctrl : Genode::Register<32> - { - struct Device : Bitfield<0,12> {}; - struct Position : Bitfield<12,4> {}; - struct Site : Bitfield<16,2> {}; - struct Function : Bitfield<20,6> {}; - struct Write : Bitfield<30,1> {}; - struct Start : Bitfield<31,1> {}; - }; - - Timer::Connection _timer; - Genode::uint32_t _spi_data = 0; - Genode::uint32_t _spi_stat = 1; - - using Error = Vm::Exception; - - void _mcc_control(unsigned device, unsigned func, bool write) - { - if (func == 1 && !write) { - switch (device) { - case 0: /* OSCCLK0 */ - _spi_data = 60000000; - return; - case 2: /* OSCCLK2 */ - _spi_data = 24000000; - return; - case 4: /* OSCCLK4 */ - _spi_data = 40000000; - return; - case 5: /* OSCCLK5 */ - _spi_data = 23750000; - return; - case 6: /* OSCCLK6 */ - _spi_data = 50000000; - return; - case 7: /* OSCCLK7 */ - _spi_data = 60000000; - return; - case 8: /* OSCCLK8 */ - _spi_data = 40000000; - return; - default: - throw Error("Sys regs: unsupported MCC device"); - }; - } - - if (func == 2 && !write) { - switch (device) { - case 0: /* VOLT0 */ - _spi_data = 900000; - return; - default: ; - }; - } - - throw Error("Unknown device %u func=%u write=%d", - device, func, write); - }; - - public: - - System_register(const char * const name, - const Genode::uint64_t addr, - const Genode::uint64_t size, - Vm & vm, - Genode::Env & env) - : Device(name, addr, size, vm), _timer(env) {} - - void read(Genode::uint32_t * reg, Genode::uint64_t off) - { - switch (off) { - case SYS_LED: - *reg = 0xff; - return; - case SYS_FLASH: - *reg = 0; - return; - case SYS_24MHZ: /* 24 MHz counter */ - *reg = (Genode::uint32_t)_timer.elapsed_ms() * 24000; - return; - case SYS_MISC: - *reg = 1 << 12; - return; - case SYS_PROCID0: - *reg = 0x14000237; /* daughterboard ID */ - return; - case SYS_MCI: - *reg = 0; /* no mmc inside */ - return; - case SYS_CFGSTAT: - *reg = _spi_stat; - return; - case SYS_CFGCTRL: - *reg = 0; - return; - case SYS_CFGDATA: - *reg = _spi_data; - return; - }; - throw Error("Sys regs: read of offset %llx forbidden", off); - } - - void write(Genode::uint32_t * reg, Genode::uint64_t off) - { - switch (off) { - case SYS_CFGDATA: - _spi_data = *reg; - return; - case SYS_CFGSTAT: - _spi_stat = *reg; - return; - case SYS_CFGCTRL: - if (Sys_cfgctrl::Start::get(*reg)) { - _spi_stat = 1; - _mcc_control(Sys_cfgctrl::Device::get(*reg), - Sys_cfgctrl::Function::get(*reg), - Sys_cfgctrl::Write::get(*reg)); - return; - } - case SYS_24MHZ: - case SYS_MISC: - case SYS_PROCID0: - case SYS_MCI: - ; - }; - throw Error("Sys regs: write of offset %llx forbidden", off); - } - }; - - - class Pl011 : public Device - { - private: - - using Board = Vea9x4::Board; - using Ring_buffer = Genode::Ring_buffer; - - class Wrong_offset {}; - - enum { - UARTDR = 0x0, - UARTFR = 0x18, - UARTIBRD = 0x24, - UARTFBRD = 0x28, - UARTLCR_H = 0x2c, - UARTCR = 0x30, - UARTIFLS = 0x34, - UARTIMSC = 0x38, - UARTMIS = 0x40, - UARTICR = 0x44, - UARTPERIPHID0 = 0xfe0, - UARTPERIPHID1 = 0xfe4, - UARTPERIPHID2 = 0xfe8, - UARTPERIPHID3 = 0xfec, - UARTPCELLID0 = 0xff0, - UARTPCELLID1 = 0xff4, - UARTPCELLID2 = 0xff8, - UARTPCELLID3 = 0xffc, - }; - - Terminal::Connection _terminal; - Signal_handler _handler; - Gic &_gic; - Ring_buffer _rx_buf; - Genode::uint16_t _ibrd = 0; - Genode::uint16_t _fbrd = 0; - Genode::uint16_t _lcr_h = 0; - Genode::uint16_t _imsc = 0b1111; - Genode::uint16_t _ris = 0; - Genode::uint16_t _cr = 0x300; - - void _out_char(unsigned char c) { - _terminal.write(&c, 1); - } - - unsigned char _get_char() - { - if (_rx_buf.empty()) return 0; - return _rx_buf.get(); - } - - Genode::uint16_t _get(Genode::uint64_t off) - { - switch (off) { - case UARTDR: return _get_char(); - case UARTPERIPHID0: return 0x11; - case UARTPERIPHID1: return 0x10; - case UARTPERIPHID2: return 0x14; - case UARTPERIPHID3: return 0x0; - case UARTPCELLID0: return 0xd; - case UARTPCELLID1: return 0xf0; - case UARTPCELLID2: return 0x5; - case UARTPCELLID3: return 0xb1; - case UARTFR: return _rx_buf.empty() ? 16 : 64; - case UARTCR: return _cr; - case UARTIMSC: return _imsc; - case UARTMIS: return _ris & _imsc; - case UARTFBRD: return _fbrd; - case UARTIBRD: return _ibrd; - case UARTLCR_H: return _lcr_h; - default: - throw Wrong_offset(); - }; - } - - void _mask_irqs(Genode::uint32_t mask) - { - /* TX IRQ unmask */ - if (mask & (1 << 5) && !(_imsc & (1 << 5))) { - _gic.inject_irq(Board::PL011_0_IRQ); - _ris |= 1 << 5; - } - - /* RX IRQ unmask */ - if (mask & (1 << 4) && !(_imsc & (1 << 4)) && - !_rx_buf.empty()) { - _gic.inject_irq(Board::PL011_0_IRQ); - _ris |= 1 << 4; - } - - _imsc = mask; - } - - void _read() - { - if (!_terminal.avail()) return; - - while (_terminal.avail()) { - unsigned char c = 0; - _terminal.read(&c, 1); - _rx_buf.add(c); - } - - _gic.inject_irq(Board::PL011_0_IRQ); - _ris |= 1 << 4; - } - - using Error = Vm::Exception; - - public: - - Pl011(const char * const name, - const Genode::uint64_t addr, - const Genode::uint64_t size, - Vmm &vmm, - Genode::Env &env, - Gic &gic) - : Device(name, addr, size, vmm.vm()), - _terminal(env), - _handler(vmm, env.ep(), *this, &Pl011::_read), - _gic(gic) { - _terminal.read_avail_sigh(_handler); - _gic.register_irq(Board::PL011_0_IRQ, this, false); - } - - void read(Genode::uint16_t * reg, Genode::uint64_t off) - { - try { - *reg = _get(off); - } catch(Wrong_offset &e) { - throw Error("UART: halfword read of offset %llx", off); - } - } - - void read(Genode::uint32_t * reg, Genode::uint64_t off) { - read((Genode::uint16_t*) reg, off); } - - void write(Genode::uint8_t * reg, Genode::uint64_t off) - { - if (off != UARTDR) - throw Error("UART: byte write %x to offset %llx", - *reg, off); - _terminal.write(reg, 1); - } - - void write(Genode::uint16_t * reg, Genode::uint64_t off) - { - switch (off) { - case UARTDR: - _terminal.write(reg, 1); - return; - case UARTFBRD: - _fbrd = *reg; - return; - case UARTIMSC: - _mask_irqs(*reg); - return; - case UARTIBRD: - _ibrd = *reg; - return; - case UARTLCR_H: - _lcr_h = *reg; - return; - case UARTICR: - _ris = _ris & ~*reg; - return; - case UARTCR: - _cr = *reg; - return; - case UARTIFLS: - return; - default: - throw Error("UART: halfword write %x to offset %llx", - *reg, off); - }; - } - }; - - - Signal_handler _vm_handler; - Vm _vm; - Cp15 _cp15; - Genode::Avl_tree _device_tree; - Gic _gic; - Generic_timer _timer; - System_register _sys_regs; - Pl011 _uart; - - void _handle_hyper_call() { - throw Vm::Exception("Unknown hyper call!"); } - - void _handle_data_abort() - { - Genode::uint64_t ipa = (Genode::uint64_t)_vm.state().hpfar << 8; - Device * device = _device_tree.first() - ? _device_tree.first()->find_by_addr(ipa) : nullptr; - if (!device) - throw Vm::Exception("No device at IPA=%llx", ipa); - device->handle_memory_access(_vm.state()); - _vm.state().ip += sizeof(Genode::addr_t); - } - - void _handle_wfi() - { - if (_vm.state().hsr & 1) - throw Vm::Exception("WFE not implemented yet"); - - _vm.wait_for_interrupt(); - _timer.schedule_timeout(); - _vm.state().ip += sizeof(Genode::addr_t); - } - - void _handle_trap() - { - /* check device number*/ - switch (Hsr::Ec::get(_vm.state().hsr)) { - case Hsr::Ec::HVC: - _handle_hyper_call(); - break; - case Hsr::Ec::CP15: - _cp15.handle_trap(_vm.state()); - break; - case Hsr::Ec::DA: - _handle_data_abort(); - break; - case Hsr::Ec::WFI: - _handle_wfi(); - return; - default: - throw Vm::Exception("Unknown trap: %x", - Hsr::Ec::get(_vm.state().hsr)); - }; - } - - void _handle() {} /* dummy handler */ - - public: - - Vmm(Genode::Env & env) - : _vm_handler(*this, env.ep(), *this, &Vmm::_handle), - _vm("linux", "dtb", 1024 * 1024 * 128, _vm_handler, env), - _cp15(_vm.state()), - _gic ("Gic", 0x2c001000, 0x2000, _vm), - _timer ("Timer", 0x2a430000, 0x1000, *this, env, _gic), - _sys_regs ("System Register", 0x1c010000, 0x1000, _vm, env), - _uart ("Pl011", 0x1c090000, 0x1000, *this, env, _gic) - { - _device_tree.insert(&_gic); - _device_tree.insert(&_sys_regs); - _device_tree.insert(&_uart); - - Genode::log("Start virtual machine ..."); - - _vm.start(); - _vm.run(); - }; - - Vm & vm() { return _vm; } - - template - void handle_vm(FUNC handler) - { - if (_vm.active()) { - - _vm.pause(); - - enum { IRQ = 6, TRAP = 8 }; - - /* check exception reason */ - switch (_vm.state().cpu_exception) { - case IRQ: - _gic.irq_occured(); - break; - case TRAP: - _handle_trap(); - break; - default: - throw Vm::Exception("Curious exception occured"); - } - } - - handler(); - - if (_vm.active()) _vm.run(); - } -}; - - -void Component::construct(Genode::Env & env) { static Vmm vmm(env); } diff --git a/repos/os/src/server/vmm/spec/arm_v7/target.mk b/repos/os/src/server/vmm/spec/arm_v7/target.mk index 456fa601c..37e2434f0 100644 --- a/repos/os/src/server/vmm/spec/arm_v7/target.mk +++ b/repos/os/src/server/vmm/spec/arm_v7/target.mk @@ -1,7 +1,19 @@ TARGET = vmm REQUIRES = hw arm_v7 LIBS = base -SRC_CC = main.cc -INC_DIR += $(PRG_DIR) +SRC_CC += spec/arm_v7/generic_timer.cc +SRC_CC += address_space.cc +SRC_CC += cpu.cc +SRC_CC += cpu_base.cc +SRC_CC += generic_timer.cc +SRC_CC += gic.cc +SRC_CC += main.cc +SRC_CC += mmio.cc +SRC_CC += pl011.cc +SRC_CC += vm.cc +SRC_CC += virtio_device.cc +INC_DIR += $(PRG_DIR)/../.. $(PRG_DIR) + +vpath %.cc $(PRG_DIR)/../.. CC_CXX_WARN_STRICT := diff --git a/repos/os/src/server/vmm/spec/arm_v7/test/main.s b/repos/os/src/server/vmm/spec/arm_v7/test/main.s deleted file mode 100644 index 529c00e5b..000000000 --- a/repos/os/src/server/vmm/spec/arm_v7/test/main.s +++ /dev/null @@ -1,30 +0,0 @@ -.section ".text.crt0" - - .global _start - _start: - - /* idle a little initially because U-Boot likes it this way */ - mov r8, r8 - mov r8, r8 - mov r8, r8 - mov r8, r8 - mov r8, r8 - mov r8, r8 - mov r8, r8 - mov r8, r8 - - /* zero-fill BSS segment */ - ldr r0, =_bss_start - ldr r1, =_bss_end - mov r2, #0 - 1: - cmp r1, r0 - ble 2f - str r2, [r0] - add r0, r0, #4 - b 1b - 2: - - hvc #0 - - 1: b 1b diff --git a/repos/os/src/server/vmm/spec/arm_v7/test/target.mk b/repos/os/src/server/vmm/spec/arm_v7/test/target.mk deleted file mode 100644 index cb8af1bb7..000000000 --- a/repos/os/src/server/vmm/spec/arm_v7/test/target.mk +++ /dev/null @@ -1,4 +0,0 @@ -TARGET = vmm-test-kernel -REQUIRES = arm_v7 -SRC_S = main.s -CC_MARCH = -mcpu=cortex-a15 diff --git a/repos/os/src/server/vmm/spec/arm_v7/virt.dts b/repos/os/src/server/vmm/spec/arm_v7/virt.dts new file mode 100755 index 000000000..4701073e7 --- /dev/null +++ b/repos/os/src/server/vmm/spec/arm_v7/virt.dts @@ -0,0 +1,80 @@ +/dts-v1/; + +/ { + compatible = "linux,dummy-virt"; + #address-cells = <0x02>; + #size-cells = <0x02>; + interrupt-parent = <0x8001>; + + cpus { + #address-cells = <0x01>; + #size-cells = <0x00>; + + cpu@0 { + compatible = "arm,cortex-a15"; + reg = <0x00>; + device_type = "cpu"; + }; + }; + + timer { + interrupts = <0x01 0x0d 0x04 0x01 0x0e 0x04 0x01 0x0b 0x04 0x01 0x0a 0x04>; + compatible = "arm,armv7-timer"; + always-on; + }; + + apb-pclk { + compatible = "fixed-clock"; + phandle = <0x8000>; + clock-output-names = "clk24mhz"; + clock-frequency = <0x16e3600>; + #clock-cells = <0x00>; + }; + + pl011@9000000 { + interrupts = <0x00 0x01 0x04>; + compatible = "arm,pl011\0arm,primecell"; + clock-names = "uartclk\0apb_pclk"; + reg = <0x00 0x9000000 0x00 0x1000>; + clocks = <0x8000 0x8000>; + }; + + memory@40000000 { + reg = <0x00 0x40000000 0x00 0x8000000>; + device_type = "memory"; + }; + + chosen { + bootargs = "rdinit=/bin/sh ip=dhcp console=hvc0"; + linux,initrd-start = <0x46000000>; + linux,initrd-end = <0x460b04b6>; + stdout-path = "/pl011@9000000"; + }; + + intc@8000000 { + compatible = "arm,cortex-a15-gic"; + phandle = <0x8001>; + reg = <0x00 0x8000000 0x00 0x10000 0x00 0x8010000 0x00 0x10000>; + ranges; + #address-cells = <0x02>; + #redistributor-regions = <0x01>; + interrupt-controller; + #interrupt-cells = <0x03>; + #size-cells = <0x02>; + }; + + + virtio_mmio@a000000 { + interrupts = <0x00 0x10 0x01>; + compatible = "virtio,mmio"; + dma-coherent; + reg = <0x00 0xa000000 0x00 0x200>; + }; + + virtio_mmio@a000200 { + interrupts = <0x00 0x11 0x01>; + compatible = "virtio,mmio"; + dma-coherent; + reg = <0x00 0xa000200 0x00 0x200>; + }; +}; diff --git a/repos/os/src/server/vmm/spec/arm_v8/board.h b/repos/os/src/server/vmm/spec/arm_v8/board.h new file mode 100644 index 000000000..96be06a49 --- /dev/null +++ b/repos/os/src/server/vmm/spec/arm_v8/board.h @@ -0,0 +1,53 @@ +/* + * \brief VMM address space utility + * \author Stefan Kalkowski + * \date 2019-11-13 + */ + +/* + * 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 _SRC__SERVER__VMM__BOARD_H_ +#define _SRC__SERVER__VMM__BOARD_H_ + +namespace Vmm { + + enum { + SIZE_1_MB = 1024 * 1024, + KERNEL_OFFSET = 0x80000, + INITRD_OFFSET = 32 * SIZE_1_MB, + DTB_OFFSET = 64 * SIZE_1_MB, + + GIC_VERSION = 3, + GICD_MMIO_START = 0x8000000, + GICD_MMIO_SIZE = 0x10000, + GICC_MMIO_START = 0x8010000, + GICR_MMIO_START = 0x80a0000, + GICR_MMIO_SIZE = 0xf60000, + + PL011_MMIO_START = 0x9000000, + PL011_MMIO_SIZE = 0x1000, + PL011_IRQ = 33, + + VIRTIO_CONSOLE_MMIO_START = 0xa000000, + VIRTIO_CONSOLE_MMIO_SIZE = 0x200, + VIRTIO_CONSOLE_IRQ = 48, + + VIRTIO_NET_MMIO_START = 0xa000200, + VIRTIO_NET_MMIO_SIZE = 0x200, + VIRTIO_NET_IRQ = 49, + + RAM_START = 0x40000000, + RAM_SIZE = 128 * 1024 *1024, + + VTIMER_IRQ = 27, + + MAX_CPUS = 1, + }; +} + +#endif /* _SRC__SERVER__VMM__BOARD_H_ */ diff --git a/repos/os/src/server/vmm/spec/arm_v8/cpu.cc b/repos/os/src/server/vmm/spec/arm_v8/cpu.cc index c2ba88c33..8708b013e 100644 --- a/repos/os/src/server/vmm/spec/arm_v8/cpu.cc +++ b/repos/os/src/server/vmm/spec/arm_v8/cpu.cc @@ -14,15 +14,27 @@ #include #include +using Vmm::Cpu_base; using Vmm::Cpu; using Vmm::Gic; -Genode::Lock & Vmm::lock() { static Genode::Lock l {}; return l; } +Genode::uint64_t Cpu_base::State::reg(unsigned idx) const +{ + if (idx > 30) return 0; + return r[idx]; +} -Cpu::System_register::Iss::access_t -Cpu::System_register::Iss::value(unsigned op0, unsigned crn, unsigned op1, - unsigned crm, unsigned op2) +void Cpu_base::State::reg(unsigned idx, Genode::uint64_t v) +{ + if (idx > 30) return; + r[idx] = v; +} + + +Cpu_base::System_register::Iss::access_t +Cpu_base::System_register::Iss::value(unsigned op0, unsigned crn, unsigned op1, + unsigned crm, unsigned op2) { access_t v = 0; Crn::set(v, crn); @@ -34,8 +46,8 @@ Cpu::System_register::Iss::value(unsigned op0, unsigned crn, unsigned op1, }; -Cpu::System_register::Iss::access_t -Cpu::System_register::Iss::mask_encoding(access_t v) +Cpu_base::System_register::Iss::access_t +Cpu_base::System_register::Iss::mask_encoding(access_t v) { return Crm::masked(v) | Crn::masked(v) | @@ -45,21 +57,69 @@ Cpu::System_register::Iss::mask_encoding(access_t v) } -Cpu::System_register::System_register(unsigned op0, - unsigned crn, - unsigned op1, - unsigned crm, - unsigned op2, - const char * name, - bool writeable, - Genode::addr_t v, - Genode::Avl_tree & tree) -: _encoding(Iss::value(op0, crn, op1, crm, op2)), - _name(name), - _writeable(writeable), - _value(v) +void Cpu_base::_handle_brk() { - tree.insert(this); + Genode::uint64_t offset = 0x0; + if (!(_state.pstate & 0b100)) { + offset = 0x400; + } else if (_state.pstate & 0b1) { + offset = 0x200; + } + _state.esr_el1 = _state.esr_el2; + _state.spsr_el1 = _state.pstate; + _state.elr_el1 = _state.ip; + _state.ip = _state.vbar_el1 + offset; + _state.pstate = 0b1111000101; +} + + +void Cpu_base::handle_exception() +{ + /* check exception reason */ + switch (_state.exception_type) { + case Cpu::NO_EXCEPTION: break; + case Cpu::AARCH64_IRQ: _handle_irq(); break; + case Cpu::AARCH64_SYNC: _handle_sync(); break; + default: + throw Exception("Curious exception ", + _state.exception_type, " occured"); + } + _state.exception_type = Cpu::NO_EXCEPTION; +} + + +void Cpu_base::dump() +{ + using namespace Genode; + + auto lambda = [] (addr_t exc) { + switch (exc) { + case Cpu::AARCH64_SYNC: return "aarch64 sync"; + case Cpu::AARCH64_IRQ: return "aarch64 irq"; + case Cpu::AARCH64_FIQ: return "aarch64 fiq"; + case Cpu::AARCH64_SERROR: return "aarch64 serr"; + case Cpu::AARCH32_SYNC: return "aarch32 sync"; + case Cpu::AARCH32_IRQ: return "aarch32 irq"; + case Cpu::AARCH32_FIQ: return "aarch32 fiq"; + case Cpu::AARCH32_SERROR: return "aarch32 serr"; + default: return "unknown"; + }; + }; + + log("VM state (", _active ? "active" : "inactive", ") :"); + for (unsigned i = 0; i < 31; i++) { + log(" r", i, " = ", + Hex(_state.r[i], Hex::PREFIX, Hex::PAD)); + } + log(" sp = ", Hex(_state.sp, Hex::PREFIX, Hex::PAD)); + log(" ip = ", Hex(_state.ip, Hex::PREFIX, Hex::PAD)); + log(" sp_el1 = ", Hex(_state.sp_el1, Hex::PREFIX, Hex::PAD)); + log(" elr_el1 = ", Hex(_state.elr_el1, Hex::PREFIX, Hex::PAD)); + log(" pstate = ", Hex(_state.pstate, Hex::PREFIX, Hex::PAD)); + log(" exception = ", _state.exception_type, " (", + lambda(_state.exception_type), ")"); + log(" esr_el2 = ", Hex(_state.esr_el2, Hex::PREFIX, Hex::PAD)); + _timer.dump(); } @@ -139,216 +199,13 @@ void Cpu::Icc_sgi1r_el1::write(Genode::addr_t v) }; -bool Cpu::_handle_sys_reg() +void Cpu_base::initialize_boot(Genode::addr_t ip, Genode::addr_t dtb) { - using Iss = System_register::Iss; - - Iss::access_t v = _state.esr_el2; - System_register * reg = _reg_tree.first(); - if (reg) reg = reg->find_by_encoding(Iss::mask_encoding(v)); - - if (!reg) { - Genode::error("ignore unknown system register access @ ip=", (void*)_state.ip, ":"); - Genode::error(Iss::Direction::get(v) ? "read" : "write", - ": " - "op0=", Iss::Opcode0::get(v), " " - "op1=", Iss::Opcode1::get(v), " " - "r", Iss::Register::get(v), " " - "crn=", Iss::Crn::get(v), " " - "crm=", Iss::Crm::get(v), " ", - "op2=", Iss::Opcode2::get(v)); - if (Iss::Direction::get(v)) _state.r[Iss::Register::get(v)] = 0; - _state.ip += sizeof(Genode::uint32_t); - return false; - } - - if (Iss::Direction::get(v)) { /* read access */ - _state.r[Iss::Register::get(v)] = reg->read(); - } else { /* write access */ - if (!reg->writeable()) { - Genode::error("writing to system register ", - reg->name(), " not allowed!"); - return false; - } - reg->write(_state.r[Iss::Register::get(v)]); - } - _state.ip += sizeof(Genode::uint32_t); - return true; + state().reg(0, dtb); + state().ip = ip; } -void Cpu::_handle_wfi() -{ - _state.ip += sizeof(Genode::uint32_t); - - if (_state.esr_el2 & 1) return; /* WFE */ - - _active = false; - _timer.schedule_timeout(); -} - - -void Cpu::_handle_brk() -{ - Genode::uint64_t offset = 0x0; - if (!(_state.pstate & 0b100)) { - offset = 0x400; - } else if (_state.pstate & 0b1) { - offset = 0x200; - } - _state.esr_el1 = _state.esr_el2; - _state.spsr_el1 = _state.pstate; - _state.elr_el1 = _state.ip; - _state.ip = _state.vbar_el1 + offset; - _state.pstate = 0b1111000101; -} - - -void Cpu::_handle_sync() -{ - /* check device number*/ - switch (Esr::Ec::get(_state.esr_el2)) { - case Esr::Ec::HVC: - _handle_hyper_call(); - break; - case Esr::Ec::MRS_MSR: - _handle_sys_reg(); - break; - case Esr::Ec::DA: - _handle_data_abort(); - break; - case Esr::Ec::WFI: - _handle_wfi(); - return; - case Esr::Ec::BRK: - _handle_brk(); - return; - default: - throw Exception("Unknown trap: %x", - Esr::Ec::get(_state.esr_el2)); - }; -} - - -void Cpu::_handle_irq() -{ - enum { /* FIXME */ VT_TIMER_IRQ = 27 }; - switch (_state.irqs.last_irq) { - case VT_TIMER_IRQ: - _timer.handle_irq(); - break; - default: - _gic.handle_irq(); - }; -} - - -void Cpu::_handle_hyper_call() -{ - switch(_state.r[0]) { - case Psci::PSCI_VERSION: - _state.r[0] = Psci::VERSION; - return; - case Psci::MIGRATE_INFO_TYPE: - _state.r[0] = Psci::NOT_SUPPORTED; - return; - case Psci::PSCI_FEATURES: - _state.r[0] = Psci::NOT_SUPPORTED; - return; - case Psci::CPU_ON: - _vm.cpu((unsigned)_state.r[1], [&] (Cpu & cpu) { - cpu.state().ip = _state.r[2]; - cpu.state().r[0] = _state.r[3]; - cpu.run(); - }); - _state.r[0] = Psci::SUCCESS; - return; - default: - Genode::warning("unknown hypercall! ", cpu_id()); - dump(); - }; -} - - -void Cpu::_handle_data_abort() -{ - _vm.bus().handle_memory_access(*this); - _state.ip += sizeof(Genode::uint32_t); -} - - -void Cpu::_update_state() -{ - if (!_gic.pending_irq()) return; - - _active = true; - _timer.cancel_timeout(); -} - -unsigned Cpu::cpu_id() const { return _vcpu_id.id; } -void Cpu::run() { _vm_session.run(_vcpu_id); } -void Cpu::pause() { _vm_session.pause(_vcpu_id); } -bool Cpu::active() const { return _active; } -Cpu::State & Cpu::state() const { return _state; } -Gic::Gicd_banked & Cpu::gic() { return _gic; } - - -void Cpu::handle_exception() -{ - /* check exception reason */ - switch (_state.exception_type) { - case NO_EXCEPTION: break; - case AARCH64_IRQ: _handle_irq(); break; - case AARCH64_SYNC: _handle_sync(); break; - default: - throw Exception("Curious exception ", - _state.exception_type, " occured"); - } - _state.exception_type = NO_EXCEPTION; -} - - -void Cpu::dump() -{ - using namespace Genode; - - auto lambda = [] (addr_t exc) { - switch (exc) { - case AARCH64_SYNC: return "aarch64 sync"; - case AARCH64_IRQ: return "aarch64 irq"; - case AARCH64_FIQ: return "aarch64 fiq"; - case AARCH64_SERROR: return "aarch64 serr"; - case AARCH32_SYNC: return "aarch32 sync"; - case AARCH32_IRQ: return "aarch32 irq"; - case AARCH32_FIQ: return "aarch32 fiq"; - case AARCH32_SERROR: return "aarch32 serr"; - default: return "unknown"; - }; - }; - - log("VM state (", _active ? "active" : "inactive", ") :"); - for (unsigned i = 0; i < 31; i++) { - log(" r", i, " = ", - Hex(_state.r[i], Hex::PREFIX, Hex::PAD)); - } - log(" sp = ", Hex(_state.sp, Hex::PREFIX, Hex::PAD)); - log(" ip = ", Hex(_state.ip, Hex::PREFIX, Hex::PAD)); - log(" sp_el1 = ", Hex(_state.sp_el1, Hex::PREFIX, Hex::PAD)); - log(" elr_el1 = ", Hex(_state.elr_el1, Hex::PREFIX, Hex::PAD)); - log(" pstate = ", Hex(_state.pstate, Hex::PREFIX, Hex::PAD)); - log(" exception = ", _state.exception_type, " (", - lambda(_state.exception_type), ")"); - log(" esr_el2 = ", Hex(_state.esr_el2, Hex::PREFIX, Hex::PAD)); - _timer.dump(); -} - - -void Cpu::recall() -{ - Genode::Signal_transmitter(_vm_handler).submit(); -}; - - Cpu::Cpu(Vm & vm, Genode::Vm_connection & vm_session, Mmio_bus & bus, @@ -356,15 +213,7 @@ Cpu::Cpu(Vm & vm, Genode::Env & env, Genode::Heap & heap, Genode::Entrypoint & ep) -: _vm(vm), - _vm_session(vm_session), - _heap(heap), - _vm_handler(*this, ep, *this, &Cpu::_handle_nothing), - _vcpu_id(_vm_session.with_upgrade([&]() { - return _vm_session.create_vcpu(heap, env, _vm_handler); - })), - _state(*((State*)env.rm().attach(_vm_session.cpu_state(_vcpu_id)))), - // op0, crn, op1, crm, op2, writeable, reset value +: Cpu_base(vm, vm_session, bus, gic, env, heap, ep), _sr_id_aa64afr0_el1 (3, 0, 0, 5, 4, "ID_AA64AFR0_EL1", false, 0x0, _reg_tree), _sr_id_aa64afr1_el1 (3, 0, 0, 5, 5, "ID_AA64AFR1_EL1", false, 0x0, _reg_tree), _sr_id_aa64dfr0_el1 (3, 0, 0, 5, 0, "ID_AA64DFR0_EL1", false, 0x6, _reg_tree), @@ -379,13 +228,10 @@ Cpu::Cpu(Vm & vm, _sr_id_aa64zfr0_el1 (3, 0, 0, 4, 4, "ID_AA64ZFR0_EL1", false, 0x0, _reg_tree), _sr_aidr_el1 (3, 0, 1, 0, 7, "AIDR_EL1", false, 0x0, _reg_tree), _sr_revidr_el1 (3, 0, 0, 0, 6, "REVIDR_EL1", false, 0x0, _reg_tree), - _sr_clidr_el1 (3, 0, 1, 0, 1, "CLIDR_EL1", false, _state.clidr_el1, _reg_tree), _sr_csselr_el1 (3, 0, 2, 0, 0, "CSSELR_EL1", true, 0x0, _reg_tree), _sr_ctr_el0 (_reg_tree), _sr_ccsidr_el1 (_sr_csselr_el1, _state, _reg_tree), - -//_sr_pmccfiltr_el0 (3, 14, 3, 15, 7, "PMCCFILTR_EL0", true, 0x0, _reg_tree), _sr_pmuserenr_el0 (3, 9, 3, 14, 0, "PMUSEREN_EL0", true, 0x0, _reg_tree), _sr_dbgbcr0 (2, 0, 0, 0, 5, "DBGBCR_EL1", true, 0x0, _reg_tree), _sr_dbgbvr0 (2, 0, 0, 0, 4, "DBGBVR_EL1", true, 0x0, _reg_tree), @@ -394,9 +240,7 @@ Cpu::Cpu(Vm & vm, _sr_mdscr (2, 0, 0, 2, 2, "MDSCR_EL1", true, 0x0, _reg_tree), _sr_osdlr (2, 1, 0, 3, 4, "OSDLR_EL1", true, 0x0, _reg_tree), _sr_oslar (2, 1, 0, 0, 4, "OSLAR_EL1", true, 0x0, _reg_tree), - _sr_sgi1r_el1 (_reg_tree, vm), - _gic(*this, gic, bus), - _timer(env, ep, _gic.irq(27), *this) + _sr_sgi1r_el1 (_reg_tree, vm) { _state.pstate = 0b1111000101; /* el1 mode and IRQs disabled */ _state.vmpidr_el2 = cpu_id(); diff --git a/repos/os/src/server/vmm/spec/arm_v8/cpu.h b/repos/os/src/server/vmm/spec/arm_v8/cpu.h index f0804beb7..1c6f65d7d 100644 --- a/repos/os/src/server/vmm/spec/arm_v8/cpu.h +++ b/repos/os/src/server/vmm/spec/arm_v8/cpu.h @@ -14,41 +14,14 @@ #ifndef _SRC__SERVER__VMM__CPU_H_ #define _SRC__SERVER__VMM__CPU_H_ -#include -#include +#include -#include -#include -#include -#include -#include +namespace Vmm { class Cpu; } -namespace Vmm { - class Vm; - class Cpu; - Genode::Lock & lock(); -} - -class Vmm::Cpu +class Vmm::Cpu : public Vmm::Cpu_base { public: - using State = Genode::Vm_state; - - struct Esr : Genode::Register<32> - { - struct Ec : Bitfield<26, 6> - { - enum { - WFI = 0x1, - HVC = 0x16, - MRS_MSR = 0x18, - DA = 0x24, - BRK = 0x3c - }; - }; - }; - Cpu(Vm & vm, Genode::Vm_connection & vm_session, Mmio_bus & bus, @@ -57,58 +30,6 @@ class Vmm::Cpu Genode::Heap & heap, Genode::Entrypoint & ep); - unsigned cpu_id() const; - void run(); - void pause(); - bool active() const; - State & state() const; - Gic::Gicd_banked & gic(); - void dump(); - void handle_exception(); - void recall(); - - template - void handle_signal(FUNC handler) - { - if (active()) { - pause(); - handle_exception(); - } - - handler(); - _update_state(); - if (active()) run(); - } - - template - struct Signal_handler : Genode::Vm_handler> - { - using Base = Genode::Vm_handler>; - - Cpu & cpu; - T & obj; - void (T::*member)(); - - void handle() - { - try { - cpu.handle_signal([this] () { (obj.*member)(); }); - } catch(Exception &e) { - Genode::error(e); - cpu.dump(); - } - } - - Signal_handler(Cpu & cpu, - Genode::Entrypoint & ep, - T & o, - void (T::*f)()) - : Base(ep, *this, &Signal_handler::handle), - cpu(cpu), obj(o), member(f) {} - }; - - private: - enum Exception_type { AARCH64_SYNC = 0x400, AARCH64_IRQ = 0x480, @@ -121,72 +42,7 @@ class Vmm::Cpu NO_EXCEPTION = 0xffff }; - class System_register : public Genode::Avl_node - { - private: - - const Esr::access_t _encoding; - const char *_name; - const bool _writeable; - Genode::uint64_t _value; - - public: - - struct Iss : Esr - { - struct Direction : Bitfield<0, 1> {}; - struct Crm : Bitfield<1, 4> {}; - struct Register : Bitfield<5, 5> {}; - struct Crn : Bitfield<10, 4> {}; - struct Opcode1 : Bitfield<14, 3> {}; - struct Opcode2 : Bitfield<17, 3> {}; - struct Opcode0 : Bitfield<20, 2> {}; - - static access_t value(unsigned op0, - unsigned crn, - unsigned op1, - unsigned crm, - unsigned op2); - - static access_t mask_encoding(access_t v); - }; - - System_register(unsigned op0, - unsigned crn, - unsigned op1, - unsigned crm, - unsigned op2, - const char * name, - bool writeable, - Genode::addr_t v, - Genode::Avl_tree & tree); - - const char * name() const { return _name; } - const bool writeable() const { return _writeable; } - - System_register * find_by_encoding(Iss::access_t e) - { - if (e == _encoding) return this; - - System_register * r = - Avl_node::child(e > _encoding); - return r ? r->find_by_encoding(e) : nullptr; - } - - virtual void write(Genode::addr_t v) { - _value = (Genode::addr_t)v; } - - virtual Genode::addr_t read() const { - return (Genode::addr_t)(_value); } - - - /************************ - ** Avl node interface ** - ************************/ - - bool higher(System_register *r) { - return (r->_encoding > _encoding); } - }; + private: class Id_aa64pfr0 : public System_register, public Genode::Register<64> @@ -252,15 +108,6 @@ class Vmm::Cpu virtual void write(Genode::addr_t v) override; }; - bool _active { true }; - Vm & _vm; - Genode::Vm_connection & _vm_session; - Genode::Heap & _heap; - Signal_handler _vm_handler; - Genode::Vm_session::Vcpu_id _vcpu_id; - State & _state; - Genode::Avl_tree _reg_tree; - /****************************** ** Identification registers ** ******************************/ @@ -308,22 +155,10 @@ class Vmm::Cpu System_register _sr_oslar; /*********************** - ** Local peripherals ** + ** GIC cpu interface ** ***********************/ Icc_sgi1r_el1 _sr_sgi1r_el1; - Gic::Gicd_banked _gic; - Generic_timer _timer; - - void _handle_nothing() {} - bool _handle_sys_reg(); - void _handle_brk(); - void _handle_wfi(); - void _handle_sync(); - void _handle_irq(); - void _handle_data_abort(); - void _handle_hyper_call(); - void _update_state(); }; #endif /* _SRC__SERVER__VMM__CPU_H_ */ diff --git a/repos/os/src/server/vmm/spec/arm_v8/generic_timer.cc b/repos/os/src/server/vmm/spec/arm_v8/generic_timer.cc index 003434053..16e82651e 100644 --- a/repos/os/src/server/vmm/spec/arm_v8/generic_timer.cc +++ b/repos/os/src/server/vmm/spec/arm_v8/generic_timer.cc @@ -28,26 +28,6 @@ Genode::uint64_t Generic_timer::_ticks_per_ms() } -bool Generic_timer::_enabled() { - return Ctrl::Enabled::get(_cpu.state().timer.control); } - - -bool Generic_timer::_masked() { - return Ctrl::Imask::get(_cpu.state().timer.control); } - - -bool Generic_timer::_pending() { - return Ctrl::Istatus::get(_cpu.state().timer.control); } - - -void Generic_timer::_handle_timeout(Genode::Duration) -{ - _cpu.handle_signal([this] (void) { - if (_enabled() && !_masked()) handle_irq(); - }); -} - - Genode::uint64_t Generic_timer::_usecs_left() { Genode::uint64_t count; @@ -57,60 +37,3 @@ Genode::uint64_t Generic_timer::_usecs_left() return Genode::timer_ticks_to_us(_cpu.state().timer.compare - count, _ticks_per_ms()); } - - -Generic_timer::Generic_timer(Genode::Env & env, - Genode::Entrypoint & ep, - Gic::Irq & irq, - Cpu & cpu) -: _timer(env, ep), - _timeout(_timer, *this, &Generic_timer::_handle_timeout), - _irq(irq), - _cpu(cpu) -{ - _cpu.state().timer.irq = true; - _irq.handler(*this); -} - - -void Generic_timer::schedule_timeout() -{ - if (_pending()) { - handle_irq(); - return; - } - - if (_enabled()) { - if (_usecs_left()) { - _timeout.schedule(Genode::Microseconds(_usecs_left())); - } else _handle_timeout(Genode::Duration(Genode::Microseconds(0))); - } -} - - -void Generic_timer::cancel_timeout() -{ - if (_timeout.scheduled()) _timeout.discard(); -} - - -void Generic_timer::handle_irq() -{ - _irq.assert(); - _cpu.state().timer.irq = false; -} - - -void Generic_timer::eoi() -{ - _cpu.state().timer.irq = true; -}; - - -void Generic_timer::dump() -{ - using namespace Genode; - - log(" timer.ctl = ", Hex(_cpu.state().timer.control, Hex::PREFIX, Hex::PAD)); - log(" timer.cmp = ", Hex(_cpu.state().timer.compare, Hex::PREFIX, Hex::PAD)); -} diff --git a/repos/os/src/server/vmm/spec/arm_v8/target.mk b/repos/os/src/server/vmm/spec/arm_v8/target.mk index 9af3f0a6e..f57618be1 100644 --- a/repos/os/src/server/vmm/spec/arm_v8/target.mk +++ b/repos/os/src/server/vmm/spec/arm_v8/target.mk @@ -1,15 +1,19 @@ TARGET = vmm REQUIRES = hw arm_v8 LIBS = base +SRC_CC += spec/arm_v8/generic_timer.cc SRC_CC += address_space.cc SRC_CC += cpu.cc +SRC_CC += cpu_base.cc SRC_CC += generic_timer.cc -SRC_CC += gicv2.cc +SRC_CC += gic.cc SRC_CC += main.cc SRC_CC += mmio.cc SRC_CC += pl011.cc SRC_CC += virtio_device.cc SRC_CC += vm.cc -INC_DIR += $(PRG_DIR) +INC_DIR += $(PRG_DIR)/../.. $(PRG_DIR) + +vpath %.cc $(PRG_DIR)/../.. CC_CXX_WARN_STRICT := diff --git a/repos/os/src/server/vmm/spec/arm_v8/virtio_console.h b/repos/os/src/server/vmm/virtio_console.h similarity index 100% rename from repos/os/src/server/vmm/spec/arm_v8/virtio_console.h rename to repos/os/src/server/vmm/virtio_console.h diff --git a/repos/os/src/server/vmm/spec/arm_v8/virtio_device.cc b/repos/os/src/server/vmm/virtio_device.cc similarity index 100% rename from repos/os/src/server/vmm/spec/arm_v8/virtio_device.cc rename to repos/os/src/server/vmm/virtio_device.cc diff --git a/repos/os/src/server/vmm/spec/arm_v8/virtio_device.h b/repos/os/src/server/vmm/virtio_device.h similarity index 96% rename from repos/os/src/server/vmm/spec/arm_v8/virtio_device.h rename to repos/os/src/server/vmm/virtio_device.h index c83c5bc02..5ec1327db 100644 --- a/repos/os/src/server/vmm/spec/arm_v8/virtio_device.h +++ b/repos/os/src/server/vmm/virtio_device.h @@ -48,9 +48,12 @@ struct Vmm::Virtio_queue_data uint32_t ready { 0 }; bool tx { false }; - addr_t descr() const { return ((addr_t)descr_high << 32) | descr_low; } - addr_t driver() const { return ((addr_t)driver_high << 32) | driver_low; } - addr_t device() const { return ((addr_t)device_high << 32) | device_low; } + uint64_t descr() const { + return ((uint64_t)descr_high << 32) | descr_low; } + uint64_t driver() const { + return ((uint64_t)driver_high << 32) | driver_low; } + uint64_t device() const { + return ((uint64_t)device_high << 32) | device_low; } enum { MAX_QUEUE_SIZE = 1 << 15 }; }; @@ -83,10 +86,10 @@ class Vmm::Virtio_descriptor : Genode::Mmio return Virtio_descriptor(base() + (size() * idx)); } - addr_t address() const { return read
(); } - size_t length () const { return read(); } - uint16_t flags() const { return read(); } - uint16_t next() const { return read(); } + uint64_t address() const { return read
(); } + size_t length () const { return read(); } + uint16_t flags() const { return read(); } + uint16_t next() const { return read(); } }; @@ -173,7 +176,7 @@ class Vmm::Virtio_queue id %= _length; Virtio_descriptor descr = _descr.index(id); - addr_t address = descr.address(); + uint64_t address = descr.address(); size_t length = descr.length(); if (!address || !length) break; diff --git a/repos/os/src/server/vmm/spec/arm_v8/virtio_net.h b/repos/os/src/server/vmm/virtio_net.h similarity index 100% rename from repos/os/src/server/vmm/spec/arm_v8/virtio_net.h rename to repos/os/src/server/vmm/virtio_net.h diff --git a/repos/os/src/server/vmm/spec/arm_v8/vm.cc b/repos/os/src/server/vmm/vm.cc similarity index 70% rename from repos/os/src/server/vmm/spec/arm_v8/vm.cc rename to repos/os/src/server/vmm/vm.cc index 26093ddfc..bfd9b31d1 100644 --- a/repos/os/src/server/vmm/spec/arm_v8/vm.cc +++ b/repos/os/src/server/vmm/vm.cc @@ -48,14 +48,16 @@ Vmm::Cpu & Vm::boot_cpu() Vm::Vm(Genode::Env & env) : _env(env), - _gic("Gicv3", 0x8000000, 0x10000, _bus, env), - _uart("Pl011", 0x9000000, 0x1000, 33, boot_cpu(), _bus, env), - _virtio_console("HVC", 0xa000000, 0x200, 48, boot_cpu(), _bus, _ram, env), - _virtio_net("Net", 0xa000200, 0x200, 49, boot_cpu(), _bus, _ram, env) + _gic("Gicv3", GICD_MMIO_START, GICD_MMIO_SIZE, + MAX_CPUS, GIC_VERSION, _vm, _bus, env), + _uart("Pl011", PL011_MMIO_START, PL011_MMIO_SIZE, + PL011_IRQ, boot_cpu(), _bus, env), + _virtio_console("HVC", VIRTIO_CONSOLE_MMIO_START, VIRTIO_CONSOLE_MMIO_SIZE, + VIRTIO_CONSOLE_IRQ, boot_cpu(), _bus, _ram, env), + _virtio_net("Net", VIRTIO_NET_MMIO_START, VIRTIO_NET_MMIO_SIZE, + VIRTIO_NET_IRQ, boot_cpu(), _bus, _ram, env) { - _vm.attach(_vm_ram.cap(), RAM_ADDRESS); - - /* FIXME extend for gicv2 by: _vm.attach_pic(0x8010000); */ + _vm.attach(_vm_ram.cap(), RAM_START); _load_kernel(); _load_dtb(); @@ -71,7 +73,7 @@ Vm::Vm(Genode::Env & env) Genode::log("Start virtual machine ..."); Cpu & cpu = boot_cpu(); - cpu.state().ip = _ram.base() + KERNEL_OFFSET; - cpu.state().r[0] = _ram.base() + DTB_OFFSET; + cpu.initialize_boot(_ram.base() + KERNEL_OFFSET, + _ram.base() + DTB_OFFSET); cpu.run(); }; diff --git a/repos/os/src/server/vmm/spec/arm_v8/vm.h b/repos/os/src/server/vmm/vm.h similarity index 86% rename from repos/os/src/server/vmm/spec/arm_v8/vm.h rename to repos/os/src/server/vmm/vm.h index 29c76523c..8b2819d81 100644 --- a/repos/os/src/server/vmm/spec/arm_v8/vm.h +++ b/repos/os/src/server/vmm/vm.h @@ -14,6 +14,7 @@ #ifndef _SRC__SERVER__VMM__VM_H_ #define _SRC__SERVER__VMM__VM_H_ +#include #include #include #include @@ -34,15 +35,7 @@ class Vmm::Vm using Ep = Genode::Entrypoint; - enum { - RAM_ADDRESS = 0x40000000, - RAM_SIZE = 128 * 1024 *1024, - KERNEL_OFFSET = 0x80000, - INITRD_OFFSET = 32 * 1024 * 1024, - DTB_OFFSET = 64 * 1024 * 1024, - MAX_CPUS = 1, - STACK_SIZE = sizeof(unsigned long) * 2048, - }; + enum { STACK_SIZE = sizeof(unsigned long) * 2048, }; Genode::Env & _env; Genode::Vm_connection _vm { _env }; @@ -51,7 +44,7 @@ class Vmm::Vm Genode::Attached_rom_dataspace _initrd_rom { _env, "initrd" }; Genode::Attached_ram_dataspace _vm_ram { _env.ram(), _env.rm(), RAM_SIZE, Genode::CACHED }; - Ram _ram { RAM_ADDRESS, RAM_SIZE, + Ram _ram { RAM_START, RAM_SIZE, (Genode::addr_t)_vm_ram.local_addr()}; Genode::Heap _heap { _env.ram(), _env.rm() }; Mmio_bus _bus;