mirror of
https://github.com/genodelabs/genode.git
synced 2025-05-11 04:53:04 +00:00
vancouver: VMX support, improved SVM portals
This commit is contained in:
parent
14307c778a
commit
1434d0948a
@ -1,11 +1,9 @@
|
|||||||
/*
|
/*
|
||||||
* \brief Vancouver main program for Genode
|
* \brief Vancouver main program for Genode
|
||||||
* \author Norman Feske
|
* \author Norman Feske
|
||||||
|
* \author Markus Partheymueller
|
||||||
* \date 2011-11-18
|
* \date 2011-11-18
|
||||||
*
|
*
|
||||||
* This code is partially based on 'vancouver.cc' that comes with the NOVA
|
|
||||||
* userland.
|
|
||||||
*
|
|
||||||
* Important remark about debugging output:
|
* Important remark about debugging output:
|
||||||
*
|
*
|
||||||
* Most of the code within this file is called during virtualization event
|
* Most of the code within this file is called during virtualization event
|
||||||
@ -21,9 +19,16 @@
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2011-2013 Genode Labs GmbH
|
* Copyright (C) 2011-2013 Genode Labs GmbH
|
||||||
|
* Copyright (C) 2012 Intel Corporation
|
||||||
*
|
*
|
||||||
* This file is part of the Genode OS framework, which is distributed
|
* This file is part of the Genode OS framework, which is distributed
|
||||||
* under the terms of the GNU General Public License version 2.
|
* under the terms of the GNU General Public License version 2.
|
||||||
|
*
|
||||||
|
* The code is partially based on the Vancouver VMM, which is distributed
|
||||||
|
* under the terms of the GNU General Public License version 2.
|
||||||
|
*
|
||||||
|
* Modifications by Intel Corporation are contributed under the terms and
|
||||||
|
* conditions of the GNU General Public License version 2.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* Genode includes */
|
/* Genode includes */
|
||||||
@ -213,7 +218,8 @@ class Vcpu_thread : Genode::Thread<STACK_SIZE> {
|
|||||||
|
|
||||||
Genode::addr_t exc_base() { return tid().exc_pt_sel; }
|
Genode::addr_t exc_base() { return tid().exc_pt_sel; }
|
||||||
|
|
||||||
void start(Genode::addr_t sel_ec) {
|
void start(Genode::addr_t sel_ec)
|
||||||
|
{
|
||||||
this->Thread_base::start();
|
this->Thread_base::start();
|
||||||
|
|
||||||
using namespace Genode;
|
using namespace Genode;
|
||||||
@ -437,6 +443,8 @@ class Vcpu_dispatcher : public Genode::Thread<STACK_SIZE>,
|
|||||||
Logging::printf("NPT mapping (base=0x%lx, order=%d, hotspot=0x%lx)\n",
|
Logging::printf("NPT mapping (base=0x%lx, order=%d, hotspot=0x%lx)\n",
|
||||||
crd.base(), crd.order(), hotspot);
|
crd.base(), crd.order(), hotspot);
|
||||||
|
|
||||||
|
utcb->mtd = 0;
|
||||||
|
|
||||||
/* EPT violation during IDT vectoring? */
|
/* EPT violation during IDT vectoring? */
|
||||||
if (utcb->inj_info & 0x80000000)
|
if (utcb->inj_info & 0x80000000)
|
||||||
Logging::panic("EPT violation during IDT vectoring - not handled\n");
|
Logging::panic("EPT violation during IDT vectoring - not handled\n");
|
||||||
@ -463,8 +471,11 @@ class Vcpu_dispatcher : public Genode::Thread<STACK_SIZE>,
|
|||||||
if (!_vcpu->executor.send(msg, true))
|
if (!_vcpu->executor.send(msg, true))
|
||||||
Logging::panic("nobody to execute %s at %x:%x\n", __func__, msg.cpu->cs.sel, msg.cpu->eip);
|
Logging::panic("nobody to execute %s at %x:%x\n", __func__, msg.cpu->cs.sel, msg.cpu->eip);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
utcb->mtd = msg.mtr_out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* SVM portal functions */
|
||||||
void _svm_startup()
|
void _svm_startup()
|
||||||
{
|
{
|
||||||
_handle_vcpu(NO_SKIP, CpuMessage::TYPE_CHECK_IRQ);
|
_handle_vcpu(NO_SKIP, CpuMessage::TYPE_CHECK_IRQ);
|
||||||
@ -513,6 +524,13 @@ class Vcpu_dispatcher : public Genode::Thread<STACK_SIZE>,
|
|||||||
_handle_vcpu(SKIP, CpuMessage::TYPE_CPUID);
|
_handle_vcpu(SKIP, CpuMessage::TYPE_CPUID);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void _svm_hlt()
|
||||||
|
{
|
||||||
|
Utcb *utcb = _utcb_of_myself();
|
||||||
|
utcb->inst_len = 1;
|
||||||
|
_vmx_hlt();
|
||||||
|
}
|
||||||
|
|
||||||
void _svm_msr()
|
void _svm_msr()
|
||||||
{
|
{
|
||||||
_svm_invalid();
|
_svm_invalid();
|
||||||
@ -523,6 +541,106 @@ class Vcpu_dispatcher : public Genode::Thread<STACK_SIZE>,
|
|||||||
_handle_vcpu(NO_SKIP, CpuMessage::TYPE_CHECK_IRQ);
|
_handle_vcpu(NO_SKIP, CpuMessage::TYPE_CHECK_IRQ);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* VMX portal functions */
|
||||||
|
void _vmx_triple()
|
||||||
|
{
|
||||||
|
_handle_vcpu(NO_SKIP, CpuMessage::TYPE_TRIPLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _vmx_init()
|
||||||
|
{
|
||||||
|
_handle_vcpu(NO_SKIP, CpuMessage::TYPE_INIT);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _vmx_irqwin()
|
||||||
|
{
|
||||||
|
_handle_vcpu(NO_SKIP, CpuMessage::TYPE_CHECK_IRQ);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _vmx_hlt()
|
||||||
|
{
|
||||||
|
_handle_vcpu(SKIP, CpuMessage::TYPE_HLT);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _vmx_rdtsc()
|
||||||
|
{
|
||||||
|
_handle_vcpu(SKIP, CpuMessage::TYPE_RDTSC);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _vmx_vmcall()
|
||||||
|
{
|
||||||
|
Utcb *utcb = _utcb_of_myself();
|
||||||
|
utcb->eip += utcb->inst_len;
|
||||||
|
}
|
||||||
|
|
||||||
|
void _vmx_pause()
|
||||||
|
{
|
||||||
|
Utcb *utcb = _utcb_of_myself();
|
||||||
|
CpuMessage msg(CpuMessage::TYPE_SINGLE_STEP, static_cast<CpuState *>(utcb), utcb->mtd);
|
||||||
|
_skip_instruction(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _vmx_invalid()
|
||||||
|
{
|
||||||
|
Utcb *utcb = _utcb_of_myself();
|
||||||
|
utcb->efl |= 2;
|
||||||
|
_handle_vcpu(NO_SKIP, CpuMessage::TYPE_SINGLE_STEP);
|
||||||
|
utcb->mtd |= MTD_RFLAGS;
|
||||||
|
}
|
||||||
|
|
||||||
|
void _vmx_startup()
|
||||||
|
{
|
||||||
|
Utcb *utcb = _utcb_of_myself();
|
||||||
|
_handle_vcpu(NO_SKIP, CpuMessage::TYPE_HLT);
|
||||||
|
utcb->mtd |= MTD_CTRL;
|
||||||
|
utcb->ctrl[0] = 0;
|
||||||
|
utcb->ctrl[1] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void _vmx_recall()
|
||||||
|
{
|
||||||
|
_handle_vcpu(NO_SKIP, CpuMessage::TYPE_CHECK_IRQ);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _vmx_ioio()
|
||||||
|
{
|
||||||
|
Utcb *utcb = _utcb_of_myself();
|
||||||
|
unsigned order;
|
||||||
|
if (utcb->qual[0] & 0x10) {
|
||||||
|
Logging::panic("invalid gueststate intel - not implemented\n");
|
||||||
|
} else {
|
||||||
|
order = utcb->qual[0] & 7;
|
||||||
|
if (order > 2) order = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
_handle_io(utcb->qual[0] & 8, order, utcb->qual[0] >> 16);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _vmx_mmio()
|
||||||
|
{
|
||||||
|
Utcb *utcb = _utcb_of_myself();
|
||||||
|
|
||||||
|
if (!_handle_map_memory(utcb->qual[0] & 0x38))
|
||||||
|
/* this is an access to MMIO */
|
||||||
|
_handle_vcpu(NO_SKIP, CpuMessage::TYPE_SINGLE_STEP);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void _vmx_cpuid()
|
||||||
|
{
|
||||||
|
_handle_vcpu(SKIP, CpuMessage::TYPE_CPUID);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _vmx_msr_read()
|
||||||
|
{
|
||||||
|
_handle_vcpu(SKIP, CpuMessage::TYPE_RDMSR);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _vmx_msr_write()
|
||||||
|
{
|
||||||
|
_handle_vcpu(SKIP, CpuMessage::TYPE_WRMSR);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Portal entry point entered on virtualization events
|
* Portal entry point entered on virtualization events
|
||||||
*
|
*
|
||||||
@ -579,7 +697,8 @@ class Vcpu_dispatcher : public Genode::Thread<STACK_SIZE>,
|
|||||||
Guest_memory &guest_memory,
|
Guest_memory &guest_memory,
|
||||||
Motherboard &motherboard,
|
Motherboard &motherboard,
|
||||||
Genode::Cap_connection &cap_session,
|
Genode::Cap_connection &cap_session,
|
||||||
bool has_svm)
|
bool has_svm,
|
||||||
|
bool has_vmx)
|
||||||
:
|
:
|
||||||
_vcpu(vcpu),
|
_vcpu(vcpu),
|
||||||
_vcpu_thread("vCPU thread"),
|
_vcpu_thread("vCPU thread"),
|
||||||
@ -644,27 +763,67 @@ class Vcpu_dispatcher : public Genode::Thread<STACK_SIZE>,
|
|||||||
Genode::addr_t exc_base =
|
Genode::addr_t exc_base =
|
||||||
_vcpu_thread.exc_base();
|
_vcpu_thread.exc_base();
|
||||||
|
|
||||||
|
_register_handler<0x64, &This::_vmx_irqwin>
|
||||||
|
(exc_base, MTD_IRQ);
|
||||||
_register_handler<0x72, &This::_svm_cpuid>
|
_register_handler<0x72, &This::_svm_cpuid>
|
||||||
(exc_base, mtd_cpuid);
|
(exc_base, MTD_RIP_LEN | MTD_GPR_ACDB | MTD_IRQ);
|
||||||
|
_register_handler<0x78, &This::_svm_hlt>
|
||||||
|
(exc_base, MTD_RIP_LEN | MTD_IRQ);
|
||||||
_register_handler<0x7b, &This::_svm_ioio>
|
_register_handler<0x7b, &This::_svm_ioio>
|
||||||
(exc_base, mtd_all);
|
(exc_base, MTD_RIP_LEN | MTD_QUAL | MTD_GPR_ACDB | MTD_STATE);
|
||||||
_register_handler<0x7c, &This::_svm_msr>
|
_register_handler<0x7c, &This::_svm_msr>
|
||||||
(exc_base, mtd_all);
|
(exc_base, MTD_ALL);
|
||||||
|
_register_handler<0x7f, &This::_vmx_triple>
|
||||||
|
(exc_base, MTD_ALL);
|
||||||
_register_handler<0xfc, &This::_svm_npt>
|
_register_handler<0xfc, &This::_svm_npt>
|
||||||
(exc_base, mtd_all);
|
(exc_base, MTD_ALL);
|
||||||
_register_handler<0xfd, &This::_svm_invalid>
|
_register_handler<0xfd, &This::_svm_invalid>
|
||||||
(exc_base, mtd_all);
|
(exc_base, MTD_ALL);
|
||||||
_register_handler<0xfe, &This::_svm_startup>
|
_register_handler<0xfe, &This::_svm_startup>
|
||||||
(exc_base, mtd_all);
|
(exc_base, MTD_ALL);
|
||||||
_register_handler<0xff, &This::_recall>
|
_register_handler<0xff, &This::_recall>
|
||||||
(exc_base, mtd_irq);
|
(exc_base, MTD_IRQ);
|
||||||
|
|
||||||
|
} else if (has_vmx) {
|
||||||
|
Genode::addr_t exc_base =
|
||||||
|
_vcpu_thread.exc_base();
|
||||||
|
|
||||||
|
_register_handler<2, &This::_vmx_triple>
|
||||||
|
(exc_base, MTD_ALL);
|
||||||
|
_register_handler<3, &This::_vmx_init>
|
||||||
|
(exc_base, MTD_ALL);
|
||||||
|
_register_handler<7, &This::_vmx_irqwin>
|
||||||
|
(exc_base, MTD_IRQ);
|
||||||
|
_register_handler<10, &This::_vmx_cpuid>
|
||||||
|
(exc_base, MTD_RIP_LEN | MTD_GPR_ACDB | MTD_STATE);
|
||||||
|
_register_handler<12, &This::_vmx_hlt>
|
||||||
|
(exc_base, MTD_RIP_LEN | MTD_IRQ);
|
||||||
|
_register_handler<16, &This::_vmx_rdtsc>
|
||||||
|
(exc_base, MTD_RIP_LEN | MTD_GPR_ACDB | MTD_TSC | MTD_STATE);
|
||||||
|
_register_handler<18, &This::_vmx_vmcall>
|
||||||
|
(exc_base, MTD_RIP_LEN | MTD_GPR_ACDB);
|
||||||
|
_register_handler<30, &This::_vmx_ioio>
|
||||||
|
(exc_base, MTD_RIP_LEN | MTD_QUAL | MTD_GPR_ACDB | MTD_STATE | MTD_RFLAGS);
|
||||||
|
_register_handler<31, &This::_vmx_msr_read>
|
||||||
|
(exc_base, MTD_RIP_LEN | MTD_GPR_ACDB | MTD_TSC | MTD_SYSENTER | MTD_STATE);
|
||||||
|
_register_handler<32, &This::_vmx_msr_write>
|
||||||
|
(exc_base, MTD_RIP_LEN | MTD_GPR_ACDB | MTD_TSC | MTD_SYSENTER | MTD_STATE);
|
||||||
|
_register_handler<33, &This::_vmx_invalid>
|
||||||
|
(exc_base, MTD_ALL);
|
||||||
|
_register_handler<40, &This::_vmx_pause>
|
||||||
|
(exc_base, MTD_RIP_LEN | MTD_STATE);
|
||||||
|
_register_handler<48, &This::_vmx_mmio>
|
||||||
|
(exc_base, MTD_ALL);
|
||||||
|
_register_handler<0xfe, &This::_vmx_startup>
|
||||||
|
(exc_base, MTD_IRQ);
|
||||||
|
_register_handler<0xff, &This::_vmx_recall>
|
||||||
|
(exc_base, MTD_IRQ | MTD_RIP_LEN | MTD_GPR_ACDB | MTD_GPR_BSD);
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* XXX: to be done, for now, we only support SVM
|
* We need Hardware Virtualization Features.
|
||||||
*/
|
*/
|
||||||
Logging::panic("no SVM available, sorry");
|
Logging::panic("no SVM/VMX available, sorry");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* let vCPU run */
|
/* let vCPU run */
|
||||||
@ -700,7 +859,8 @@ class Vcpu_dispatcher : public Genode::Thread<STACK_SIZE>,
|
|||||||
* a unique identifier of the VCPU. I.e., it gets passed as
|
* a unique identifier of the VCPU. I.e., it gets passed as
|
||||||
* arguments for 'MessageHostOp' operations.
|
* arguments for 'MessageHostOp' operations.
|
||||||
*/
|
*/
|
||||||
Nova::mword_t sel_sm_ec() {
|
Nova::mword_t sel_sm_ec()
|
||||||
|
{
|
||||||
return tid().exc_pt_sel + Nova::SM_SEL_EC;
|
return tid().exc_pt_sel + Nova::SM_SEL_EC;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -792,7 +952,7 @@ class Machine : public StaticReceiver<Machine>
|
|||||||
Vcpu_dispatcher *vcpu_dispatcher =
|
Vcpu_dispatcher *vcpu_dispatcher =
|
||||||
new Vcpu_dispatcher(msg.vcpu, _guest_memory,
|
new Vcpu_dispatcher(msg.vcpu, _guest_memory,
|
||||||
_motherboard, cap_session,
|
_motherboard, cap_session,
|
||||||
_hip->has_svm());
|
_hip->has_svm(), _hip->has_vmx());
|
||||||
|
|
||||||
msg.value = vcpu_dispatcher->sel_sm_ec();
|
msg.value = vcpu_dispatcher->sel_sm_ec();
|
||||||
return true;
|
return true;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user