vbox5: enable 64bit SVM support

Fixes #3965
This commit is contained in:
Alexander Boettcher 2021-01-16 17:20:19 +01:00 committed by Norman Feske
parent d186e4361e
commit d6a5a66623
6 changed files with 168 additions and 66 deletions

View File

@ -1 +1 @@
667a8abdf36fece2200041dfb6e85fec3d1b5a81
0316f8810c665d115fb860399d824a6531aa5aad

View File

@ -4,7 +4,7 @@ DOWNLOADS := nova.git
# r10 branch
URL(nova) := https://github.com/alex-ab/NOVA.git
REV(nova) := b49bc550b934d542641a86dc35590b193141c5a7
REV(nova) := 98b501b243bcd7aa1be36454cf58a63aae362c2e
DIR(nova) := src/kernel/nova
PATCHES := $(sort $(wildcard $(REP_DIR)/patches/*.patch))

View File

@ -44,6 +44,14 @@ static inline bool svm_save_state(Nova::Utcb * utcb, VM * pVM, PVMCPU pVCpu)
GENODE_READ_SELREG(gs);
GENODE_READ_SELREG(ss);
if ( !pCtx->cs.Attr.n.u1Granularity
&& pCtx->cs.Attr.n.u1Present
&& pCtx->cs.u32Limit > UINT32_C(0xfffff))
{
Assert((pCtx->cs.u32Limit & 0xfff) == 0xfff);
pCtx->cs.Attr.n.u1Granularity = 1;
}
GENODE_SVM_ASSERT_SELREG(cs);
GENODE_SVM_ASSERT_SELREG(ds);
GENODE_SVM_ASSERT_SELREG(es);
@ -54,6 +62,8 @@ static inline bool svm_save_state(Nova::Utcb * utcb, VM * pVM, PVMCPU pVCpu)
GENODE_READ_SELREG(ldtr);
GENODE_READ_SELREG(tr);
CPUMSetGuestEFER(pVCpu, CPUMGetGuestEFER(pVCpu) & ~uint64_t(MSR_K6_EFER_SVME));
return true;
}
@ -75,14 +85,8 @@ static inline bool svm_load_state(Nova::Utcb * utcb, VM * pVM, PVMCPU pVCpu)
{
PCPUMCTX pCtx = CPUMQueryGuestCtxPtr(pVCpu);
#ifdef __x86_64__
utcb->mtd |= Nova::Mtd::EFER;
utcb->efer = pCtx->msrEFER | MSR_K6_EFER_SVME;
/* unimplemented */
if (CPUMIsGuestInLongModeEx(pCtx))
return false;
utcb->efer &= ~MSR_K6_EFER_LME;
#endif
utcb->write_efer(utcb->read_efer() | MSR_K6_EFER_SVME);
utcb->mtd |= Nova::Mtd::ESDS;
GENODE_WRITE_SELREG(es);

View File

@ -30,29 +30,6 @@ class Vcpu_handler_svm : public Vcpu_handler
_irq_window();
}
__attribute__((noreturn)) void _svm_ioio()
{
using namespace Nova;
using namespace Genode;
Thread *myself = Thread::myself();
Utcb *utcb = reinterpret_cast<Utcb *>(myself->utcb());
if (utcb->qual[0] & 0x4) {
unsigned ctrl0 = utcb->ctrl[0];
Vmm::warning("invalid gueststate");
utcb->ctrl[0] = ctrl0;
utcb->ctrl[1] = 0;
utcb->mtd = Mtd::CTRL;
Nova::reply(_stack_reply);
}
_default_handler();
}
template <unsigned X>
__attribute__((noreturn)) void _svm_npt()
{
@ -72,8 +49,32 @@ class Vcpu_handler_svm : public Vcpu_handler
/* enable VM exits for CPUID */
next_utcb.mtd = Nova::Mtd::CTRL;
next_utcb.ctrl[0] = SVM_CTRL1_INTERCEPT_CPUID;
next_utcb.ctrl[1] = 0;
next_utcb.ctrl[0] = SVM_CTRL1_INTERCEPT_INTR
| SVM_CTRL1_INTERCEPT_NMI
| SVM_CTRL1_INTERCEPT_INIT
| SVM_CTRL1_INTERCEPT_RDPMC
| SVM_CTRL1_INTERCEPT_CPUID
| SVM_CTRL1_INTERCEPT_RSM
| SVM_CTRL1_INTERCEPT_HLT
| SVM_CTRL1_INTERCEPT_INOUT_BITMAP
| SVM_CTRL1_INTERCEPT_MSR_SHADOW
| SVM_CTRL1_INTERCEPT_INVLPGA
| SVM_CTRL1_INTERCEPT_SHUTDOWN
| SVM_CTRL1_INTERCEPT_RDTSC
| SVM_CTRL1_INTERCEPT_FERR_FREEZE;
next_utcb.ctrl[1] = SVM_CTRL2_INTERCEPT_VMRUN
| SVM_CTRL2_INTERCEPT_VMMCALL
| SVM_CTRL2_INTERCEPT_VMLOAD
| SVM_CTRL2_INTERCEPT_VMSAVE
| SVM_CTRL2_INTERCEPT_STGI
| SVM_CTRL2_INTERCEPT_CLGI
| SVM_CTRL2_INTERCEPT_SKINIT
| SVM_CTRL2_INTERCEPT_WBINVD
| SVM_CTRL2_INTERCEPT_MONITOR
| SVM_CTRL2_INTERCEPT_RDTSCP
| SVM_CTRL2_INTERCEPT_MWAIT;
void *exit_status = _start_routine(_start_routine_arg);
pthread_exit(exit_status);
@ -81,6 +82,25 @@ class Vcpu_handler_svm : public Vcpu_handler
Nova::reply(nullptr);
}
__attribute__((noreturn)) void _svm_shutdown()
{
Vmm::error("shutdown exit");
exit(-1);
}
__attribute__((noreturn)) void _svm_invalid()
{
using namespace Nova;
using namespace Genode;
Thread *myself = Thread::myself();
Utcb *utcb = reinterpret_cast<Utcb *>(myself->utcb());
Vmm::warning("invalid svm ip=", Genode::Hex(utcb->ip));
_default_handler();
}
__attribute__((noreturn)) void _svm_recall()
{
_fpu_save();
@ -105,14 +125,56 @@ class Vcpu_handler_svm : public Vcpu_handler
typedef Vcpu_handler_svm This;
register_handler<SVM_EXIT_READ_CR0, This,
&This::_svm_default> (exc_base, Mtd(Mtd::ALL | Mtd::FPU));
register_handler<SVM_EXIT_READ_CR1, This,
&This::_svm_default> (exc_base, Mtd(Mtd::ALL | Mtd::FPU));
register_handler<SVM_EXIT_READ_CR2, This,
&This::_svm_default> (exc_base, Mtd(Mtd::ALL | Mtd::FPU));
register_handler<SVM_EXIT_READ_CR3, This,
&This::_svm_default> (exc_base, Mtd(Mtd::ALL | Mtd::FPU));
register_handler<SVM_EXIT_READ_CR4, This,
&This::_svm_default> (exc_base, Mtd(Mtd::ALL | Mtd::FPU));
register_handler<SVM_EXIT_READ_CR5, This,
&This::_svm_default> (exc_base, Mtd(Mtd::ALL | Mtd::FPU));
register_handler<SVM_EXIT_READ_CR6, This,
&This::_svm_default> (exc_base, Mtd(Mtd::ALL | Mtd::FPU));
register_handler<SVM_EXIT_READ_CR7, This,
&This::_svm_default> (exc_base, Mtd(Mtd::ALL | Mtd::FPU));
register_handler<SVM_EXIT_READ_CR8, This,
&This::_svm_default> (exc_base, Mtd(Mtd::ALL | Mtd::FPU));
register_handler<SVM_EXIT_WRITE_CR0, This,
&This::_svm_default> (exc_base, Mtd(Mtd::ALL | Mtd::FPU));
register_handler<SVM_EXIT_WRITE_CR1, This,
&This::_svm_default> (exc_base, Mtd(Mtd::ALL | Mtd::FPU));
register_handler<SVM_EXIT_WRITE_CR2, This,
&This::_svm_default> (exc_base, Mtd(Mtd::ALL | Mtd::FPU));
register_handler<SVM_EXIT_WRITE_CR3, This,
&This::_svm_default> (exc_base, Mtd(Mtd::ALL | Mtd::FPU));
register_handler<SVM_EXIT_WRITE_CR4, This,
&This::_svm_default> (exc_base, Mtd(Mtd::ALL | Mtd::FPU));
register_handler<SVM_EXIT_WRITE_CR5, This,
&This::_svm_default> (exc_base, Mtd(Mtd::ALL | Mtd::FPU));
register_handler<SVM_EXIT_WRITE_CR6, This,
&This::_svm_default> (exc_base, Mtd(Mtd::ALL | Mtd::FPU));
register_handler<SVM_EXIT_WRITE_CR7, This,
&This::_svm_default> (exc_base, Mtd(Mtd::ALL | Mtd::FPU));
register_handler<SVM_EXIT_WRITE_CR8, This,
&This::_svm_default> (exc_base, Mtd(Mtd::ALL | Mtd::FPU));
register_handler<RECALL, This,
&This::_svm_recall> (exc_base, Mtd::ALL | Mtd::FPU);
&This::_svm_recall> (exc_base, Mtd(Mtd::ALL | Mtd::FPU));
register_handler<SVM_EXIT_INVLPGA, This,
&This::_svm_default> (exc_base, Mtd(Mtd::ALL | Mtd::FPU));
register_handler<SVM_EXIT_IOIO, This,
&This::_svm_ioio> (exc_base, Mtd(Mtd::ALL | Mtd::FPU));
&This::_svm_default> (exc_base, Mtd(Mtd::ALL | Mtd::FPU));
register_handler<SVM_EXIT_VINTR, This,
&This::_svm_vintr> (exc_base, Mtd(Mtd::ALL | Mtd::FPU));
register_handler<SVM_EXIT_RDTSC, This,
&This::_svm_default> (exc_base, Mtd(Mtd::ALL | Mtd::FPU));
register_handler<SVM_EXIT_RDTSCP, This,
&This::_svm_default> (exc_base, Mtd(Mtd::ALL | Mtd::FPU));
register_handler<SVM_EXIT_MSR, This,
&This::_svm_default> (exc_base, Mtd(Mtd::ALL | Mtd::FPU));
register_handler<SVM_NPT, This,
@ -121,6 +183,12 @@ class Vcpu_handler_svm : public Vcpu_handler
&This::_svm_default> (exc_base, Mtd(Mtd::ALL | Mtd::FPU));
register_handler<SVM_EXIT_CPUID, This,
&This::_svm_default> (exc_base, Mtd(Mtd::ALL | Mtd::FPU));
register_handler<SVM_EXIT_SHUTDOWN, This,
&This::_svm_shutdown> (exc_base, Mtd(Mtd::ALL | Mtd::FPU));
register_handler<SVM_EXIT_WBINVD, This,
&This::_svm_default> (exc_base, Mtd(Mtd::ALL | Mtd::FPU));
register_handler<SVM_INVALID, This,
&This::_svm_invalid> (exc_base, Mtd(Mtd::ALL | Mtd::FPU));
register_handler<VCPU_STARTUP, This,
&This::_svm_startup> (exc_base, Mtd(Mtd::ALL | Mtd::FPU));

View File

@ -44,6 +44,14 @@ static inline bool svm_save_state(Genode::Vm_state * state, VM * pVM, PVMCPU pVC
GENODE_READ_SELREG(gs);
GENODE_READ_SELREG(ss);
if ( !pCtx->cs.Attr.n.u1Granularity
&& pCtx->cs.Attr.n.u1Present
&& pCtx->cs.u32Limit > UINT32_C(0xfffff))
{
Assert((pCtx->cs.u32Limit & 0xfff) == 0xfff);
pCtx->cs.Attr.n.u1Granularity = 1;
}
GENODE_SVM_ASSERT_SELREG(cs);
GENODE_SVM_ASSERT_SELREG(ds);
GENODE_SVM_ASSERT_SELREG(es);
@ -54,6 +62,8 @@ static inline bool svm_save_state(Genode::Vm_state * state, VM * pVM, PVMCPU pVC
GENODE_READ_SELREG(ldtr);
GENODE_READ_SELREG(tr);
CPUMSetGuestEFER(pVCpu, CPUMGetGuestEFER(pVCpu) & ~uint64_t(MSR_K6_EFER_SVME));
return true;
}
@ -75,11 +85,7 @@ static inline bool svm_load_state(Genode::Vm_state * state, VM * pVM, PVMCPU pVC
PCPUMCTX pCtx = CPUMQueryGuestCtxPtr(pVCpu);
state->efer.value(pCtx->msrEFER | MSR_K6_EFER_SVME);
/* unimplemented */
if (CPUMIsGuestInLongModeEx(pCtx))
return false;
state->efer.value(state->efer.value() & ~MSR_K6_EFER_LME);
state->efer.value(state->efer.value() | MSR_K6_EFER_SVME);
GENODE_WRITE_SELREG(es);
GENODE_WRITE_SELREG(ds);

View File

@ -38,23 +38,6 @@ class Vcpu_handler_svm : public Vcpu_handler
void _svm_default() { _default_handler(); }
void _svm_vintr() { _irq_window(); }
void _svm_ioio()
{
if (_state->qual_primary.value() & 0x4) {
unsigned ctrl0 = _state->ctrl_primary.value();
Genode::warning("invalid gueststate");
*_state = Genode::Vm_state {}; /* reset */
_state->ctrl_primary.value(ctrl0);
_state->ctrl_secondary.value(0);
_vm_session.run(_vcpu);
} else
_default_handler();
}
template <unsigned X>
void _svm_npt()
{
@ -71,9 +54,32 @@ class Vcpu_handler_svm : public Vcpu_handler
void _svm_startup()
{
/* enable VM exits for CPUID */
next_utcb.ctrl[0] = SVM_CTRL1_INTERCEPT_CPUID;
next_utcb.ctrl[1] = 0;
/* enable VM exits */
next_utcb.ctrl[0] = SVM_CTRL1_INTERCEPT_INTR
| SVM_CTRL1_INTERCEPT_NMI
| SVM_CTRL1_INTERCEPT_INIT
| SVM_CTRL1_INTERCEPT_RDPMC
| SVM_CTRL1_INTERCEPT_CPUID
| SVM_CTRL1_INTERCEPT_RSM
| SVM_CTRL1_INTERCEPT_HLT
| SVM_CTRL1_INTERCEPT_INOUT_BITMAP
| SVM_CTRL1_INTERCEPT_MSR_SHADOW
| SVM_CTRL1_INTERCEPT_INVLPGA
| SVM_CTRL1_INTERCEPT_SHUTDOWN
| SVM_CTRL1_INTERCEPT_RDTSC
| SVM_CTRL1_INTERCEPT_FERR_FREEZE;
next_utcb.ctrl[1] = SVM_CTRL2_INTERCEPT_VMRUN
| SVM_CTRL2_INTERCEPT_VMMCALL
| SVM_CTRL2_INTERCEPT_VMLOAD
| SVM_CTRL2_INTERCEPT_VMSAVE
| SVM_CTRL2_INTERCEPT_STGI
| SVM_CTRL2_INTERCEPT_CLGI
| SVM_CTRL2_INTERCEPT_SKINIT
| SVM_CTRL2_INTERCEPT_WBINVD
| SVM_CTRL2_INTERCEPT_MONITOR
| SVM_CTRL2_INTERCEPT_RDTSCP
| SVM_CTRL2_INTERCEPT_MWAIT;
}
void _handle_vm_exception()
@ -82,13 +88,27 @@ class Vcpu_handler_svm : public Vcpu_handler
bool recall_wait = true;
switch (exit) {
case SVM_EXIT_IOIO: _svm_ioio(); break;
case SVM_EXIT_VINTR: _svm_vintr(); break;
// case SVM_EXIT_RDTSC: _svm_default(); break;
case SVM_EXIT_MSR: _svm_default(); break;
case SVM_NPT: _svm_npt<SVM_NPT>(); break;
case SVM_EXIT_HLT: _svm_default(); break;
case SVM_EXIT_CPUID: _svm_default(); break;
case SVM_EXIT_CPUID:
case SVM_EXIT_HLT:
case SVM_EXIT_INVLPGA:
case SVM_EXIT_IOIO:
case SVM_EXIT_MSR:
case SVM_EXIT_READ_CR0 ... SVM_EXIT_WRITE_CR15:
case SVM_EXIT_RDTSC:
case SVM_EXIT_RDTSCP:
case SVM_EXIT_WBINVD:
_svm_default();
break;
case SVM_INVALID:
Genode::warning("invalid svm ip=", _state->ip.value());
_svm_default();
break;
case SVM_EXIT_SHUTDOWN:
Genode::error("shutdown exit");
::exit(-1);
break;
case RECALL:
recall_wait = Vcpu_handler::_recall_handler();
break;
@ -134,13 +154,17 @@ class Vcpu_handler_svm : public Vcpu_handler
{
switch (exit) {
case RECALL:
case SVM_EXIT_INVLPGA:
case SVM_EXIT_IOIO:
case SVM_EXIT_VINTR:
case SVM_EXIT_READ_CR0 ... SVM_EXIT_WRITE_CR15:
case SVM_EXIT_RDTSC:
case SVM_EXIT_RDTSCP:
case SVM_EXIT_MSR:
case SVM_NPT:
case SVM_EXIT_HLT:
case SVM_EXIT_CPUID:
case SVM_EXIT_WBINVD:
case VCPU_STARTUP:
/* todo - touch all members */
Genode::memset(&state, ~0U, sizeof(state));