mirror of
https://github.com/genodelabs/genode.git
synced 2025-01-18 10:46:25 +00:00
base-hw: make ARMv7/v8 hypervisor smp ready
* Introduce hypervisor-stack per CPU * Introduce host world context per CPU * Mark EL2 translation table memory as inner shareable * The VMID is not bound to a single VCPU, but to the Vm_session as a whole * Set affinity of the VCPU accordingly * Add VMPIDR to VM state Ref #3926
This commit is contained in:
parent
1d826a2c48
commit
7298b00013
@ -50,6 +50,7 @@ struct Genode::Vm_state : Genode::Cpu_state_modes
|
||||
Genode::uint32_t tls2 { 0 };
|
||||
Genode::uint32_t tls3 { 0 };
|
||||
Genode::uint32_t cpacr { 0 };
|
||||
Genode::uint32_t vmpidr { 0 };
|
||||
|
||||
/**
|
||||
* Fpu registers
|
||||
|
@ -58,7 +58,8 @@ static inline void prepare_non_secure_world()
|
||||
}
|
||||
|
||||
|
||||
static inline void prepare_hypervisor(Cpu::Ttbr::access_t const ttbr)
|
||||
static inline void prepare_hypervisor(Cpu::Ttbr::access_t const ttbr,
|
||||
unsigned cpu_id)
|
||||
{
|
||||
using namespace Hw::Mm;
|
||||
|
||||
@ -80,7 +81,7 @@ static inline void prepare_hypervisor(Cpu::Ttbr::access_t const ttbr)
|
||||
/* set hypervisor exception vector */
|
||||
Cpu::Vbar_el2::write(el2_addr(hypervisor_exception_vector().base));
|
||||
Genode::addr_t const stack_el2 = el2_addr(hypervisor_stack().base +
|
||||
hypervisor_stack().size);
|
||||
(cpu_id+1) * 0x1000);
|
||||
|
||||
/* set hypervisor's translation table */
|
||||
Cpu::Ttbr0_el2::write(ttbr);
|
||||
@ -89,7 +90,7 @@ static inline void prepare_hypervisor(Cpu::Ttbr::access_t const ttbr)
|
||||
Cpu::Tcr_el2::T0sz::set(tcr_el2, 25);
|
||||
Cpu::Tcr_el2::Irgn0::set(tcr_el2, 1);
|
||||
Cpu::Tcr_el2::Orgn0::set(tcr_el2, 1);
|
||||
Cpu::Tcr_el2::Sh0::set(tcr_el2, 0b10);
|
||||
Cpu::Tcr_el2::Sh0::set(tcr_el2, 0b11);
|
||||
|
||||
/* prepare MMU usage by hypervisor code */
|
||||
Cpu::Tcr_el2::write(tcr_el2);
|
||||
@ -141,6 +142,8 @@ unsigned Bootstrap::Platform::enable_mmu()
|
||||
bool primary = primary_cpu;
|
||||
if (primary) primary_cpu = false;
|
||||
|
||||
unsigned cpu_id = (Cpu::Mpidr::read() & 0xff);
|
||||
|
||||
Cpu::Ttbr::access_t ttbr =
|
||||
Cpu::Ttbr::Baddr::masked((Genode::addr_t)core_pd->table_base);
|
||||
|
||||
@ -152,7 +155,7 @@ unsigned Bootstrap::Platform::enable_mmu()
|
||||
prepare_non_secure_world();
|
||||
} else {
|
||||
::Board::Pic pic __attribute__((unused)) {};
|
||||
prepare_hypervisor(ttbr);
|
||||
prepare_hypervisor(ttbr, cpu_id);
|
||||
}
|
||||
}
|
||||
|
||||
@ -201,5 +204,5 @@ unsigned Bootstrap::Platform::enable_mmu()
|
||||
Cpu::Sctlr::Uct::set(sctlr, 1);
|
||||
Cpu::Sctlr_el1::write(sctlr);
|
||||
|
||||
return (Cpu::Mpidr::read() & 0xff);
|
||||
return cpu_id;
|
||||
}
|
||||
|
@ -12,11 +12,11 @@
|
||||
*/
|
||||
|
||||
#include <platform.h>
|
||||
#include <hw/memory_map.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 */
|
||||
extern "C" void * _start_setup_stack; /* entrypoint for non-boot CPUs */
|
||||
|
||||
using namespace Board;
|
||||
|
||||
@ -161,7 +161,7 @@ Bootstrap::Platform::Board::Board()
|
||||
}
|
||||
|
||||
|
||||
static inline void switch_to_supervisor_mode()
|
||||
static inline void switch_to_supervisor_mode(unsigned cpu_id)
|
||||
{
|
||||
using Cpsr = Hw::Arm_cpu::Psr;
|
||||
|
||||
@ -170,6 +170,9 @@ static inline void switch_to_supervisor_mode()
|
||||
Cpsr::F::set(cpsr, 1);
|
||||
Cpsr::I::set(cpsr, 1);
|
||||
|
||||
Genode::addr_t const stack = Hw::Mm::hypervisor_stack().base +
|
||||
(cpu_id+1) * 0x1000;
|
||||
|
||||
asm volatile (
|
||||
"msr sp_svc, sp \n" /* copy current mode's sp */
|
||||
"msr lr_svc, lr \n" /* copy current mode's lr */
|
||||
@ -178,7 +181,7 @@ static inline void switch_to_supervisor_mode()
|
||||
"msr spsr_cxfs, %[cpsr] \n" /* set psr for supervisor mode */
|
||||
"adr lr, 1f \n" /* load exception return address */
|
||||
"eret \n" /* exception return */
|
||||
"1:":: [cpsr] "r" (cpsr), [stack] "r" (&hyp_mode_stack));
|
||||
"1:":: [cpsr] "r" (cpsr), [stack] "r" (stack));
|
||||
}
|
||||
|
||||
|
||||
@ -186,13 +189,14 @@ unsigned Bootstrap::Platform::enable_mmu()
|
||||
{
|
||||
static volatile bool primary_cpu = true;
|
||||
static unsigned long timer_freq = Cpu::Cntfrq::read();
|
||||
unsigned cpu = Cpu::Mpidr::Aff_0::get(Cpu::Mpidr::read());
|
||||
|
||||
/* locally initialize interrupt controller */
|
||||
::Board::Pic pic { };
|
||||
|
||||
prepare_nonsecure_world(timer_freq);
|
||||
prepare_hypervisor((addr_t)core_pd->table_base);
|
||||
switch_to_supervisor_mode();
|
||||
switch_to_supervisor_mode(cpu);
|
||||
|
||||
Cpu::Sctlr::init();
|
||||
Cpu::Cpsr::init();
|
||||
@ -206,7 +210,7 @@ unsigned Bootstrap::Platform::enable_mmu()
|
||||
|
||||
Cpu::enable_mmu_and_caches((Genode::addr_t)core_pd->table_base);
|
||||
|
||||
return Cpu::Mpidr::Aff_0::get(Cpu::Mpidr::read());
|
||||
return cpu;
|
||||
}
|
||||
|
||||
|
||||
|
@ -15,7 +15,6 @@
|
||||
#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 */
|
||||
|
||||
using namespace Board;
|
||||
|
||||
@ -31,7 +30,7 @@ Bootstrap::Platform::Board::Board()
|
||||
Cpu_mmio::IRQ_CONTROLLER_VT_CTRL_SIZE }) {}
|
||||
|
||||
|
||||
static inline void switch_to_supervisor_mode()
|
||||
static inline void switch_to_supervisor_mode(unsigned cpu_id)
|
||||
{
|
||||
using Cpsr = Hw::Arm_cpu::Psr;
|
||||
|
||||
@ -40,6 +39,9 @@ static inline void switch_to_supervisor_mode()
|
||||
Cpsr::F::set(cpsr, 1);
|
||||
Cpsr::I::set(cpsr, 1);
|
||||
|
||||
Genode::addr_t const stack = Hw::Mm::hypervisor_stack().base +
|
||||
(cpu_id+1) * 0x1000;
|
||||
|
||||
asm volatile (
|
||||
"msr sp_svc, sp \n" /* copy current mode's sp */
|
||||
"msr lr_svc, lr \n" /* copy current mode's lr */
|
||||
@ -48,13 +50,14 @@ static inline void switch_to_supervisor_mode()
|
||||
"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));
|
||||
"1:":: [cpsr] "r" (cpsr), [stack] "r" (stack));
|
||||
}
|
||||
|
||||
|
||||
unsigned Bootstrap::Platform::enable_mmu()
|
||||
{
|
||||
static volatile bool primary_cpu = true;
|
||||
unsigned cpu = Cpu::Mpidr::Aff_0::get(Cpu::Mpidr::read());
|
||||
|
||||
/* locally initialize interrupt controller */
|
||||
::Board::Pic pic { };
|
||||
@ -67,14 +70,14 @@ unsigned Bootstrap::Platform::enable_mmu()
|
||||
}
|
||||
|
||||
prepare_hypervisor((addr_t)core_pd->table_base);
|
||||
switch_to_supervisor_mode();
|
||||
switch_to_supervisor_mode(cpu);
|
||||
|
||||
Cpu::Sctlr::init();
|
||||
Cpu::Cpsr::init();
|
||||
|
||||
Cpu::enable_mmu_and_caches((Genode::addr_t)core_pd->table_base);
|
||||
|
||||
return Cpu::Mpidr::Aff_0::get(Cpu::Mpidr::read());
|
||||
return cpu;
|
||||
}
|
||||
|
||||
|
||||
|
@ -35,6 +35,14 @@ namespace Kernel
|
||||
|
||||
class Kernel::Vm : private Kernel::Object, public Cpu_job
|
||||
{
|
||||
public:
|
||||
|
||||
struct Identity
|
||||
{
|
||||
unsigned const id;
|
||||
void * const table;
|
||||
};
|
||||
|
||||
private:
|
||||
|
||||
using State = Board::Vm_state;
|
||||
@ -48,10 +56,9 @@ class Kernel::Vm : private Kernel::Object, public Cpu_job
|
||||
enum Scheduler_state { ACTIVE, INACTIVE };
|
||||
|
||||
Object _kernel_object { *this };
|
||||
unsigned _id = 0;
|
||||
State & _state;
|
||||
Signal_context & _context;
|
||||
void * const _table;
|
||||
Identity const _id;
|
||||
Scheduler_state _scheduled = INACTIVE;
|
||||
Board::Vcpu_context _vcpu_context;
|
||||
|
||||
@ -60,16 +67,14 @@ class Kernel::Vm : private Kernel::Object, public Cpu_job
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* \param cpu cpu affinity
|
||||
* \param state initial CPU state
|
||||
* \param context signal for VM exceptions other than interrupts
|
||||
* \param table translation table for guest to host physical memory
|
||||
*/
|
||||
Vm(unsigned cpu,
|
||||
State & state,
|
||||
Signal_context & context,
|
||||
void * const table);
|
||||
|
||||
~Vm();
|
||||
Identity & id);
|
||||
|
||||
/**
|
||||
* Inject an interrupt to this VM
|
||||
@ -85,8 +90,7 @@ class Kernel::Vm : private Kernel::Object, public Cpu_job
|
||||
* \param dst memory donation for the VM object
|
||||
* \param state location of the CPU state of the VM
|
||||
* \param signal_context_id kernel name of the signal context for VM events
|
||||
* \param table guest-physical to host-physical translation
|
||||
* table pointer
|
||||
* \param id VM identity
|
||||
*
|
||||
* \retval cap id when successful, otherwise invalid cap id
|
||||
*/
|
||||
@ -94,10 +98,10 @@ class Kernel::Vm : private Kernel::Object, public Cpu_job
|
||||
unsigned cpu,
|
||||
void * const state,
|
||||
capid_t const signal_context_id,
|
||||
void * const table)
|
||||
Identity & id)
|
||||
{
|
||||
return call(call_id_new_vm(), (Call_arg)&vm, (Call_arg)cpu,
|
||||
(Call_arg)state, (Call_arg)table, signal_context_id);
|
||||
(Call_arg)state, (Call_arg)&id, signal_context_id);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -25,7 +25,7 @@ void Kernel::Thread::_call_new_vm()
|
||||
}
|
||||
|
||||
_call_new<Vm>((unsigned)user_arg_2(), *(Board::Vm_state*)user_arg_3(),
|
||||
*context, (void*)user_arg_4());
|
||||
*context, *(Vm::Identity*)user_arg_4());
|
||||
}
|
||||
|
||||
|
||||
|
@ -80,6 +80,22 @@ void * Vm_session_component::_alloc_table()
|
||||
}
|
||||
|
||||
|
||||
using Vmid_allocator = Genode::Bit_allocator<256>;
|
||||
|
||||
static Vmid_allocator &alloc()
|
||||
{
|
||||
static Vmid_allocator * allocator = nullptr;
|
||||
if (!allocator) {
|
||||
allocator = unmanaged_singleton<Vmid_allocator>();
|
||||
|
||||
/* reserve VM ID 0 for the hypervisor */
|
||||
unsigned id = allocator->alloc();
|
||||
assert (id == 0);
|
||||
}
|
||||
return *allocator;
|
||||
}
|
||||
|
||||
|
||||
Vm_session_component::Vm_session_component(Rpc_entrypoint &ds_ep,
|
||||
Resources resources,
|
||||
Label const &,
|
||||
@ -96,7 +112,8 @@ Vm_session_component::Vm_session_component(Rpc_entrypoint &ds_ep,
|
||||
_region_map(region_map),
|
||||
_table(*construct_at<Board::Vm_page_table>(_alloc_table())),
|
||||
_table_array(*(new (cma()) Board::Vm_page_table_array([this] (void * virt) {
|
||||
return (addr_t)cma().phys_addr(virt);})))
|
||||
return (addr_t)cma().phys_addr(virt);}))),
|
||||
_id({(unsigned)alloc().alloc(), cma().phys_addr(&_table)})
|
||||
{
|
||||
/* configure managed VM area */
|
||||
_map.add_range(0, 0UL - 0x1000);
|
||||
@ -117,7 +134,7 @@ Vm_session_component::~Vm_session_component()
|
||||
}
|
||||
|
||||
/* free region in allocator */
|
||||
for (unsigned i = 0; i < _id_alloc; i++) {
|
||||
for (unsigned i = 0; i < _vcpu_id_alloc; i++) {
|
||||
Vcpu & vcpu = _vcpus[i];
|
||||
if (vcpu.ds_cap.valid()) {
|
||||
_region_map.detach(vcpu.ds_addr);
|
||||
@ -128,4 +145,5 @@ Vm_session_component::~Vm_session_component()
|
||||
/* free guest-to-host page tables */
|
||||
destroy(platform().core_mem_alloc(), &_table);
|
||||
destroy(platform().core_mem_alloc(), &_table_array);
|
||||
alloc().free(_id.id);
|
||||
}
|
||||
|
@ -23,21 +23,18 @@ using namespace Kernel;
|
||||
Kernel::Vm::Vm(unsigned,
|
||||
Genode::Vm_state & state,
|
||||
Kernel::Signal_context & context,
|
||||
void * const)
|
||||
Identity & id)
|
||||
: Kernel::Object { *this },
|
||||
Cpu_job(Cpu_priority::MIN, 0),
|
||||
_state(state),
|
||||
_context(context),
|
||||
_table(0),
|
||||
_vcpu_context(cpu_pool().primary_cpu())
|
||||
Cpu_job(Cpu_priority::MIN, 0),
|
||||
_state(state),
|
||||
_context(context),
|
||||
_id(id),
|
||||
_vcpu_context(cpu_pool().primary_cpu())
|
||||
{
|
||||
affinity(cpu_pool().primary_cpu());
|
||||
}
|
||||
|
||||
|
||||
Kernel::Vm::~Vm() {}
|
||||
|
||||
|
||||
void Vm::exception(Cpu & cpu)
|
||||
{
|
||||
switch(_state.cpu_exception) {
|
||||
|
@ -48,6 +48,9 @@ void * Vm_session_component::_alloc_table()
|
||||
}
|
||||
|
||||
|
||||
static unsigned id_alloc = 0;
|
||||
|
||||
|
||||
Vm_session_component::Vm_session_component(Rpc_entrypoint &ep,
|
||||
Resources resources,
|
||||
Label const &,
|
||||
@ -55,15 +58,21 @@ Vm_session_component::Vm_session_component(Rpc_entrypoint &ep,
|
||||
Ram_allocator &ram_alloc,
|
||||
Region_map ®ion_map,
|
||||
unsigned, Trace::Source_registry &)
|
||||
:
|
||||
Ram_quota_guard(resources.ram_quota),
|
||||
Cap_quota_guard(resources.cap_quota),
|
||||
_ep(ep),
|
||||
_constrained_md_ram_alloc(ram_alloc, _ram_quota_guard(), _cap_quota_guard()),
|
||||
_sliced_heap(_constrained_md_ram_alloc, region_map),
|
||||
_region_map(region_map),
|
||||
: Ram_quota_guard(resources.ram_quota),
|
||||
Cap_quota_guard(resources.cap_quota),
|
||||
_ep(ep),
|
||||
_constrained_md_ram_alloc(ram_alloc, _ram_quota_guard(), _cap_quota_guard()),
|
||||
_sliced_heap(_constrained_md_ram_alloc, region_map),
|
||||
_region_map(region_map),
|
||||
_table(*construct_at<Board::Vm_page_table>(_alloc_table())),
|
||||
_table_array(dummy_array()) { }
|
||||
_table_array(dummy_array()),
|
||||
_id({id_alloc++, nullptr})
|
||||
{
|
||||
if (_id.id) {
|
||||
error("Only one TrustZone VM available!");
|
||||
throw Service_denied();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Vm_session_component::~Vm_session_component()
|
||||
@ -79,11 +88,13 @@ Vm_session_component::~Vm_session_component()
|
||||
}
|
||||
|
||||
/* free region in allocator */
|
||||
for (unsigned i = 0; i < _id_alloc; i++) {
|
||||
for (unsigned i = 0; i < _vcpu_id_alloc; i++) {
|
||||
Vcpu & vcpu = _vcpus[i];
|
||||
if (vcpu.ds_cap.valid()) {
|
||||
_region_map.detach(vcpu.ds_addr);
|
||||
_constrained_md_ram_alloc.free(vcpu.ds_cap);
|
||||
}
|
||||
}
|
||||
|
||||
id_alloc--;
|
||||
}
|
||||
|
@ -11,34 +11,12 @@
|
||||
* under the terms of the GNU Affero General Public License version 3.
|
||||
*/
|
||||
|
||||
.set USR_MODE, 16
|
||||
.set FIQ_MODE, 17
|
||||
.set IRQ_MODE, 18
|
||||
.set SVC_MODE, 19
|
||||
.set ABT_MODE, 23
|
||||
.set UND_MODE, 27
|
||||
.set SYS_MODE, 31
|
||||
|
||||
.macro _save_bank mode
|
||||
cps #\mode /* switch to given mode */
|
||||
mrs r1, spsr /* store mode-specific spsr */
|
||||
stmia r0!, {r1,sp,lr} /* store mode-specific sp and lr */
|
||||
.endm /* _save_bank mode */
|
||||
|
||||
.macro _restore_bank mode
|
||||
cps #\mode /* switch to given mode */
|
||||
ldmia r0!, {r1,sp,lr} /* load mode-specific sp, lr, and spsr into r1 */
|
||||
msr spsr_cxfs, r1 /* load mode-specific spsr */
|
||||
.endm
|
||||
|
||||
.macro _vm_exit exception_type
|
||||
str r0, [sp]
|
||||
push { r0 }
|
||||
mrc p15, 4, r0, c1, c1, 0 /* read HCR register */
|
||||
tst r0, #1 /* check VM bit */
|
||||
ldreq r0, [sp]
|
||||
beq _host_to_vm
|
||||
mov r0, #\exception_type
|
||||
str r0, [sp, #17*4]
|
||||
b _vm_to_host
|
||||
.endm /* _vm_exit */
|
||||
|
||||
@ -70,146 +48,176 @@ _vt_irq_entry: _vm_exit 6
|
||||
_vt_trp_entry: _vm_exit 8
|
||||
|
||||
_host_to_vm:
|
||||
msr elr_hyp, r2
|
||||
msr spsr_cxfs, r3 /* load cpsr */
|
||||
mcrr p15, 6, r5, r6, c2 /* write VTTBR */
|
||||
mcr p15, 0, r7, c1, c0, 0 /* write SCTRL */
|
||||
mcr p15, 4, r8, c1, c1, 3 /* write HSTR */
|
||||
mcr p15, 4, r9, c1, c1, 0 /* write HCR register */
|
||||
mcr p15, 0, r12, c2, c0, 2 /* write TTBRC */
|
||||
sub sp, r0, #46*4
|
||||
ldm r0!, {r1-r12}
|
||||
mcr p15, 0, r1, c2, c0, 0 /* write TTBR0 */
|
||||
mcr p15, 0, r2, c2, c0, 1 /* write TTBR1 */
|
||||
mcr p15, 0, r3, c10, c2, 0 /* write PRRR */
|
||||
mcr p15, 0, r4, c10, c2, 1 /* write NMRR */
|
||||
mcr p15, 0, r5, c3, c0, 0 /* write DACR */
|
||||
mcr p15, 0, r6, c5, c0, 0 /* write DFSR */
|
||||
mcr p15, 0, r7, c5, c0, 1 /* write IFSR */
|
||||
mcr p15, 0, r8, c5, c1, 0 /* write ADFSR */
|
||||
mcr p15, 0, r9, c5, c1, 1 /* write AIFSR */
|
||||
mcr p15, 0, r10, c6, c0, 0 /* write DFAR */
|
||||
mcr p15, 0, r11, c6, c0, 2 /* write IFAR */
|
||||
mcr p15, 0, r12, c13, c0, 1 /* write CIDR */
|
||||
ldm r0!, {r1-r4}
|
||||
mcr p15, 0, r1, c13, c0, 2 /* write TLS1 */
|
||||
mcr p15, 0, r2, c13, c0, 3 /* write TLS2 */
|
||||
mcr p15, 0, r3, c13, c0, 4 /* write TLS3 */
|
||||
mcr p15, 0, r4, c1, c0, 2 /* write CPACR */
|
||||
ldr r1, [r0]
|
||||
vmsr fpscr, r1
|
||||
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 */
|
||||
push { r1 }
|
||||
ldr r0, [sp, #1*4]
|
||||
add r0, r0, #13*4
|
||||
ldmia r0!, { r1-r5 }
|
||||
msr sp_usr, r1
|
||||
mov lr, r2
|
||||
msr elr_hyp, r3
|
||||
msr spsr_cxfs, r4
|
||||
ldmia r0!, { r1-r12 }
|
||||
msr spsr_und, r1
|
||||
msr sp_und, r2
|
||||
msr lr_und, r3
|
||||
msr spsr_svc, r4
|
||||
msr sp_svc, r5
|
||||
msr lr_svc, r6
|
||||
msr spsr_abt, r7
|
||||
msr sp_abt, r8
|
||||
msr lr_abt, r9
|
||||
msr spsr_irq, r10
|
||||
msr sp_irq, r11
|
||||
msr lr_irq, r12
|
||||
ldmia r0!, {r5 - r12}
|
||||
msr spsr_fiq, r5
|
||||
msr sp_fiq, r6
|
||||
msr lr_fiq, r7
|
||||
msr r8_fiq, r8
|
||||
msr r9_fiq, r9
|
||||
msr r10_fiq, r10
|
||||
msr r11_fiq, r11
|
||||
msr r12_fiq, r12
|
||||
ldmia r0!, {r1 - r12}
|
||||
mcrr p15, 6, r1, r2, c2 /* write VTTBR */
|
||||
mcr p15, 0, r3, c1, c0, 0 /* write SCTRL */
|
||||
mcr p15, 4, r4, c1, c1, 3 /* write HSTR */
|
||||
mcr p15, 4, r5, c1, c1, 0 /* write HCR register */
|
||||
mcr p15, 0, r8, c2, c0, 2 /* write TTBRC */
|
||||
mcr p15, 0, r9, c2, c0, 0 /* write TTBR0 */
|
||||
mcr p15, 0, r10, c2, c0, 1 /* write TTBR1 */
|
||||
mcr p15, 0, r11, c10, c2, 0 /* write PRRR */
|
||||
mcr p15, 0, r12, c10, c2, 1 /* write NMRR */
|
||||
ldmia r0!, {r1-r12}
|
||||
mcr p15, 0, r1, c3, c0, 0 /* write DACR */
|
||||
mcr p15, 0, r2, c5, c0, 0 /* write DFSR */
|
||||
mcr p15, 0, r3, c5, c0, 1 /* write IFSR */
|
||||
mcr p15, 0, r4, c5, c1, 0 /* write ADFSR */
|
||||
mcr p15, 0, r5, c5, c1, 1 /* write AIFSR */
|
||||
mcr p15, 0, r6, c6, c0, 0 /* write DFAR */
|
||||
mcr p15, 0, r7, c6, c0, 2 /* write IFAR */
|
||||
mcr p15, 0, r8, c13, c0, 1 /* write CIDR */
|
||||
mcr p15, 0, r9, c13, c0, 2 /* write TLS1 */
|
||||
mcr p15, 0, r10, c13, c0, 3 /* write TLS2 */
|
||||
mcr p15, 0, r11, c13, c0, 4 /* write TLS3 */
|
||||
mcr p15, 0, r12, c1, c0, 2 /* write CPACR */
|
||||
ldmia r0!, {r1-r2}
|
||||
mcr p15, 4, r1, c0, c0, 5 /* write VMPIDR */
|
||||
vmsr fpscr, r2
|
||||
vldm r0!, {d0-d15}
|
||||
vldm r0!, {d16-d31}
|
||||
ldmia r0!, {r1-r6}
|
||||
mcrr p15, 4, r1, r2, c14 /* write cntvoff */
|
||||
mcrr p15, 3, r3, r4, c14 /* write cntv_cval */
|
||||
mcr p15, 0, r5, c14, c3, 1 /* write cntv_ctl */
|
||||
mcr p15, 0, r6, c14, c1, 0 /* write cntkctl */
|
||||
ldr r0, [sp, #1*4]
|
||||
ldmia r0, {r0-r12} /* load vm's r0-r12 */
|
||||
eret
|
||||
|
||||
_vm_to_host:
|
||||
add r0, sp, #1*4
|
||||
stmia r0, {r1-r12} /* save regs r1-r12 */
|
||||
mov r1, #0
|
||||
mcrr p15, 6, r1, r1, c2 /* write VTTBR */
|
||||
mcr p15, 4, r1, c1, c1, 0 /* write HCR register */
|
||||
mcr p15, 4, r1, c1, c1, 3 /* write HSTR register */
|
||||
push { r0 } /* push cpu excep. */
|
||||
ldr r0, [sp, #3*4] /* load vm state ptr */
|
||||
add r0, r0, #1*4 /* skip r0 */
|
||||
stmia r0!, {r1-r12} /* save regs r1-r12 */
|
||||
pop { r5 } /* pop cpu excep. */
|
||||
pop { r1 } /* pop r0 */
|
||||
str r1, [r0, #-13*4] /* save r0 */
|
||||
mrs r1, sp_usr /* read USR sp */
|
||||
mov r2, lr /* read USR lr */
|
||||
mrs r3, elr_hyp /* read ip */
|
||||
mrs r4, spsr /* read cpsr */
|
||||
mrs r6, spsr_und
|
||||
mrs r7, sp_und
|
||||
mrs r8, lr_und
|
||||
mrs r9, spsr_svc
|
||||
mrs r10, sp_svc
|
||||
mrs r11, lr_svc
|
||||
mrs r12, spsr_abt
|
||||
stmia r0!, {r1-r12}
|
||||
mrs r1, sp_abt
|
||||
mrs r2, lr_abt
|
||||
mrs r3, spsr_irq
|
||||
mrs r4, sp_irq
|
||||
mrs r5, lr_irq
|
||||
mrs r6, spsr_fiq
|
||||
mrs r7, sp_fiq
|
||||
mrs r8, lr_fiq
|
||||
mrs r9, r8_fiq
|
||||
mrs r10, r9_fiq
|
||||
mrs r11, r10_fiq
|
||||
mrs r12, r11_fiq
|
||||
stmia r0!, {r1-r12}
|
||||
mrs r1, r12_fiq
|
||||
str r1, [r0]
|
||||
add r0, r0, #3*4 /* skip VTTBR */
|
||||
mrc p15, 0, r1, c1, c0, 0 /* read SCTRL */
|
||||
mrc p15, 4, r2, c5, c2, 0 /* read HSR */
|
||||
mrc p15, 4, r3, c6, c0, 4 /* read HPFAR */
|
||||
mrc p15, 4, r4, c6, c0, 0 /* read HDFAR */
|
||||
mrc p15, 4, r5, c6, c0, 2 /* read HIFAR */
|
||||
mrc p15, 0, r6, c2, c0, 2 /* read TTBRC */
|
||||
mrc p15, 0, r7, c2, c0, 0 /* read TTBR0 */
|
||||
mrc p15, 0, r8, c2, c0, 1 /* read TTBR1 */
|
||||
mrc p15, 0, r9, c10, c2, 0 /* read PRRR */
|
||||
mrc p15, 0, r10, c10, c2, 1 /* read NMRR */
|
||||
mrc p15, 0, r11, c3, c0, 0 /* read DACR */
|
||||
mrc p15, 0, r12, c5, c0, 0 /* read DFSR */
|
||||
stmia r0!, {r1-r12}
|
||||
mrc p15, 0, r1, c5, c0, 1 /* read IFSR */
|
||||
mrc p15, 0, r2, c5, c1, 0 /* read ADFSR */
|
||||
mrc p15, 0, r3, c5, c1, 1 /* read AIFSR */
|
||||
mrc p15, 0, r4, c6, c0, 0 /* read DFAR */
|
||||
mrc p15, 0, r5, c6, c0, 2 /* read IFAR */
|
||||
mrc p15, 0, r6, c13, c0, 1 /* read CIDR */
|
||||
mrc p15, 0, r7, c13, c0, 2 /* read TLS1 */
|
||||
mrc p15, 0, r8, c13, c0, 3 /* read TLS2 */
|
||||
mrc p15, 0, r9, c13, c0, 4 /* read TLS3 */
|
||||
mrc p15, 0, r10, c1, c0, 2 /* read CPACR */
|
||||
mrc p15, 4, r11, c0, c0, 5 /* read VMPIDR */
|
||||
stmia r0!, {r1-r11}
|
||||
mov r1, #1 /* clear fpu excep. state */
|
||||
lsl r1, #30
|
||||
vmsr fpexc, r1
|
||||
vmrs r12, fpscr
|
||||
stmia r0!, {r12}
|
||||
vstm r0!, {d0-d15}
|
||||
vstm r0!, {d16-d31}
|
||||
mrrc p15, 4, r1, r2, c14 /* read cntvoff */
|
||||
mrrc p15, 3, r3, r4, c14 /* read cntv_cval */
|
||||
mrc p15, 0, r5, c14, c3, 1 /* read cntv_ctl */
|
||||
mrc p15, 0, r6, c14, c1, 0 /* read cntkctl */
|
||||
stmia r0!, {r1-r6}
|
||||
|
||||
mrs r1, ELR_hyp /* read ip */
|
||||
mrs r2, spsr /* read cpsr */
|
||||
mrc p15, 0, r3, c1, c0, 0 /* read SCTRL */
|
||||
mrc p15, 4, r4, c5, c2, 0 /* read HSR */
|
||||
mrc p15, 4, r5, c6, c0, 4 /* read HPFAR */
|
||||
mrc p15, 4, r6, c6, c0, 0 /* read HDFAR */
|
||||
mrc p15, 4, r7, c6, c0, 2 /* read HIFAR */
|
||||
mrc p15, 0, r8, c2, c0, 2 /* read TTBRC */
|
||||
mrc p15, 0, r9, c2, c0, 0 /* read TTBR0 */
|
||||
mrc p15, 0, r10, c2, c0, 1 /* read TTBR1 */
|
||||
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-r12}
|
||||
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}
|
||||
clrex
|
||||
dsb sy
|
||||
isb sy
|
||||
|
||||
mov r3, #0xf
|
||||
lsl r3, #20
|
||||
mcr p15, 0, r3, c1, c0, 2 /* write CPACR */
|
||||
/**************************
|
||||
** Restore host context **
|
||||
**************************/
|
||||
|
||||
mov r3, #1 /* clear fpu exception state */
|
||||
lsl r3, #30
|
||||
vmsr fpexc, r3
|
||||
vmrs r4, fpscr
|
||||
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]
|
||||
add r3, r3, #2*4
|
||||
ldm r3, {r4-r11}
|
||||
mcrr p15, 0, r6, r7, c2
|
||||
mcrr p15, 1, r6, r7, c2
|
||||
mcr p15, 0, r8, c1, c0, 0 /* write SCTRL */
|
||||
mcr p15, 0, r9, c2, c0, 2 /* write TTBRC */
|
||||
mcr p15, 0, r10, c10, c2, 0 /* write MAIR0 */
|
||||
mcr p15, 0, r11, c3, c0, 0 /* write DACR */
|
||||
mov r10, #7
|
||||
lsl r10, #6
|
||||
add r10, r10, #SVC_MODE
|
||||
msr spsr_cxsf, r10
|
||||
adr r10, _svc_mode_ret
|
||||
msr ELR_hyp, r10
|
||||
pop { r0, r1 }
|
||||
ldmia r0!, {r1-r12}
|
||||
mcrr p15, 6, r1, r2, c2 /* write VTTBR */
|
||||
mcr p15, 4, r3, c1, c1, 0 /* write HCR register */
|
||||
mcr p15, 4, r4, c1, c1, 3 /* write HSTR register */
|
||||
mcr p15, 0, r5, c1, c0, 2 /* write CPACR */
|
||||
msr sp_svc, r6
|
||||
msr elr_hyp, r7
|
||||
msr spsr_cxfs, r8
|
||||
mcrr p15, 0, r9, r10, c2 /* write TTBR0 */
|
||||
mcrr p15, 1, r11, r12, c2 /* write TTBR1 */
|
||||
ldmia r0, {r1-r5}
|
||||
mcr p15, 0, r1, c1, c0, 0 /* write SCTRL */
|
||||
mcr p15, 0, r2, c2, c0, 2 /* write TTBRC */
|
||||
mcr p15, 0, r3, c10, c2, 0 /* write MAIR0 */
|
||||
mcr p15, 0, r4, c3, c0, 0 /* write DACR */
|
||||
mcr p15, 4, r5, c0, c0, 5 /* write VMPIDR */
|
||||
eret
|
||||
_svc_mode_ret:
|
||||
stmia r0, {r13-r14}^ /* save user regs sp,lr */
|
||||
add r0, r0, #2*4
|
||||
stmia r0!, {r1-r2} /* save ip, cpsr */
|
||||
add r0, r0, #1*4
|
||||
_save_bank UND_MODE /* save undefined banks */
|
||||
_save_bank SVC_MODE /* save supervisor banks */
|
||||
_save_bank ABT_MODE /* save abort banks */
|
||||
_save_bank IRQ_MODE /* save irq banks */
|
||||
_save_bank FIQ_MODE /* save fiq banks */
|
||||
stmia r0!, {r8-r12} /* save fiq r8-r12 */
|
||||
cps #SVC_MODE
|
||||
ldr r0, _vt_host_context_ptr
|
||||
ldm r0, {sp,pc}
|
||||
|
||||
|
||||
/* host kernel must jump to this point to switch to a vm */
|
||||
.global hypervisor_enter_vm
|
||||
hypervisor_enter_vm:
|
||||
add r0, r0, #13*4
|
||||
ldm r0, {r13 - r14}^
|
||||
add r0, r0, #2*4
|
||||
ldmia r0!, {r2 - r4}
|
||||
_restore_bank UND_MODE
|
||||
_restore_bank SVC_MODE
|
||||
_restore_bank ABT_MODE
|
||||
_restore_bank IRQ_MODE
|
||||
_restore_bank FIQ_MODE
|
||||
ldmia r0!, {r8 - r12}
|
||||
cps #SVC_MODE
|
||||
ldm r0!, {r5 - r12}
|
||||
hvc #0
|
||||
|
||||
_vt_host_context_ptr: .long vt_host_context
|
||||
|
@ -39,22 +39,53 @@ namespace Kernel
|
||||
|
||||
using namespace Kernel;
|
||||
|
||||
extern "C" void kernel();
|
||||
extern void * kernel_stack;
|
||||
extern "C" void hypervisor_enter_vm(Genode::Vm_state&);
|
||||
|
||||
struct Host_context {
|
||||
Cpu::Ttbr_64bit::access_t vttbr;
|
||||
Cpu::Hcr::access_t hcr;
|
||||
Cpu::Hstr::access_t hstr;
|
||||
Cpu::Cpacr::access_t cpacr;
|
||||
addr_t sp;
|
||||
addr_t ip;
|
||||
addr_t spsr;
|
||||
Cpu::Ttbr_64bit::access_t ttbr0;
|
||||
Cpu::Ttbr_64bit::access_t ttbr1;
|
||||
Cpu::Sctlr::access_t sctlr;
|
||||
Cpu::Ttbcr::access_t ttbcr;
|
||||
Cpu::Mair0::access_t mair0;
|
||||
Cpu::Dacr::access_t dacr;
|
||||
Cpu::Vmpidr::access_t vmpidr;
|
||||
} vt_host_context;
|
||||
|
||||
|
||||
extern "C" void kernel();
|
||||
extern "C" void hypervisor_enter_vm(Genode::Vm_state&, Host_context&);
|
||||
|
||||
|
||||
static Host_context & host_context(Cpu & cpu)
|
||||
{
|
||||
static Genode::Constructible<Host_context> host_context[NR_OF_CPUS];
|
||||
if (!host_context[cpu.id()].constructed()) {
|
||||
host_context[cpu.id()].construct();
|
||||
Host_context & c = *host_context[cpu.id()];
|
||||
c.sp = cpu.stack_start();
|
||||
c.ttbr0 = Cpu::Ttbr0_64bit::read();
|
||||
c.ttbr1 = Cpu::Ttbr1_64bit::read();
|
||||
c.sctlr = Cpu::Sctlr::read();
|
||||
c.ttbcr = Cpu::Ttbcr::read();
|
||||
c.mair0 = Cpu::Mair0::read();
|
||||
c.dacr = Cpu::Dacr::read();
|
||||
c.vmpidr = Cpu::Mpidr::read();
|
||||
c.ip = (addr_t) &kernel;
|
||||
c.vttbr = 0;
|
||||
c.hcr = 0;
|
||||
c.hstr = 0;
|
||||
c.cpacr = 0xf00000;
|
||||
c.spsr = 0x1d3;
|
||||
}
|
||||
return *host_context[cpu.id()];
|
||||
}
|
||||
|
||||
|
||||
Board::Vcpu_context::Vm_irq::Vm_irq(unsigned const irq, Cpu & cpu)
|
||||
: Kernel::Irq(irq, cpu.irq_pool())
|
||||
{ }
|
||||
@ -92,50 +123,22 @@ void Board::Vcpu_context::Virtual_timer_irq::disable()
|
||||
asm volatile("mcr p15, 0, %0, c14, c1, 0" :: "r" (0b11));
|
||||
}
|
||||
|
||||
using Vmid_allocator = Genode::Bit_allocator<256>;
|
||||
|
||||
static Vmid_allocator &alloc()
|
||||
{
|
||||
static Vmid_allocator * allocator = nullptr;
|
||||
if (!allocator) {
|
||||
allocator = unmanaged_singleton<Vmid_allocator>();
|
||||
|
||||
/* reserve VM ID 0 for the hypervisor */
|
||||
unsigned id = allocator->alloc();
|
||||
assert (id == 0);
|
||||
}
|
||||
return *allocator;
|
||||
}
|
||||
|
||||
|
||||
Kernel::Vm::Vm(unsigned, /* FIXME: smp support */
|
||||
Kernel::Vm::Vm(unsigned cpu,
|
||||
Genode::Vm_state & state,
|
||||
Kernel::Signal_context & context,
|
||||
void * const table)
|
||||
Identity & id)
|
||||
: Kernel::Object { *this },
|
||||
Cpu_job(Cpu_priority::MIN, 0),
|
||||
_id(alloc().alloc()),
|
||||
_state(state),
|
||||
_context(context),
|
||||
_table(table),
|
||||
_vcpu_context(cpu_pool().primary_cpu())
|
||||
_id(id),
|
||||
_vcpu_context(cpu_pool().cpu(cpu))
|
||||
{
|
||||
affinity(cpu_pool().primary_cpu());
|
||||
|
||||
vt_host_context.sp = _cpu->stack_start();
|
||||
vt_host_context.ttbr0 = Cpu::Ttbr0_64bit::read();
|
||||
vt_host_context.ttbr1 = Cpu::Ttbr1_64bit::read();
|
||||
vt_host_context.sctlr = Cpu::Sctlr::read();
|
||||
vt_host_context.ttbcr = Cpu::Ttbcr::read();
|
||||
vt_host_context.mair0 = Cpu::Mair0::read();
|
||||
vt_host_context.dacr = Cpu::Dacr::read();
|
||||
vt_host_context.ip = (addr_t) &kernel;
|
||||
affinity(cpu_pool().cpu(cpu));
|
||||
}
|
||||
|
||||
|
||||
Kernel::Vm::~Vm() { alloc().free(_id); }
|
||||
|
||||
|
||||
void Kernel::Vm::exception(Cpu & cpu)
|
||||
{
|
||||
switch(_state.cpu_exception) {
|
||||
@ -163,8 +166,8 @@ void Kernel::Vm::proceed(Cpu & cpu)
|
||||
/*
|
||||
* the following values have to be enforced by the hypervisor
|
||||
*/
|
||||
_state.vttbr = Cpu::Ttbr_64bit::Ba::masked((Cpu::Ttbr_64bit::access_t)_table);
|
||||
Cpu::Ttbr_64bit::Asid::set(_state.vttbr, _id);
|
||||
_state.vttbr = Cpu::Ttbr_64bit::Ba::masked((Cpu::Ttbr_64bit::access_t)_id.table);
|
||||
Cpu::Ttbr_64bit::Asid::set(_state.vttbr, _id.id);
|
||||
|
||||
/*
|
||||
* use the following report fields not needed for loading the context
|
||||
@ -174,7 +177,7 @@ void Kernel::Vm::proceed(Cpu & cpu)
|
||||
_state.esr_el2 = Cpu::Hstr::init();
|
||||
_state.hpfar_el2 = Cpu::Hcr::init();
|
||||
|
||||
hypervisor_enter_vm(_state);
|
||||
hypervisor_enter_vm(_state, host_context(cpu));
|
||||
}
|
||||
|
||||
|
||||
|
@ -32,32 +32,34 @@ extern "C" void hypervisor_enter_vm(addr_t vm, addr_t host,
|
||||
addr_t pic, addr_t guest_table);
|
||||
|
||||
|
||||
static Genode::Vm_state & host_context()
|
||||
static Genode::Vm_state & host_context(Cpu & cpu)
|
||||
{
|
||||
static Genode::Constructible<Genode::Vm_state> host_context;
|
||||
if (!host_context.constructed()) {
|
||||
host_context.construct();
|
||||
host_context->ip = (addr_t) &kernel;
|
||||
host_context->pstate = 0;
|
||||
Cpu::Spsr::Sp::set(host_context->pstate, 1); /* select non-el0 stack pointer */
|
||||
Cpu::Spsr::El::set(host_context->pstate, Cpu::Current_el::EL1);
|
||||
Cpu::Spsr::F::set(host_context->pstate, 1);
|
||||
Cpu::Spsr::I::set(host_context->pstate, 1);
|
||||
Cpu::Spsr::A::set(host_context->pstate, 1);
|
||||
Cpu::Spsr::D::set(host_context->pstate, 1);
|
||||
host_context->fpcr = Cpu::Fpcr::read();
|
||||
host_context->fpsr = 0;
|
||||
host_context->sctlr_el1 = Cpu::Sctlr_el1::read();
|
||||
host_context->actlr_el1 = Cpu::Actlr_el1::read();
|
||||
host_context->vbar_el1 = Cpu::Vbar_el1::read();
|
||||
host_context->cpacr_el1 = Cpu::Cpacr_el1::read();
|
||||
host_context->ttbr0_el1 = Cpu::Ttbr0_el1::read();
|
||||
host_context->ttbr1_el1 = Cpu::Ttbr1_el1::read();
|
||||
host_context->tcr_el1 = Cpu::Tcr_el1::read();
|
||||
host_context->mair_el1 = Cpu::Mair_el1::read();
|
||||
host_context->amair_el1 = Cpu::Amair_el1::read();
|
||||
static Genode::Constructible<Genode::Vm_state> host_context[NR_OF_CPUS];
|
||||
if (!host_context[cpu.id()].constructed()) {
|
||||
host_context[cpu.id()].construct();
|
||||
Genode::Vm_state & c = *host_context[cpu.id()];
|
||||
c.sp_el1 = cpu.stack_start();
|
||||
c.ip = (addr_t) &kernel;
|
||||
c.pstate = 0;
|
||||
Cpu::Spsr::Sp::set(c.pstate, 1); /* select non-el0 stack pointer */
|
||||
Cpu::Spsr::El::set(c.pstate, Cpu::Current_el::EL1);
|
||||
Cpu::Spsr::F::set(c.pstate, 1);
|
||||
Cpu::Spsr::I::set(c.pstate, 1);
|
||||
Cpu::Spsr::A::set(c.pstate, 1);
|
||||
Cpu::Spsr::D::set(c.pstate, 1);
|
||||
c.fpcr = Cpu::Fpcr::read();
|
||||
c.fpsr = 0;
|
||||
c.sctlr_el1 = Cpu::Sctlr_el1::read();
|
||||
c.actlr_el1 = Cpu::Actlr_el1::read();
|
||||
c.vbar_el1 = Cpu::Vbar_el1::read();
|
||||
c.cpacr_el1 = Cpu::Cpacr_el1::read();
|
||||
c.ttbr0_el1 = Cpu::Ttbr0_el1::read();
|
||||
c.ttbr1_el1 = Cpu::Ttbr1_el1::read();
|
||||
c.tcr_el1 = Cpu::Tcr_el1::read();
|
||||
c.mair_el1 = Cpu::Mair_el1::read();
|
||||
c.amair_el1 = Cpu::Amair_el1::read();
|
||||
}
|
||||
return *host_context;
|
||||
return *host_context[cpu.id()];
|
||||
}
|
||||
|
||||
|
||||
@ -99,32 +101,15 @@ void Board::Vcpu_context::Virtual_timer_irq::disable()
|
||||
}
|
||||
|
||||
|
||||
using Vmid_allocator = Genode::Bit_allocator<256>;
|
||||
|
||||
static Vmid_allocator &alloc()
|
||||
{
|
||||
static Vmid_allocator * allocator = nullptr;
|
||||
if (!allocator) {
|
||||
allocator = unmanaged_singleton<Vmid_allocator>();
|
||||
|
||||
/* reserve VM ID 0 for the hypervisor */
|
||||
unsigned id = allocator->alloc();
|
||||
assert (id == 0);
|
||||
}
|
||||
return *allocator;
|
||||
}
|
||||
|
||||
|
||||
Vm::Vm(unsigned cpu,
|
||||
Genode::Vm_state & state,
|
||||
Kernel::Signal_context & context,
|
||||
void * const table)
|
||||
Identity & id)
|
||||
: Kernel::Object { *this },
|
||||
Cpu_job(Cpu_priority::MIN, 0),
|
||||
_id(alloc().alloc()),
|
||||
_state(state),
|
||||
_context(context),
|
||||
_table(table),
|
||||
_id(id),
|
||||
_vcpu_context(cpu_pool().cpu(cpu))
|
||||
{
|
||||
affinity(cpu_pool().cpu(cpu));
|
||||
@ -158,9 +143,6 @@ Vm::Vm(unsigned cpu,
|
||||
}
|
||||
|
||||
|
||||
Vm::~Vm() { alloc().free(_id); }
|
||||
|
||||
|
||||
void Vm::exception(Cpu & cpu)
|
||||
{
|
||||
switch (_state.exception_type) {
|
||||
@ -198,12 +180,11 @@ void Vm::proceed(Cpu & cpu)
|
||||
* the following values have to be enforced by the hypervisor
|
||||
*/
|
||||
Cpu::Vttbr_el2::access_t vttbr_el2 =
|
||||
Cpu::Vttbr_el2::Ba::masked((Cpu::Vttbr_el2::access_t)_table);
|
||||
Cpu::Vttbr_el2::Asid::set(vttbr_el2, _id);
|
||||
Cpu::Vttbr_el2::Ba::masked((Cpu::Vttbr_el2::access_t)_id.table);
|
||||
Cpu::Vttbr_el2::Asid::set(vttbr_el2, _id.id);
|
||||
addr_t guest = Hw::Mm::el2_addr(&_state);
|
||||
addr_t pic = Hw::Mm::el2_addr(&_vcpu_context.pic);
|
||||
addr_t host = Hw::Mm::el2_addr(&host_context());
|
||||
host_context().sp_el1 = cpu.stack_start();
|
||||
addr_t host = Hw::Mm::el2_addr(&host_context(cpu));
|
||||
|
||||
hypervisor_enter_vm(guest, host, pic, vttbr_el2);
|
||||
}
|
||||
|
@ -25,7 +25,7 @@ namespace Board {
|
||||
|
||||
struct Virtual_local_pic {};
|
||||
|
||||
enum { TIMER_IRQ = 30, VCPU_MAX = 1 };
|
||||
enum { TIMER_IRQ = 30, VCPU_MAX = 16 };
|
||||
}
|
||||
|
||||
#endif /* _CORE__SPEC__IMX7_SABRELITE__BOARD_H_ */
|
||||
|
@ -27,7 +27,7 @@ namespace Board {
|
||||
TIMER_IRQ = 14 + 16,
|
||||
VT_TIMER_IRQ = 11 + 16,
|
||||
VT_MAINTAINANCE_IRQ = 9 + 16,
|
||||
VCPU_MAX = 4
|
||||
VCPU_MAX = 16
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -31,7 +31,7 @@ namespace Board {
|
||||
TIMER_IRQ = 30 /* PPI IRQ 14 */,
|
||||
VT_TIMER_IRQ = 27,
|
||||
VT_MAINTAINANCE_IRQ = 25,
|
||||
VCPU_MAX = 1
|
||||
VCPU_MAX = 16
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -19,23 +19,20 @@
|
||||
#include <kernel/vm.h>
|
||||
|
||||
Kernel::Vm::Vm(unsigned,
|
||||
Board::Vm_state & state,
|
||||
Board::Vm_state & state,
|
||||
Kernel::Signal_context & context,
|
||||
void * const)
|
||||
Identity & id)
|
||||
: Kernel::Object { *this },
|
||||
Cpu_job(Cpu_priority::MIN, 0),
|
||||
_state(state),
|
||||
_context(context),
|
||||
_table(nullptr),
|
||||
_id(id),
|
||||
_vcpu_context(cpu_pool().primary_cpu())
|
||||
{
|
||||
affinity(cpu_pool().primary_cpu());
|
||||
}
|
||||
|
||||
|
||||
Kernel::Vm::~Vm() { }
|
||||
|
||||
|
||||
void Kernel::Vm::exception(Cpu & cpu)
|
||||
{
|
||||
pause();
|
||||
|
@ -55,15 +55,15 @@ Vm_session_component::Vm_session_component(Rpc_entrypoint &ep,
|
||||
Ram_allocator &ram_alloc,
|
||||
Region_map ®ion_map,
|
||||
unsigned, Trace::Source_registry &)
|
||||
:
|
||||
Ram_quota_guard(resources.ram_quota),
|
||||
Cap_quota_guard(resources.cap_quota),
|
||||
_ep(ep),
|
||||
_constrained_md_ram_alloc(ram_alloc, _ram_quota_guard(), _cap_quota_guard()),
|
||||
_sliced_heap(_constrained_md_ram_alloc, region_map),
|
||||
_region_map(region_map),
|
||||
: Ram_quota_guard(resources.ram_quota),
|
||||
Cap_quota_guard(resources.cap_quota),
|
||||
_ep(ep),
|
||||
_constrained_md_ram_alloc(ram_alloc, _ram_quota_guard(), _cap_quota_guard()),
|
||||
_sliced_heap(_constrained_md_ram_alloc, region_map),
|
||||
_region_map(region_map),
|
||||
_table(*construct_at<Board::Vm_page_table>(_alloc_table())),
|
||||
_table_array(dummy_array()) { }
|
||||
_table_array(dummy_array()),
|
||||
_id({0, nullptr}) { }
|
||||
|
||||
|
||||
Vm_session_component::~Vm_session_component()
|
||||
@ -79,7 +79,7 @@ Vm_session_component::~Vm_session_component()
|
||||
}
|
||||
|
||||
/* free region in allocator */
|
||||
for (unsigned i = 0; i < _id_alloc; i++) {
|
||||
for (unsigned i = 0; i < _vcpu_id_alloc; i++) {
|
||||
Vcpu & vcpu = _vcpus[i];
|
||||
if (vcpu.ds_cap.valid()) {
|
||||
_region_map.detach(vcpu.ds_addr);
|
||||
|
@ -23,10 +23,6 @@
|
||||
|
||||
using namespace Genode;
|
||||
|
||||
static Core_mem_allocator & cma() {
|
||||
return static_cast<Core_mem_allocator&>(platform().core_mem_alloc()); }
|
||||
|
||||
|
||||
size_t Vm_session_component::_ds_size() {
|
||||
return align_addr(sizeof(Board::Vm_state), get_page_size_log2()); }
|
||||
|
||||
@ -70,8 +66,7 @@ void Vm_session_component::_exception_handler(Signal_context_capability handler,
|
||||
|
||||
unsigned const cpu = vcpu.location.valid() ? vcpu.location.xpos() : 0;
|
||||
|
||||
if (!vcpu.kobj.create(cpu, vcpu.ds_addr, Capability_space::capid(handler),
|
||||
cma().phys_addr(&_table)))
|
||||
if (!vcpu.kobj.create(cpu, vcpu.ds_addr, Capability_space::capid(handler), _id))
|
||||
Genode::warning("Cannot instantiate vm kernel object, ",
|
||||
"invalid signal context?");
|
||||
}
|
||||
@ -81,7 +76,7 @@ Vm_session::Vcpu_id Vm_session_component::_create_vcpu(Thread_capability tcap)
|
||||
{
|
||||
using namespace Genode;
|
||||
|
||||
if (_id_alloc == Board::VCPU_MAX) return Vcpu_id{Vcpu_id::INVALID};
|
||||
if (_vcpu_id_alloc == Board::VCPU_MAX) return Vcpu_id{Vcpu_id::INVALID};
|
||||
|
||||
Affinity::Location vcpu_location;
|
||||
auto lambda = [&] (Cpu_thread_component *ptr) {
|
||||
@ -90,7 +85,7 @@ Vm_session::Vcpu_id Vm_session_component::_create_vcpu(Thread_capability tcap)
|
||||
};
|
||||
_ep.apply(tcap, lambda);
|
||||
|
||||
Vcpu & vcpu = _vcpus[_id_alloc];
|
||||
Vcpu & vcpu = _vcpus[_vcpu_id_alloc];
|
||||
vcpu.ds_cap = _constrained_md_ram_alloc.alloc(_ds_size(),
|
||||
Cache_attribute::UNCACHED);
|
||||
try {
|
||||
@ -101,7 +96,7 @@ Vm_session::Vcpu_id Vm_session_component::_create_vcpu(Thread_capability tcap)
|
||||
}
|
||||
|
||||
vcpu.location = vcpu_location;
|
||||
return Vcpu_id { _id_alloc++ };
|
||||
return Vcpu_id { _vcpu_id_alloc++ };
|
||||
}
|
||||
|
||||
|
||||
|
@ -65,7 +65,8 @@ class Genode::Vm_session_component
|
||||
Region_map &_region_map;
|
||||
Board::Vm_page_table &_table;
|
||||
Board::Vm_page_table_array &_table_array;
|
||||
unsigned _id_alloc { 0 };
|
||||
Kernel::Vm::Identity _id;
|
||||
unsigned _vcpu_id_alloc { 0 };
|
||||
|
||||
static size_t _ds_size();
|
||||
bool _valid_id(Vcpu_id id) { return id.id < Board::VCPU_MAX; }
|
||||
|
@ -36,6 +36,9 @@ struct Hw::Arm_cpu
|
||||
struct Me : Bitfield<31, 1> { }; /* multiprocessing extension */
|
||||
);
|
||||
|
||||
/* Virtual Multiprocessor Affinity Register */
|
||||
ARM_CP15_REGISTER_32BIT(Vmpidr, c0, c0, 4, 5);
|
||||
|
||||
/* System Control Register */
|
||||
ARM_CP15_REGISTER_32BIT(Sctlr, c1, c0, 0, 0,
|
||||
struct M : Bitfield<0,1> { }; /* enable MMU */
|
||||
|
@ -46,7 +46,7 @@ Memory_region const Hw::Mm::hypervisor_exception_vector() {
|
||||
return Memory_region(0xfff10000UL, 0x1000UL); }
|
||||
|
||||
Memory_region const Hw::Mm::hypervisor_stack() {
|
||||
return Memory_region(0xfff12000UL, 0x1000UL); }
|
||||
return Memory_region(0xfff20000UL, 0x10000UL); }
|
||||
|
||||
Memory_region const Hw::Mm::boot_info() {
|
||||
return Memory_region(0xfffe0000UL, 0x1000UL); }
|
||||
|
@ -51,7 +51,7 @@ Memory_region const Hw::Mm::hypervisor_exception_vector() {
|
||||
return Memory_region(0xffffffe050000000UL, 0x2000UL); }
|
||||
|
||||
Memory_region const Hw::Mm::hypervisor_stack() {
|
||||
return Memory_region(0xffffffe050003000UL, 0x1000UL); }
|
||||
return Memory_region(0xffffffe060000000UL, 0x10000UL); }
|
||||
|
||||
Memory_region const Hw::Mm::supervisor_exception_vector() {
|
||||
return Memory_region(KERNEL_START, 0x1000UL); }
|
||||
|
Loading…
Reference in New Issue
Block a user