vmm: unify armv7/v8 virtualization

Fix #3638
This commit is contained in:
Stefan Kalkowski
2019-11-14 10:52:20 +01:00
committed by Christian Helmuth
parent 74e75d7fbc
commit 941e918b46
53 changed files with 1555 additions and 2648 deletions

View File

@ -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 <platform.h>
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);
}

View File

@ -11,6 +11,7 @@
* under the terms of the GNU Affero General Public License version 3.
*/
#include <spec/arm/cortex_a7_a15_virtualization.h>
#include <platform.h>
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);
}

View File

@ -13,6 +13,7 @@
#include <platform.h>
#include <spec/arm/imx_aipstz.h>
#include <spec/arm/cortex_a7_a15_virtualization.h>
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;

View File

@ -12,6 +12,7 @@
*/
#include <platform.h>
#include <spec/arm/cortex_a7_a15_virtualization.h>
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();

View File

@ -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 <translation_table.h>
#include <kernel/configuration.h>
#include <kernel/irq.h>
namespace Board {
using Vm_page_table = Hw::Level_1_stage_2_translation_table;
using Vm_page_table_array =
Vm_page_table::Allocator::Array<Kernel::DEFAULT_TRANSLATION_TABLE_MAX>;
struct Vcpu_context;
using Vm_state = Genode::Vm_state;
};
namespace Kernel {
class Cpu;
class Vm;
};
struct Board::Vcpu_context
{
struct Vm_irq : Kernel::Irq
{
Vm_irq(unsigned const irq, Kernel::Cpu &);
virtual ~Vm_irq() {};
virtual void handle(Kernel::Cpu &, Kernel::Vm & vm, unsigned irq);
void occurred() override;
};
struct Pic_maintainance_irq : Vm_irq
{
Pic_maintainance_irq(Kernel::Cpu &);
void handle(Kernel::Cpu &, Kernel::Vm &, unsigned) override { }
};
struct Virtual_timer_irq
{
Vm_irq irq;
Virtual_timer_irq(Kernel::Cpu &);
void enable();
void disable();
};
Vcpu_context(Kernel::Cpu & cpu)
: pic_irq(cpu), vtimer_irq(cpu) {}
Pic::Virtual_context pic {};
Pic_maintainance_irq pic_irq;
Virtual_timer_irq vtimer_irq;
};
#endif /* _CORE__SPEC__ARM__VIRTUALIZATION__BOARD_H_ */

View File

@ -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]

View File

@ -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<Vm*>(&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<Vm*>(&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 <unsigned SLOT>
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<Gich_hcr >();
s.gic_misr = pic().read<Gich_misr >();
s.gic_vmcr = pic().read<Gich_vmcr >();
s.gic_apr = pic().read<Gich_apr >();
s.gic_eisr = pic().read<Gich_eisr0 >();
s.gic_elrsr0 = pic().read<Gich_elrsr0>();
s.gic_lr[0] = pic().read<Gich_lr<0> >();
s.gic_lr[1] = pic().read<Gich_lr<1> >();
s.gic_lr[2] = pic().read<Gich_lr<2> >();
s.gic_lr[3] = pic().read<Gich_lr<3> >();
/* disable virtual PIC CPU interface */
pic().write<Gich_hcr>(0);
}
/**
* Load the virtual interrupt controller state from VM state
*/
static void load (Genode::Vm_state &s)
{
pic().write<Gich_hcr >(s.gic_hcr );
pic().write<Gich_misr >(s.gic_misr);
pic().write<Gich_vmcr >(s.gic_vmcr);
pic().write<Gich_apr >(s.gic_apr );
pic().write<Gich_elrsr0>(s.gic_elrsr0);
pic().write<Gich_lr<0> >(s.gic_lr[0]);
pic().write<Gich_lr<1> >(s.gic_lr[1]);
pic().write<Gich_lr<2> >(s.gic_lr[2]);
pic().write<Gich_lr<3> >(s.gic_lr[3]);
}
};
struct Kernel::Virtual_timer
{
Vm_irq irq { 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);
}

View File

@ -14,28 +14,20 @@
#ifndef _CORE__SPEC__ARNDALE__BOARD_H_
#define _CORE__SPEC__ARNDALE__BOARD_H_
#include <hw/spec/arm/gicv2.h>
#include <spec/arm/virtualization/gicv2.h>
#include <hw/spec/arm/arndale_board.h>
#include <spec/arm/exynos_mct.h>
#include <spec/arm/cpu/vm_state_virtualization.h>
#include <translation_table.h>
#include <kernel/configuration.h>
#include <spec/arm/virtualization/board.h>
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<Kernel::DEFAULT_TRANSLATION_TABLE_MAX>;
struct Vcpu_context { Vcpu_context(Kernel::Cpu &) {} };
}
#endif /* _CORE__SPEC__ARNDALE__BOARD_H_ */

View File

@ -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;
};
};

View File

@ -18,10 +18,7 @@
#include <spec/arm/virtualization/gicv2.h>
#include <spec/arm/generic_timer.h>
#include <spec/arm/cpu/vm_state_virtualization.h>
#include <translation_table.h>
#include <kernel/configuration.h>
namespace Kernel { class Cpu; }
#include <spec/arm/virtualization/board.h>
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<Kernel::DEFAULT_TRANSLATION_TABLE_MAX>;
struct Vcpu_context { Vcpu_context(Kernel::Cpu &) {} };
}
#endif /* _CORE__SPEC__IMX7_SABRELITE__BOARD_H_ */

View File

@ -18,9 +18,7 @@
#include <spec/arm/generic_timer.h>
#include <spec/arm/virtualization/gicv3.h>
#include <spec/arm_64/cpu/vm_state_virtualization.h>
#include <translation_table.h>
#include <kernel/configuration.h>
#include <kernel/irq.h>
#include <spec/arm/virtualization/board.h>
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<Kernel::DEFAULT_TRANSLATION_TABLE_MAX>;
struct Vcpu_context;
using Vm_state = Genode::Vm_state;
};
namespace Kernel {
class Cpu;
class Vm;
};
struct Board::Vcpu_context
{
struct Vm_irq : Kernel::Irq
{
Vm_irq(unsigned const irq, Kernel::Cpu &);
virtual ~Vm_irq() {};
virtual void handle(Kernel::Cpu &, Kernel::Vm & vm, unsigned irq);
void occurred() override;
};
struct Pic_maintainance_irq : Vm_irq
{
Pic_maintainance_irq(Kernel::Cpu &);
void handle(Kernel::Cpu &, Kernel::Vm &, unsigned) override { }
};
struct Virtual_timer_irq
{
Vm_irq irq;
Virtual_timer_irq(Kernel::Cpu &);
void enable();
void disable();
};
Vcpu_context(Kernel::Cpu & cpu)
: pic_irq(cpu), vtimer_irq(cpu) {}
Pic::Virtual_context pic {};
Pic_maintainance_irq pic_irq;
Virtual_timer_irq vtimer_irq;
};
#endif /* _CORE__SPEC__IMX8Q_EVK__BOARD_H_ */

View File

@ -18,8 +18,7 @@
#include <spec/arm/virtualization/gicv2.h>
#include <spec/arm/generic_timer.h>
#include <spec/arm/cpu/vm_state_virtualization.h>
#include <translation_table.h>
#include <kernel/configuration.h>
#include <spec/arm/virtualization/board.h>
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<Kernel::DEFAULT_TRANSLATION_TABLE_MAX>;
struct Vcpu_context { Vcpu_context(Kernel::Cpu &) {} };
};
#endif /* _SRC__CORE__SPEC__VIRT__QEMU_H_ */

View File

@ -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)