vbox: update the PDPTE registers if needed

Fixes #1638
This commit is contained in:
Christian Prochaska 2015-07-24 15:03:12 +02:00 committed by Christian Helmuth
parent 2337dc03f4
commit 824fb72694
2 changed files with 59 additions and 0 deletions

View File

@ -362,6 +362,32 @@ class Vcpu_handler : public Vmm::Vcpu_dispatcher<pthread>
utcb->mtd |= Mtd::EFER;
utcb->write_efer(CPUMGetGuestEFER(pVCpu));
/*
* Update the PDPTE registers if necessary
*
* Intel manual sections 4.4.1 of Vol. 3A and 26.3.2.4 of Vol. 3C
* indicate the conditions when this is the case. The following
* code currently does not check if the recompiler modified any
* CR registers, which means the update can happen more often
* than really necessary.
*/
if (pVM->hm.s.vmx.fSupported &&
CPUMIsGuestPagingEnabledEx(pCtx) &&
CPUMIsGuestInPAEModeEx(pCtx)) {
utcb->mtd |= Mtd::PDPTE;
Genode::uint64_t *pdpte = (Genode::uint64_t*)
guest_memory()->lookup(utcb->cr3, sizeof(utcb->pdpte));
Assert(pdpte != 0);
utcb->pdpte[0] = pdpte[0];
utcb->pdpte[1] = pdpte[1];
utcb->pdpte[2] = pdpte[2];
utcb->pdpte[3] = pdpte[3];
}
Assert(!(VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS)));
return true;

View File

@ -113,6 +113,37 @@ class Vcpu_handler_vmx : public Vcpu_handler
Vcpu_handler::_default_handler();
}
/*
* This VM exit is in part handled by the NOVA kernel (writing the CR
* register) and in part by VirtualBox (updating the PDPTE registers,
* which requires access to the guest physical memory).
* Intel manual sections 4.4.1 of Vol. 3A and 26.3.2.4 of Vol. 3C
* indicate the conditions when the PDPTE registers need to get
* updated.
*/
__attribute__((noreturn)) void _vmx_mov_crx()
{
unsigned long value;
void *stack_reply = reinterpret_cast<void *>(&value - 1);
Genode::Thread_base *myself = Genode::Thread_base::myself();
Nova::Utcb *utcb = reinterpret_cast<Nova::Utcb *>(myself->utcb());
Genode::uint64_t *pdpte = (Genode::uint64_t*)
guest_memory()->lookup(utcb->cr3, sizeof(utcb->pdpte));
Assert(pdpte != 0);
utcb->pdpte[0] = pdpte[0];
utcb->pdpte[1] = pdpte[1];
utcb->pdpte[2] = pdpte[2];
utcb->pdpte[3] = pdpte[3];
utcb->mtd = Nova::Mtd::PDPTE | Nova::Mtd::FPU;
Nova::reply(stack_reply);
}
public:
Vcpu_handler_vmx(size_t stack_size, const pthread_attr_t *attr,
@ -160,6 +191,8 @@ class Vcpu_handler_vmx : public Vcpu_handler
// &This::_vmx_default> (exc_base, Mtd::ALL | Mtd::FPU);
register_handler<VMX_EXIT_WBINVD, This,
&This::_vmx_default> (exc_base, Mtd::ALL | Mtd::FPU);
register_handler<VMX_EXIT_MOV_CRX, This,
&This::_vmx_mov_crx> (exc_base, Mtd::ALL | Mtd::FPU);
register_handler<VMX_EXIT_MOV_DRX, This,
&This::_vmx_default> (exc_base, Mtd::ALL | Mtd::FPU);
register_handler<VMX_EXIT_EPT_VIOLATION, This,