mirror of
https://github.com/genodelabs/genode.git
synced 2025-01-18 10:46:25 +00:00
foc: extend vm_session impl. for vbox5
- transfer more guest registers - print warning once for unsupported guest registers - improve synchronization of vm state transfer Issue #3111
This commit is contained in:
parent
12127a7bd2
commit
64fac6cee7
@ -147,6 +147,11 @@ struct Vcpu : Genode::Thread
|
||||
TSC_OFF_LO = 0x2010,
|
||||
TSC_OFF_HI = 0x2011,
|
||||
|
||||
MSR_FMASK = 0x2842,
|
||||
MSR_LSTAR = 0x2844,
|
||||
MSR_STAR = 0x284a,
|
||||
KERNEL_GS_BASE = 0x284c,
|
||||
|
||||
CR4_VMX = 1 << 13,
|
||||
INTEL_EXIT_INVALID = 0x21,
|
||||
|
||||
@ -202,6 +207,9 @@ struct Vcpu : Genode::Thread
|
||||
addr_t _task { 0 };
|
||||
enum Virt const _vm_type;
|
||||
uint64_t _tsc_offset { 0 };
|
||||
bool _show_error_unsupported_pdpte { true };
|
||||
bool _show_error_unsupported_tpr { true };
|
||||
bool _show_error_unsupported_fpu { true };
|
||||
|
||||
enum
|
||||
{
|
||||
@ -216,8 +224,11 @@ struct Vcpu : Genode::Thread
|
||||
PAUSE = 1,
|
||||
RUN = 2,
|
||||
TERMINATE = 3,
|
||||
} _remote { NONE };
|
||||
Lock _remote_lock { Lock::UNLOCKED };
|
||||
};
|
||||
|
||||
State _state_request { NONE };
|
||||
State _state_current { NONE };
|
||||
Lock _remote_lock { Lock::UNLOCKED };
|
||||
|
||||
void entry() override
|
||||
{
|
||||
@ -227,10 +238,10 @@ struct Vcpu : Genode::Thread
|
||||
Lock::Guard guard(_remote_lock);
|
||||
|
||||
/* leave scope for Thread::join() - vCPU setup failed */
|
||||
if (_remote == TERMINATE)
|
||||
if (_state_request == TERMINATE)
|
||||
return;
|
||||
|
||||
_remote = NONE;
|
||||
_state_request = NONE;
|
||||
}
|
||||
|
||||
/* reserved ranged for state of vCPUs - see platform.cc */
|
||||
@ -306,56 +317,21 @@ struct Vcpu : Genode::Thread
|
||||
|
||||
vcpu->saved_state = L4_VCPU_F_USER_MODE | L4_VCPU_F_FPU_ENABLED;
|
||||
|
||||
State local_state { NONE };
|
||||
|
||||
while (true) {
|
||||
/* read in requested state from remote threads */
|
||||
{
|
||||
Lock::Guard guard(_remote_lock);
|
||||
local_state = _remote;
|
||||
_remote = NONE;
|
||||
|
||||
if (local_state == PAUSE) {
|
||||
while (vcpu->sticky_flags) {
|
||||
/* consume spurious notifications */
|
||||
Fiasco::l4_cap_idx_t tid = native_thread().kcap;
|
||||
Fiasco::l4_cap_idx_t irq = tid + Fiasco::TASK_VCPU_IRQ_CAP;
|
||||
l4_irq_receive(irq, L4_IPC_RECV_TIMEOUT_0);
|
||||
}
|
||||
}
|
||||
_state_current = _state_request;
|
||||
_state_request = NONE;
|
||||
}
|
||||
|
||||
if (local_state == NONE) {
|
||||
if (_state_current == NONE) {
|
||||
_wake_up.down();
|
||||
continue;
|
||||
}
|
||||
if (local_state == PAUSE) {
|
||||
|
||||
if (_vm_type == Virt::SVM)
|
||||
_write_amd_state(state, vmcb, vcpu);
|
||||
if (_vm_type == Virt::VMX)
|
||||
_write_intel_state(state, vmcs, vcpu);
|
||||
|
||||
state.exit_reason = VMEXIT_PAUSED;
|
||||
|
||||
if (_vm_type == Virt::SVM)
|
||||
_read_amd_state(state, vmcb, vcpu);
|
||||
if (_vm_type == Virt::VMX)
|
||||
_read_intel_state(state, vmcs, vcpu);
|
||||
|
||||
/* notify VM handler */
|
||||
Genode::Signal_transmitter(_signal).submit();
|
||||
|
||||
/*
|
||||
* Wait until VM handler is really really done,
|
||||
* otherwise we lose state.
|
||||
*/
|
||||
_handler_ready.down();
|
||||
continue;
|
||||
}
|
||||
|
||||
if (local_state != RUN) {
|
||||
Genode::error("unknown vcpu state ", (int)local_state);
|
||||
if (_state_current != RUN && _state_current != PAUSE) {
|
||||
Genode::error("unknown vcpu state ", (int)_state_current);
|
||||
while (true) { _remote_lock.lock(); }
|
||||
}
|
||||
|
||||
@ -379,21 +355,21 @@ struct Vcpu : Genode::Thread
|
||||
if (reason == 0x400) /* no NPT support */
|
||||
reason = 0xfc;
|
||||
|
||||
/* remotely PAUSE was called */
|
||||
if (l4_error(tag) && reason == 0x60) {
|
||||
reason = VMEXIT_PAUSED;
|
||||
|
||||
{
|
||||
Lock::Guard guard(_remote_lock);
|
||||
if (_remote == PAUSE) {
|
||||
_remote = NONE;
|
||||
_wake_up.down();
|
||||
}
|
||||
_state_request = NONE;
|
||||
_state_current = PAUSE;
|
||||
|
||||
/* consume notification */
|
||||
while (vcpu->sticky_flags) {
|
||||
Fiasco::l4_cap_idx_t tid = native_thread().kcap;
|
||||
Fiasco::l4_cap_idx_t irq = tid + Fiasco::TASK_VCPU_IRQ_CAP;
|
||||
l4_irq_receive(irq, L4_IPC_RECV_TIMEOUT_0);
|
||||
/* remotely PAUSE was called */
|
||||
if (l4_error(tag) && reason == 0x60) {
|
||||
reason = VMEXIT_PAUSED;
|
||||
|
||||
/* consume notification */
|
||||
while (vcpu->sticky_flags) {
|
||||
Fiasco::l4_cap_idx_t tid = native_thread().kcap;
|
||||
Fiasco::l4_cap_idx_t irq = tid + Fiasco::TASK_VCPU_IRQ_CAP;
|
||||
l4_irq_receive(irq, L4_IPC_RECV_TIMEOUT_0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -404,21 +380,21 @@ struct Vcpu : Genode::Thread
|
||||
if (_vm_type == Virt::VMX) {
|
||||
reason = Fiasco::l4_vm_vmx_read_32(vmcs, Vmcs::EXI_REASON);
|
||||
|
||||
/* remotely PAUSE was called */
|
||||
if (l4_error(tag) && reason == 0x1) {
|
||||
reason = VMEXIT_PAUSED;
|
||||
|
||||
{
|
||||
Lock::Guard guard(_remote_lock);
|
||||
if (_remote == PAUSE) {
|
||||
_remote = NONE;
|
||||
_wake_up.down();
|
||||
}
|
||||
_state_request = NONE;
|
||||
_state_current = PAUSE;
|
||||
|
||||
/* consume notification */
|
||||
while (vcpu->sticky_flags) {
|
||||
Fiasco::l4_cap_idx_t tid = native_thread().kcap;
|
||||
Fiasco::l4_cap_idx_t irq = tid + Fiasco::TASK_VCPU_IRQ_CAP;
|
||||
l4_irq_receive(irq, L4_IPC_RECV_TIMEOUT_0);
|
||||
/* remotely PAUSE was called */
|
||||
if (l4_error(tag) && reason == 0x1) {
|
||||
reason = VMEXIT_PAUSED;
|
||||
|
||||
/* consume notification */
|
||||
while (vcpu->sticky_flags) {
|
||||
Fiasco::l4_cap_idx_t tid = native_thread().kcap;
|
||||
Fiasco::l4_cap_idx_t irq = tid + Fiasco::TASK_VCPU_IRQ_CAP;
|
||||
l4_irq_receive(irq, L4_IPC_RECV_TIMEOUT_0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -615,11 +591,14 @@ struct Vcpu : Genode::Thread
|
||||
|
||||
state.efer.value(l4_vm_vmx_read(vmcs, Vmcs::EFER));
|
||||
|
||||
state.star.value(l4_vm_vmx_read(vmcs, Vmcs::MSR_STAR));
|
||||
state.lstar.value(l4_vm_vmx_read(vmcs, Vmcs::MSR_LSTAR));
|
||||
state.fmask.value(l4_vm_vmx_read(vmcs, Vmcs::MSR_FMASK));
|
||||
state.kernel_gs_base.value(l4_vm_vmx_read(vmcs, Vmcs::KERNEL_GS_BASE));
|
||||
|
||||
/* XXX missing */
|
||||
#if 0
|
||||
if (state.pdpte_0_updated() || state.pdpte_1_updated() ||
|
||||
if (state.star_updated() || state.lstar_updated() ||
|
||||
state.fmask_updated() || state.kernel_gs_base_updated()) {
|
||||
if (state.tpr_updated() || state.tpr_threshold_updated()) {
|
||||
#endif
|
||||
}
|
||||
@ -807,12 +786,24 @@ struct Vcpu : Genode::Thread
|
||||
l4_vm_vmx_write(vmcs, Vmcs::TSC_OFF_HI, (_tsc_offset >> 32) & 0xffffffffu);
|
||||
}
|
||||
|
||||
if (state.star.valid() || state.lstar.valid() ||
|
||||
state.fmask.valid() || state.kernel_gs_base.valid())
|
||||
Genode::error(__LINE__, " not implemented");
|
||||
if (state.star.valid())
|
||||
l4_vm_vmx_write(vmcs, Vmcs::MSR_STAR, state.star.value());
|
||||
|
||||
if (state.tpr.valid() || state.tpr_threshold.valid())
|
||||
Genode::error(__LINE__, " not implemented");
|
||||
if (state.lstar.valid())
|
||||
l4_vm_vmx_write(vmcs, Vmcs::MSR_LSTAR, state.lstar.value());
|
||||
|
||||
if (state.fmask.valid())
|
||||
l4_vm_vmx_write(vmcs, Vmcs::MSR_FMASK, state.fmask.value());
|
||||
|
||||
if (state.kernel_gs_base.valid())
|
||||
l4_vm_vmx_write(vmcs, Vmcs::KERNEL_GS_BASE, state.kernel_gs_base.value());
|
||||
|
||||
if (state.tpr.valid() || state.tpr_threshold.valid()) {
|
||||
if (_show_error_unsupported_tpr) {
|
||||
_show_error_unsupported_tpr = false;
|
||||
Genode::error("TPR & TPR_THRESHOLD not supported on Fiasco.OC");
|
||||
}
|
||||
}
|
||||
|
||||
if (state.dr7.valid())
|
||||
l4_vm_vmx_write(vmcs, Vmcs::DR7, state.dr7.value());
|
||||
@ -958,14 +949,14 @@ struct Vcpu : Genode::Thread
|
||||
l4_vm_vmx_write(vmcs, Vmcs::GDTR_LIMIT, state.gdtr.value().limit);
|
||||
}
|
||||
|
||||
if (state.pdpte_0.valid())
|
||||
Genode::error(__LINE__, " not implemented");
|
||||
if (state.pdpte_1.valid())
|
||||
Genode::error(__LINE__, " not implemented");
|
||||
if (state.pdpte_2.valid())
|
||||
Genode::error(__LINE__, " not implemented");
|
||||
if (state.pdpte_3.valid())
|
||||
Genode::error(__LINE__, " not implemented");
|
||||
if (state.pdpte_0.valid() || state.pdpte_1.valid() ||
|
||||
state.pdpte_2.valid() || state.pdpte_3.valid())
|
||||
{
|
||||
if (_show_error_unsupported_pdpte) {
|
||||
_show_error_unsupported_pdpte = false;
|
||||
Genode::error("PDPTE 0/1/2/3 not supported on Fiasco.OC");
|
||||
}
|
||||
}
|
||||
|
||||
if (state.sysenter_cs.valid())
|
||||
l4_vm_vmx_write(vmcs, Vmcs::SYSENTER_CS,
|
||||
@ -976,6 +967,13 @@ struct Vcpu : Genode::Thread
|
||||
if (state.sysenter_ip.valid())
|
||||
l4_vm_vmx_write(vmcs, Vmcs::SYSENTER_IP,
|
||||
state.sysenter_ip.value());
|
||||
|
||||
if (state.fpu.valid()) {
|
||||
if (_show_error_unsupported_fpu) {
|
||||
_show_error_unsupported_fpu = false;
|
||||
Genode::error("FPU guest state not supported on Fiasco.OC");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void _write_amd_state(Vm_state &state, Fiasco::l4_vm_svm_vmcb_t *vmcb,
|
||||
@ -1021,8 +1019,12 @@ struct Vcpu : Genode::Thread
|
||||
state.fmask.value() || state.kernel_gs_base.value())
|
||||
Genode::error(__LINE__, " not implemented");
|
||||
|
||||
if (state.tpr.valid() || state.tpr_threshold.valid())
|
||||
Genode::error(__LINE__, " not implemented");
|
||||
if (state.tpr.valid() || state.tpr_threshold.valid()) {
|
||||
if (_show_error_unsupported_tpr) {
|
||||
_show_error_unsupported_tpr = false;
|
||||
Genode::error("TPR & TPR_THRESHOLD not supported on Fiasco.OC");
|
||||
}
|
||||
}
|
||||
|
||||
if (state.dr7.valid())
|
||||
vmcb->state_save_area.dr7 = state.dr7.value();
|
||||
@ -1155,14 +1157,14 @@ struct Vcpu : Genode::Thread
|
||||
vmcb->state_save_area.gdtr.limit = state.gdtr.value().limit;
|
||||
}
|
||||
|
||||
if (state.pdpte_0.valid())
|
||||
Genode::error(__LINE__, " not implemented");
|
||||
if (state.pdpte_1.valid())
|
||||
Genode::error(__LINE__, " not implemented");
|
||||
if (state.pdpte_2.valid())
|
||||
Genode::error(__LINE__, " not implemented");
|
||||
if (state.pdpte_3.valid())
|
||||
Genode::error(__LINE__, " not implemented");
|
||||
if (state.pdpte_0.valid() || state.pdpte_1.valid() ||
|
||||
state.pdpte_2.valid() || state.pdpte_3.valid())
|
||||
{
|
||||
if (_show_error_unsupported_pdpte) {
|
||||
_show_error_unsupported_pdpte = false;
|
||||
Genode::error("PDPTE 0/1/2/3 not supported on Fiasco.OC");
|
||||
}
|
||||
}
|
||||
|
||||
if (state.sysenter_cs.valid())
|
||||
vmcb->state_save_area.sysenter_cs = state.sysenter_cs.value();
|
||||
@ -1170,6 +1172,13 @@ struct Vcpu : Genode::Thread
|
||||
vmcb->state_save_area.sysenter_esp = state.sysenter_sp.value();
|
||||
if (state.sysenter_ip.valid())
|
||||
vmcb->state_save_area.sysenter_eip = state.sysenter_ip.value();
|
||||
|
||||
if (state.fpu.valid()) {
|
||||
if (_show_error_unsupported_fpu) {
|
||||
_show_error_unsupported_fpu = false;
|
||||
Genode::error("FPU guest state not supported on Fiasco.OC");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
@ -1197,34 +1206,40 @@ struct Vcpu : Genode::Thread
|
||||
*reinterpret_cast<Fiasco::l4_cap_idx_t *>(_state) = 0UL;
|
||||
}
|
||||
|
||||
void resume() {
|
||||
void resume()
|
||||
{
|
||||
Lock::Guard guard(_remote_lock);
|
||||
|
||||
if (_remote == RUN || _remote == PAUSE)
|
||||
if (_state_request == RUN || _state_request == PAUSE)
|
||||
return;
|
||||
|
||||
_remote = RUN;
|
||||
_wake_up.up();
|
||||
_state_request = RUN;
|
||||
|
||||
if (_state_current == NONE)
|
||||
_wake_up.up();
|
||||
}
|
||||
|
||||
void pause() {
|
||||
void pause()
|
||||
{
|
||||
Lock::Guard guard(_remote_lock);
|
||||
|
||||
if (_remote == PAUSE)
|
||||
if (_state_request == PAUSE)
|
||||
return;
|
||||
|
||||
_remote = PAUSE;
|
||||
_state_request = PAUSE;
|
||||
|
||||
/* recall vCPU */
|
||||
Fiasco::l4_cap_idx_t tid = native_thread().kcap;
|
||||
Fiasco::l4_cap_idx_t irq = tid + Fiasco::TASK_VCPU_IRQ_CAP;
|
||||
Fiasco::l4_irq_trigger(irq);
|
||||
|
||||
_wake_up.up();
|
||||
if (_state_current == NONE)
|
||||
_wake_up.up();
|
||||
}
|
||||
|
||||
void terminate() {
|
||||
_remote = TERMINATE;
|
||||
void terminate()
|
||||
{
|
||||
_state_request = TERMINATE;
|
||||
_wake_up.up();
|
||||
}
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user