vbox5: remove VM generic version

Issue #4968
This commit is contained in:
Alexander Boettcher 2023-09-14 15:44:39 +02:00 committed by Christian Helmuth
parent 17a140db3d
commit 484bde4b4b
34 changed files with 7 additions and 3505 deletions

View File

@ -1,20 +0,0 @@
include $(REP_DIR)/lib/mk/virtualbox5-common.inc
LIBS += stdcxx
SRC_CC = sup.cc sup_vmm.cc
INC_DIR += $(call select_from_repositories,src/lib/libc)
INC_DIR += $(VIRTUALBOX_DIR)/VBoxAPIWrap
INC_DIR += $(VBOX_DIR)/Main/xml
INC_DIR += $(VBOX_DIR)/Main/include
INC_DIR += $(VBOX_DIR)/VMM/include
INC_DIR += $(REP_DIR)/src/virtualbox5
INC_DIR += $(REP_DIR)/src/virtualbox5/frontend
vpath sup_vmm.cc $(REP_DIR)/src/virtualbox5/generic
vpath sup.cc $(REP_DIR)/src/virtualbox5/generic
CC_CXX_WARN_STRICT =

View File

@ -1,2 +0,0 @@
VirtualBox runtime for hosting a large VM in the Sculpt scenario

View File

@ -1,10 +0,0 @@
_/src/vbox5
_/src/libc
_/src/init
_/src/posix
_/src/zlib
_/src/libiconv
_/src/libyuv
_/src/stdcxx
_/src/vfs
_/src/jpeg

View File

@ -1 +0,0 @@
2023-08-21 464b0638d93864d8748bfa61e6472f21d6f26788

View File

@ -1,90 +0,0 @@
<runtime ram="4300M" caps="2500" binary="init">
<requires>
<file_system label="vm"/>
<file_system label="shared"/>
<vm/>
<timer/>
<gui/>
<nic/>
<rom label="capslock"/>
<rom label="platform_info"/>
<report label="shape"/>
<report label="clipboard"/>
<rom label="clipboard"/>
<rm/>
<rtc/>
<rom label="usb_devices"/>
<usb/>
</requires>
<config verbose="yes">
<parent-provides>
<service name="ROM"/>
<service name="PD"/>
<service name="RM"/>
<service name="CPU"/>
<service name="LOG"/>
<service name="VM"/>
<service name="Gui"/>
<service name="Timer"/>
<service name="Rtc"/>
<service name="Report"/>
<service name="File_system"/>
<service name="Usb"/>
<service name="Nic"/>
</parent-provides>
<default-route> <any-service> <parent/> <any-child/> </any-service> </default-route>
<default caps="100"/>
<start name="vbox" caps="2000">
<binary name="virtualbox5" />
<resource name="RAM" quantum="8G"/>
<exit propagate="yes"/>
<config vbox_file="machine.vbox" xhci="yes" vm_name="linux" capslock="ROM">
<vfs>
<dir name="dev">
<log/>
<rtc/>
</dir>
<dir name="shared"> <fs label="shared" writeable="yes"/> </dir>
<fs writeable="yes"/>
</vfs>
<libc stdout="/dev/log" stderr="/dev/log" rtc="/dev/rtc"/>
</config>
<route>
<service name="Audio_out"> <parent/> </service>
<service name="File_system" label="shared"> <parent label="shared"/> </service>
<service name="File_system"> <parent label="vm"/> </service>
<service name="ROM" label="usb_devices"> <parent label="usb_devices"/> </service>
<service name="ROM" label="capslock"> <parent label="capslock"/> </service>
<service name="ROM" label="platform_info">
<parent label="platform_info"/> </service>
<service name="Nic"> <parent/> </service>
<service name="Report" label="shape"> <parent label="shape"/> </service>
<service name="ROM" label="clipboard"> <parent label="clipboard"/> </service>
<service name="Report" label="clipboard"> <parent label="clipboard"/> </service>
<service name="Gui"> <parent label=""/> </service>
<any-service> <parent/> </any-service>
</route>
</start>
</config>
<content>
<rom label="ld.lib.so"/>
<rom label="init"/>
<rom label="virtualbox5"/>
<rom label="libc.lib.so"/>
<rom label="libm.lib.so"/>
<rom label="libiconv.lib.so"/>
<rom label="libyuv.lib.so"/>
<rom label="qemu-usb.lib.so"/>
<rom label="stdcxx.lib.so"/>
<rom label="vfs.lib.so"/>
<rom label="jpeg.lib.so"/>
</content>
</runtime>

View File

@ -12,11 +12,8 @@ content: $(MIRROR_FROM_REP_DIR)
$(MIRROR_FROM_REP_DIR):
$(mirror_from_rep_dir)
# omit virtualbox5-rem binary (12 MiB) from binary archive
content: disable_virtualbox_rem disable_assertions
disable_virtualbox_rem: $(MIRROR_FROM_REP_DIR)
rm src/virtualbox5/target.mk
# disable debug assertions
content: disable_assertions
disable_assertions: $(MIRROR_FROM_REP_DIR)
rm lib/mk/virtualbox5-debug.inc

View File

@ -1,84 +0,0 @@
LIB_MK_FILES := $(notdir $(wildcard $(REP_DIR)/lib/mk/virtualbox5*))
MIRROR_FROM_REP_DIR := src/virtualbox5 \
src/virtualbox5/network.cpp \
src/virtualbox5/include \
include/vmm \
$(addprefix lib/mk/,$(LIB_MK_FILES))
content: $(MIRROR_FROM_REP_DIR)
$(MIRROR_FROM_REP_DIR):
$(mirror_from_rep_dir)
# omit virtualbox5-rem binary (12 MiB) from binary archive
content: disable_virtualbox_nova disable_assertions
disable_virtualbox_nova: $(MIRROR_FROM_REP_DIR)
rm src/virtualbox5/nova/target.mk
rmdir src/virtualbox5/nova
rm -r src/virtualbox5/spec
disable_assertions: $(MIRROR_FROM_REP_DIR)
rm lib/mk/virtualbox5-debug.inc
touch lib/mk/virtualbox5-debug.inc
PORT_DIR := $(call port_dir,$(REP_DIR)/ports/virtualbox5)
MIRROR_FROM_PORT_DIR := src/app/virtualbox src/app/virtualbox_sdk \
VBoxAPIWrap VirtualBox_stripped.xidl
content: $(MIRROR_FROM_PORT_DIR)
$(MIRROR_FROM_PORT_DIR):
mkdir -p $(dir $@)
cp -r $(PORT_DIR)/$@ $(dir $@)
MIRROR_FROM_LIBPORTS := lib/mk/libc-mem.mk \
lib/mk/libc-common.inc \
src/lib/libc/internal/init.h \
src/lib/libc/internal/mem_alloc.h \
src/lib/libc/internal/monitor.h \
src/lib/libc/internal/pthread.h \
src/lib/libc/internal/thread_create.h \
src/lib/libc/internal/timer.h \
src/lib/libc/internal/types.h \
src/lib/libc/libc_mem_alloc.cc \
lib/import/import-qemu-usb_include.mk \
lib/mk/qemu-usb_include.mk \
lib/mk/qemu-usb.inc \
lib/mk/spec/x86_32/qemu-usb.mk \
lib/mk/spec/x86_64/qemu-usb.mk \
include/qemu \
src/lib/qemu-usb \
content: $(MIRROR_FROM_LIBPORTS)
$(MIRROR_FROM_LIBPORTS):
mkdir -p $(dir $@)
cp -r $(GENODE_DIR)/repos/libports/$@ $(dir $@)
QEMU_USB_PORT_DIR := $(call port_dir,$(GENODE_DIR)/repos/libports/ports/qemu-usb)
MIRROR_FROM_QEMU_USB_PORT_DIR := src/lib/qemu
content: $(MIRROR_FROM_QEMU_USB_PORT_DIR)
$(MIRROR_FROM_QEMU_USB_PORT_DIR):
mkdir -p $(dir $@)
cp -r $(QEMU_USB_PORT_DIR)/$@ $(dir $@)
MIRROR_FROM_OS := src/drivers/ps2/scan_code_set_1.h \
include/pointer/shape_report.h \
content: $(MIRROR_FROM_OS)
$(MIRROR_FROM_OS):
mkdir -p $(dir $@)
cp -r $(GENODE_DIR)/repos/os/$@ $(dir $@)
content: LICENSE
LICENSE:
echo "GNU GPL version 2, see src/app/virtualbox/COPYING" > $@

View File

@ -1 +0,0 @@
2023-08-21 8bc399184344e122bbf80d7130e42fe63f91343c

View File

@ -1,23 +0,0 @@
audio_in_session
audio_out_session
base
capture_session
framebuffer_session
input_session
libc
libiconv
nic_session
gui_session
os
report_session
rtc_session
stdcxx
terminal_session
timer_session
usb_session
vfs
vm_session
nitpicker_gfx
blit
libyuv
format

View File

@ -25,7 +25,4 @@ set use_ps2 1
set use_vms 1
set use_cpu_load 1
# use non-generic vbox5 VMM version
set use_vbox5_nova 1
source ${genode_dir}/repos/ports/run/vbox_win.inc

View File

@ -25,7 +25,4 @@ set use_ps2 1
set use_vms 1
set use_cpu_load 1
# use non-generic vbox5 VMM version
set use_vbox5_nova 1
source ${genode_dir}/repos/ports/run/vbox_win.inc

View File

@ -1,35 +0,0 @@
#
# Ubuntu 16.04 32bit in VBox 5
#
assert_spec x86
if {(![have_spec nova] && ![have_spec foc])} {
puts "Platform is unsupported."
}
set flavor "ubuntu_16_04_32"
set vm_ram "1280M"
set use_vbox5 1
set use_rumpfs 1
# Write overlay only into ram
set use_ram_fs 1
# However read initial overlay from disk
set use_overlay_from_disk 1
set use_serial 1
set use_check_result 1
set use_usb [expr ![get_cmd_switch --autopilot]]
set use_ps2 1
set use_vms 1
set use_cpu_load 1
# use generic vbox5 VMM version
set use_vbox5_nova 0
source ${genode_dir}/repos/ports/run/vbox_win.inc

View File

@ -1,31 +0,0 @@
#
# Ubuntu 16.04 64bit in VBox 5
#
assert_spec x86_64
assert_spec nova
set flavor "ubuntu_16_04_64"
set vm_ram "9460M"
set use_vbox5 1
set use_rumpfs 1
# Write overlay only into ram
set use_ram_fs 1
# However read initial overlay from disk
set use_overlay_from_disk 1
set use_serial 1
set use_check_result 1
set use_usb [expr ![get_cmd_switch --autopilot]]
set use_ps2 1
set use_vms 1
set use_cpu_load 1
# use generic vbox5 VMM version
set use_vbox5_nova 0
source ${genode_dir}/repos/ports/run/vbox_win.inc

View File

@ -1,31 +0,0 @@
#
# Windows 10 in VirtualBox 5
#
assert_spec nova
assert_spec x86_64
set flavor "win10_64_1vcpu"
set vm_ram "8280M"
set use_vbox5 1
set use_rumpfs 1
# Write overlay only into ram
set use_ram_fs 1
# However read initial overlay from disk
set use_overlay_from_disk 1
set use_serial 0
set use_check_result 1
set use_usb [expr ![get_cmd_switch --autopilot]]
set use_ps2 1
set use_vms 1
set use_cpu_load 0
# use generic vbox5 VMM version
set use_vbox5_nova 0
source ${genode_dir}/repos/ports/run/vbox_win.inc

View File

@ -1,31 +0,0 @@
#
# Windows 7 in VirtualBox 5
#
assert_spec x86
assert_spec nova
set flavor "win7"
set vm_ram "1280M"
set use_vbox5 1
set use_rumpfs 1
# Write overlay only into ram
set use_ram_fs 1
# However read initial overlay from disk
set use_overlay_from_disk 1
set use_serial 0
set use_check_result 1
set use_usb [expr ![get_cmd_switch --autopilot]]
set use_ps2 1
set use_vms 1
set use_cpu_load 0
# use generic vbox5 VMM version
set use_vbox5_nova 0
source ${genode_dir}/repos/ports/run/vbox_win.inc

View File

@ -1,31 +0,0 @@
#
# Windows 7 64bit in VirtualBox
#
assert_spec x86_64
assert_spec nova
set flavor "win7_64_1vcpu"
set vm_ram "9480M"
set use_vbox5 1
set use_rumpfs 1
# Write overlay only into ram
set use_ram_fs 1
# However read initial overlay from disk
set use_overlay_from_disk 1
set use_serial 0
set use_check_result 1
set use_usb [expr ![get_cmd_switch --autopilot]]
set use_ps2 1
set use_vms 1
set use_cpu_load 0
# use generic vbox5 VMM version
set use_vbox5_nova 0
source ${genode_dir}/repos/ports/run/vbox_win.inc

View File

@ -25,9 +25,6 @@ set use_ps2 1
set use_vms 1
set use_cpu_load 0
# use non-generic vbox5 VMM version
set use_vbox5_nova 1
set use_webcam 1
source ${genode_dir}/repos/ports/run/vbox_win.inc

View File

@ -25,7 +25,4 @@ set use_ps2 1
set use_vms 1
set use_cpu_load 0
# use non-generic vbox5 VMM version
set use_vbox5_nova 1
source ${genode_dir}/repos/ports/run/vbox_win.inc

View File

@ -25,7 +25,4 @@ set use_ps2 1
set use_vms 1
set use_cpu_load 0
# use non-generic vbox5 VMM version
set use_vbox5_nova 1
source ${genode_dir}/repos/ports/run/vbox_win.inc

View File

@ -37,7 +37,4 @@ set use_vms 6
set affinity_space_width 8
set use_cpu_load 0
# use non-generic vbox5 VMM version
set use_vbox5_nova 1
source ${genode_dir}/repos/ports/run/vbox_win.inc

View File

@ -24,7 +24,4 @@ set use_ps2 1
set use_vms 1
set use_cpu_load 0
# use non-generic vbox5 VMM version
set use_vbox5_nova 1
source ${genode_dir}/repos/ports/run/vbox_win.inc

View File

@ -53,8 +53,7 @@ set boot_modules {
dynamic_rom
}
set virtualbox5_binary "virtualbox5"
if {$use_vbox5_nova} { set virtualbox5_binary "virtualbox5-nova" }
set virtualbox5_binary "virtualbox5-nova"
set config_of_app {
@ -83,7 +82,7 @@ set config_of_app {
Note: to get network access in the VM, the virtual network adapter
needs to be enabled in the .vbox file (disabled by default)
-->
<start name="nic_drv" priority="-1">
<start name="nic_drv" caps="150" priority="-1">
<binary name="pc_nic_drv"/>
<resource name="RAM" quantum="8M" />
<route>

View File

@ -1,10 +1,10 @@
assert_spec nova
set use_net 0
set use_usb_qemu 0
set use_serial 1
set use_top 1
set use_vbox5_nova 0
# use_gui starts two VMs
set use_gui 0
@ -15,11 +15,7 @@ set build_components {
append build_components virtualbox5
set virtualbox_binary "virtualbox5"
if {$use_vbox5_nova} {
set virtualbox_binary "virtualbox5-nova"
}
create_boot_directory

View File

@ -31,27 +31,6 @@ set match_guest_log "\[init -\> log_terminal\]"
set match_boot_string "\[init -\> vbox.*\].*Using VMX virtualization extension"
#set match_guest_down
# use generic vbox5 VMM version
set use_vbox5_nova 0
set vmm_name "vbox5_gen"
set use_vcpus 1
lappend results_expected 1 3 23 79
lappend boottime_expected 54
source ${genode_dir}/repos/ports/run/vbox_win.inc
source ${genode_dir}/repos/ports/run/vmm_vm_stress.inc
kill_spawned [output_spawn_id]
# set use_vcpus 2
# lappend results_expected 2 10 42 50
# lappend boottime_expected 21
# source ${genode_dir}/repos/ports/run/vbox_win.inc
# source ${genode_dir}/repos/ports/run/vmm_vm_stress.inc
# kill_spawned [output_spawn_id]
if {[have_spec nova]} {
# use non-generic vbox5 VMM version
set use_vbox5_nova 1
set vmm_name "vbox5_nova"
set use_vcpus 1
@ -81,7 +60,6 @@ if {[have_spec nova]} {
source ${genode_dir}/repos/ports/run/vbox_win.inc
source ${genode_dir}/repos/ports/run/vmm_vm_stress.inc
kill_spawned [output_spawn_id]
}
#
# Dump aggregated output of the several runs above

View File

@ -31,27 +31,6 @@ set match_guest_log "\[init -\> log_terminal\]"
set match_boot_string "\[init -\> vbox.*\].*Using VMX virtualization extension"
#set match_guest_down
# use generic vbox5 VMM version
set use_vbox5_nova 0
set vmm_name "vbox5_gen"
set use_vcpus 1
lappend results_expected 1 2 25 78
lappend boottime_expected 24
source ${genode_dir}/repos/ports/run/vbox_win.inc
source ${genode_dir}/repos/ports/run/vmm_vm_stress.inc
kill_spawned [output_spawn_id]
# set use_vcpus 2
# lappend results_expected 0 0 0 0
# lappend boottime_expected 35
# source ${genode_dir}/repos/ports/run/vbox_win.inc
# source ${genode_dir}/repos/ports/run/vmm_vm_stress.inc
# kill_spawned [output_spawn_id]
if {[have_spec nova]} {
# use non-generic vbox5 VMM version
set use_vbox5_nova 1
set vmm_name "vbox5_nova"
set use_vcpus 1
@ -81,7 +60,6 @@ if {[have_spec nova]} {
source ${genode_dir}/repos/ports/run/vbox_win.inc
source ${genode_dir}/repos/ports/run/vmm_vm_stress.inc
kill_spawned [output_spawn_id]
}
#
# Dump aggregated output of the several runs above

View File

@ -1,227 +0,0 @@
/*
* \brief VirtualBox SUPLib supplements
* \author Norman Feske
* \date 2013-08-20
*/
/*
* Copyright (C) 2013-2017 Genode Labs GmbH
*
* This file is distributed under the terms of the GNU General Public License
* version 2.
*/
/* Genode includes */
#include <base/attached_ram_dataspace.h>
#include <trace/timestamp.h>
/* Genode/Virtualbox includes */
#include "sup.h"
#include "vmm.h"
/* VirtualBox includes */
#include <iprt/ldr.h>
#include <iprt/semaphore.h>
#include <VBox/err.h>
SUPR3DECL(SUPPAGINGMODE) SUPR3GetPagingMode(void)
{
return sizeof(void *) == 4 ? SUPPAGINGMODE_32_BIT : SUPPAGINGMODE_AMD64_NX;
}
int SUPR3Term(bool) { return VINF_SUCCESS; }
int SUPR3HardenedLdrLoadAppPriv(const char *pszFilename, PRTLDRMOD phLdrMod,
uint32_t fFlags, PRTERRINFO pErrInfo)
{
return RTLdrLoad(pszFilename, phLdrMod);
}
SUPR3DECL(int) SUPR3PageFreeEx(void *pvPages, size_t cPages)
{
Genode::log(__func__, " pvPages=", pvPages, " pages=", cPages);
return VINF_SUCCESS;
}
int SUPR3QueryMicrocodeRev(uint32_t *puMicrocodeRev)
{
return E_FAIL;
}
uint32_t SUPSemEventMultiGetResolution(PSUPDRVSESSION)
{
return 100000*10; /* called by 'vmR3HaltGlobal1Init' */
}
int SUPSemEventCreate(PSUPDRVSESSION pSession, PSUPSEMEVENT phEvent)
{
return RTSemEventCreate((PRTSEMEVENT)phEvent);
}
int SUPSemEventClose(PSUPDRVSESSION pSession, SUPSEMEVENT hEvent)
{
Assert (hEvent);
return RTSemEventDestroy((RTSEMEVENT)hEvent);
}
int SUPSemEventSignal(PSUPDRVSESSION pSession, SUPSEMEVENT hEvent)
{
Assert (hEvent);
return RTSemEventSignal((RTSEMEVENT)hEvent);
}
int SUPSemEventWaitNoResume(PSUPDRVSESSION pSession, SUPSEMEVENT hEvent,
uint32_t cMillies)
{
Assert (hEvent);
return RTSemEventWaitNoResume((RTSEMEVENT)hEvent, cMillies);
}
int SUPSemEventMultiCreate(PSUPDRVSESSION, PSUPSEMEVENTMULTI phEventMulti)
{
RTSEMEVENTMULTI sem;
/*
* Input validation.
*/
AssertPtrReturn(phEventMulti, VERR_INVALID_POINTER);
/*
* Create the event semaphore object.
*/
int rc = RTSemEventMultiCreate(&sem);
static_assert(sizeof(sem) == sizeof(*phEventMulti), "oi");
*phEventMulti = reinterpret_cast<SUPSEMEVENTMULTI>(sem);
return rc;
}
int SUPSemEventMultiWaitNoResume(PSUPDRVSESSION, SUPSEMEVENTMULTI event,
uint32_t ms)
{
RTSEMEVENTMULTI const rtevent = reinterpret_cast<RTSEMEVENTMULTI>(event);
return RTSemEventMultiWait(rtevent, ms);
}
int SUPSemEventMultiSignal(PSUPDRVSESSION, SUPSEMEVENTMULTI event) {
return RTSemEventMultiSignal(reinterpret_cast<RTSEMEVENTMULTI>(event)); }
int SUPSemEventMultiReset(PSUPDRVSESSION, SUPSEMEVENTMULTI event) {
return RTSemEventMultiReset(reinterpret_cast<RTSEMEVENTMULTI>(event)); }
int SUPSemEventMultiClose(PSUPDRVSESSION, SUPSEMEVENTMULTI event) {
return RTSemEventMultiDestroy(reinterpret_cast<RTSEMEVENTMULTI>(event)); }
int SUPR3CallVMMR0(PVMR0 pVMR0, VMCPUID idCpu, unsigned uOperation,
void *pvArg)
{
if (uOperation == VMMR0_DO_CALL_HYPERVISOR) {
Genode::log(__func__, ": VMMR0_DO_CALL_HYPERVISOR - doing nothing");
return VINF_SUCCESS;
}
if (uOperation == VMMR0_DO_VMMR0_TERM) {
Genode::log(__func__, ": VMMR0_DO_VMMR0_TERM - doing nothing");
return VINF_SUCCESS;
}
if (uOperation == VMMR0_DO_GVMM_DESTROY_VM) {
Genode::log(__func__, ": VMMR0_DO_GVMM_DESTROY_VM - doing nothing");
return VINF_SUCCESS;
}
AssertMsg(uOperation != VMMR0_DO_VMMR0_TERM &&
uOperation != VMMR0_DO_CALL_HYPERVISOR &&
uOperation != VMMR0_DO_GVMM_DESTROY_VM,
("SUPR3CallVMMR0: unhandled uOperation %d", uOperation));
return VERR_GENERAL_FAILURE;
}
void genode_VMMR0_DO_GVMM_CREATE_VM(PSUPVMMR0REQHDR pReqHdr)
{
GVMMCREATEVMREQ &req = reinterpret_cast<GVMMCREATEVMREQ &>(*pReqHdr);
size_t const cCpus = req.cCpus;
/*
* Allocate and initialize VM struct
*
* The VM struct is followed by the variable-sizedA array of VMCPU
* objects. 'RT_UOFFSETOF' is used to determine the size including
* the VMCPU array.
*
* VM struct must be page-aligned, which is checked at least in
* PDMR3CritSectGetNop().
*/
size_t const cbVM = RT_UOFFSETOF(VM, aCpus[cCpus]);
static Genode::Attached_ram_dataspace vm(genode_env().ram(),
genode_env().rm(),
cbVM);
Assert (vm.size() >= cbVM);
VM *pVM = vm.local_addr<VM>();
Genode::memset(pVM, 0, cbVM);
/*
* On Genode, VMMR0 and VMMR3 share a single address space. Hence, the
* same pVM pointer is valid as pVMR0 and pVMR3.
*/
pVM->enmVMState = VMSTATE_CREATING;
pVM->pVMR0 = (RTHCUINTPTR)pVM;
pVM->pVMRC = (RTGCUINTPTR)pVM;
pVM->pSession = req.pSession;
pVM->cbSelf = cbVM;
pVM->cCpus = cCpus;
pVM->uCpuExecutionCap = 100; /* expected by 'vmR3CreateU()' */
pVM->offVMCPU = RT_UOFFSETOF(VM, aCpus);
for (uint32_t i = 0; i < cCpus; i++) {
pVM->aCpus[i].pVMR0 = pVM->pVMR0;
pVM->aCpus[i].pVMR3 = pVM;
pVM->aCpus[i].idHostCpu = NIL_RTCPUID;
pVM->aCpus[i].hNativeThreadR0 = NIL_RTNATIVETHREAD;
}
pVM->aCpus[0].hNativeThreadR0 = RTThreadNativeSelf();
/* out parameters of the request */
req.pVMR0 = pVM->pVMR0;
req.pVMR3 = pVM;
}
void genode_VMMR0_DO_GVMM_REGISTER_VMCPU(PVMR0 pVMR0, VMCPUID idCpu)
{
PVM pVM = reinterpret_cast<PVM>(pVMR0);
pVM->aCpus[idCpu].hNativeThreadR0 = RTThreadNativeSelf();
}
HRESULT genode_check_memory_config(ComObjPtr<Machine>,
size_t const memory_vmm)
{
/* Request max available memory */
size_t const memory_available = genode_env().pd().avail_ram().value;
if (memory_vmm <= memory_available)
return S_OK;
Genode::error("Available memory too low to start the VM - available: ",
memory_available, " MB < ", memory_vmm, " MB requested");
return E_FAIL;
}

File diff suppressed because it is too large Load Diff

View File

@ -1,110 +0,0 @@
/*
* \brief Genode specific VirtualBox SUPLib supplements
* \author Norman Feske
* \author Alexander Boettcher
* \author Christian Helmuth
*/
/*
* Copyright (C) 2013-2021 Genode Labs GmbH
*
* This file is distributed under the terms of the GNU General Public License
* version 2.
*/
#ifndef _VIRTUALBOX__SVM_H_
#define _VIRTUALBOX__SVM_H_
/* based on HWSVMR0.h - adjusted to Genode */
#define GENODE_SVM_ASSERT_SELREG(REG) \
AssertMsg(!pCtx->REG.Attr.n.u1Present || \
(pCtx->REG.Attr.n.u1Granularity \
? (pCtx->REG.u32Limit & 0xfffU) == 0xfffU \
: pCtx->REG.u32Limit <= 0xfffffU), \
("%u %u %#x %#x %#llx\n", pCtx->REG.Attr.n.u1Present, \
pCtx->REG.Attr.n.u1Granularity, pCtx->REG.u32Limit, \
pCtx->REG.Attr.u, pCtx->REG.u64Base))
#define GENODE_READ_SELREG(REG) \
pCtx->REG.Sel = state->REG.value().sel; \
pCtx->REG.ValidSel = state->REG.value().sel; \
pCtx->REG.fFlags = CPUMSELREG_FLAGS_VALID; \
pCtx->REG.u32Limit = state->REG.value().limit; \
pCtx->REG.u64Base = state->REG.value().base; \
pCtx->REG.Attr.u = sel_ar_conv_from_genode(state->REG.value().ar)
static inline bool svm_save_state(Genode::Vcpu_state * state, VM * pVM, PVMCPU pVCpu)
{
PCPUMCTX pCtx = CPUMQueryGuestCtxPtr(pVCpu);
GENODE_READ_SELREG(cs);
GENODE_READ_SELREG(ds);
GENODE_READ_SELREG(es);
GENODE_READ_SELREG(fs);
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);
GENODE_SVM_ASSERT_SELREG(fs);
GENODE_SVM_ASSERT_SELREG(gs);
GENODE_SVM_ASSERT_SELREG(ss);
GENODE_READ_SELREG(ldtr);
GENODE_READ_SELREG(tr);
CPUMSetGuestEFER(pVCpu, CPUMGetGuestEFER(pVCpu) & ~uint64_t(MSR_K6_EFER_SVME));
return true;
}
#undef GENODE_ASSERT_SELREG
#undef GENODE_READ_SELREG
#define GENODE_WRITE_SELREG(REG) \
Assert(pCtx->REG.fFlags & CPUMSELREG_FLAGS_VALID); \
Assert(pCtx->REG.ValidSel == pCtx->REG.Sel); \
state->REG.charge(Segment { .sel = pCtx->REG.Sel, \
.ar = sel_ar_conv_to_genode(pCtx->REG.Attr.u), \
.limit = pCtx->REG.u32Limit, \
.base = pCtx->REG.u64Base });
static inline bool svm_load_state(Genode::Vcpu_state * state, VM * pVM, PVMCPU pVCpu)
{
typedef Genode::Vcpu_state::Segment Segment;
PCPUMCTX pCtx = CPUMQueryGuestCtxPtr(pVCpu);
state->efer.charge(state->efer.value() | MSR_K6_EFER_SVME);
GENODE_WRITE_SELREG(es);
GENODE_WRITE_SELREG(ds);
GENODE_WRITE_SELREG(fs);
GENODE_WRITE_SELREG(gs);
GENODE_WRITE_SELREG(cs);
GENODE_WRITE_SELREG(ss);
GENODE_WRITE_SELREG(ldtr);
GENODE_WRITE_SELREG(tr);
return true;
}
#undef GENODE_WRITE_SELREG
#endif /* _VIRTUALBOX__SVM_H_ */

View File

@ -1,11 +0,0 @@
TARGET = virtualbox5
include $(REP_DIR)/src/virtualbox5/target.inc
LIBS += virtualbox5
LIBS += blit
vpath frontend/% $(REP_DIR)/src/virtualbox5/
vpath %.cc $(REP_DIR)/src/virtualbox5/
CC_CXX_WARN_STRICT =

View File

@ -1,862 +0,0 @@
/*
* \brief Genode VirtualBox SUPLib supplements
* \author Alexander Boettcher
* \author Norman Feske
* \author Christian Helmuth
*/
/*
* Copyright (C) 2013-2021 Genode Labs GmbH
*
* This file is distributed under the terms of the GNU General Public License
* version 2.
*/
#ifndef _VIRTUALBOX__VCPU_H_
#define _VIRTUALBOX__VCPU_H_
/* Genode includes */
#include <base/log.h>
#include <rom_session/connection.h>
#include <timer_session/connection.h>
#include <vm_session/connection.h>
#include <cpu/vcpu_state.h>
/* VirtualBox includes */
#include "PGMInternal.h" /* enable access to pgm.s.* */
#include "HMInternal.h" /* enable access to hm.s.* */
#include "CPUMInternal.h" /* enable access to cpum.s.* */
#include <VBox/vmm/vm.h>
#include <VBox/vmm/hm_svm.h>
#include <VBox/err.h>
#include <VBox/vmm/pdmapi.h>
#include <iprt/time.h>
/* Genode's VirtualBox includes */
#include "sup.h"
/* Genode libc pthread binding */
#include <internal/pthread.h>
#include <VBox/vmm/rem.h>
/*
* VirtualBox stores segment attributes in Intel format using a 32-bit
* value. Genode represents the attributes in packed format using a 16-bit
* value.
*/
static inline Genode::uint16_t sel_ar_conv_to_genode(Genode::uint32_t v)
{
return (v & 0xff) | ((v & 0x1f000) >> 4);
}
static inline Genode::uint32_t sel_ar_conv_from_genode(Genode::uint16_t v)
{
return (v & 0xff) | (((uint32_t )v << 4) & 0x1f000);
}
class Vcpu_handler : public Genode::List<Vcpu_handler>::Element
{
protected:
static Genode::Vm_connection::Exit_config const _exit_config;
Genode::Entrypoint _ep;
Genode::Blockade _blockade_emt { };
Genode::Semaphore _sem_handler;
Genode::Vcpu_state *_state { nullptr };
pthread_cond_t _cond_wait;
pthread_mutex_t _mutex;
/* information used for NPT/EPT handling */
Genode::addr_t npt_ept_exit_addr { 0 };
RTGCUINT npt_ept_errorcode { 0 };
bool npt_ept_unmap { false };
/* state machine between EMT and EP thread of a vCPU */
enum { RUNNING, PAUSED, IRQ_WIN, NPT_EPT } _vm_state { PAUSED };
enum { PAUSE_EXIT, RUN } _next_state { RUN };
private:
bool _irq_win = false;
unsigned const _cpu_id;
PVM _vm { nullptr };
PVMCPU _vcpu { nullptr };
unsigned int _last_inj_info = 0;
unsigned int _last_inj_error = 0;
enum {
REQ_IRQWIN_EXIT = 0x1000U,
IRQ_INJ_VALID_MASK = 0x80000000UL,
IRQ_INJ_NONE = 0U,
/*
* Intel® 64 and IA-32 Architectures Software Developers Manual
* Volume 3C, Chapter 24.4.2.
* May 2012
*/
BLOCKING_BY_STI = 1U << 0,
BLOCKING_BY_MOV_SS = 1U << 1,
ACTIVITY_STATE_ACTIVE = 0U,
INTERRUPT_STATE_NONE = 0U,
};
timespec add_timespec_ns(timespec a, uint64_t ns) const
{
enum { NSEC_PER_SEC = 1'000'000'000ull };
long sec = a.tv_sec;
while (a.tv_nsec >= NSEC_PER_SEC) {
a.tv_nsec -= NSEC_PER_SEC;
sec++;
}
while (ns >= NSEC_PER_SEC) {
ns -= NSEC_PER_SEC;
sec++;
}
long nsec = a.tv_nsec + ns;
while (nsec >= NSEC_PER_SEC) {
nsec -= NSEC_PER_SEC;
sec++;
}
return timespec { sec, nsec };
}
protected:
int map_memory(Genode::Vm_connection &vm_session,
RTGCPHYS GCPhys, RTGCUINT vbox_fault_reason);
Genode::addr_t _vm_exits = 0;
Genode::addr_t _recall_skip = 0;
Genode::addr_t _recall_req = 0;
Genode::addr_t _recall_inv = 0;
Genode::addr_t _recall_drop = 0;
Genode::addr_t _irq_request = 0;
Genode::addr_t _irq_inject = 0;
Genode::addr_t _irq_drop = 0;
struct {
unsigned ctrl[2];
} next_utcb;
unsigned _ept_fault_addr_type;
Genode::uint64_t * pdpte_map(VM *pVM, RTGCPHYS cr3);
void switch_to_hw(PCPUMCTX pCtx)
{
using Genode::Vcpu_state;
again:
/* write FPU state */
AssertCompile(sizeof(Vcpu_state::Fpu::State) >= sizeof(X86FXSTATE));
_state->fpu.charge([&] (Vcpu_state::Fpu::State &fpu) {
::memcpy(&fpu, pCtx->pXStateR3, sizeof(X86FXSTATE));
});
Assert(_vm_state == IRQ_WIN || _vm_state == PAUSED || _vm_state == NPT_EPT);
Assert(_next_state == PAUSE_EXIT || _next_state == RUN);
/* wake up vcpu ep handler */
_sem_handler.up();
/* wait for next exit */
_blockade_emt.block();
/* next time run - recall() may change this */
_next_state = RUN;
/* write FPU state of vCPU to pCtx */
_state->fpu.with_state([&] (Vcpu_state::Fpu::State const &fpu) {
::memcpy(pCtx->pXStateR3, &fpu, sizeof(X86FXSTATE));
});
_state->discharge();
if (_vm_state == IRQ_WIN) {
_irq_window_pthread();
goto again;
} else
if (_vm_state == NPT_EPT) {
if (npt_ept_unmap) {
Genode::error("NPT/EPT unmap not supported - stop");
while (true) {
_blockade_emt.block();
}
}
Genode::addr_t const gp_map_addr = npt_ept_exit_addr & ~((1UL << 12) - 1);
int res = attach_memory_to_vm(gp_map_addr, npt_ept_errorcode);
if (res == VINF_SUCCESS) {
goto again;
}
}
if (!(_vm_state == PAUSED || _vm_state == NPT_EPT))
Genode::error("which state we are ? ", (int)_vm_state, " ", Genode::Thread::myself()->name());
Assert(_vm_state == PAUSED || _vm_state == NPT_EPT);
}
void _default_handler()
{
if (_vm_state != RUNNING)
Genode::error(__func__, " _vm_state=", (int)_vm_state, " exit_reason=", Genode::Hex(_state->exit_reason));
Assert(_vm_state == RUNNING);
Assert(_state->actv_state.value() == ACTIVITY_STATE_ACTIVE);
Assert(!(_state->inj_info.value() & IRQ_INJ_VALID_MASK));
_vm_exits ++;
_vm_state = PAUSED;
_blockade_emt.wakeup();
}
bool _recall_handler()
{
if (_vm_state != RUNNING)
Genode::error(__func__, " _vm_state=", (int)_vm_state, " exit_reason=", Genode::Hex(_state->exit_reason));
Assert(_vm_state == RUNNING);
_vm_exits ++;
_recall_inv ++;
Assert(_state->actv_state.value() == ACTIVITY_STATE_ACTIVE);
if (_state->inj_info.value() & IRQ_INJ_VALID_MASK) {
Assert(_state->flags.value() & X86_EFL_IF);
if (_state->intr_state.value() != INTERRUPT_STATE_NONE)
Genode::log("intr state ", Genode::Hex(_state->intr_state.value()),
" ", Genode::Hex(_state->intr_state.value() & 0xf));
Assert(_state->intr_state.value() == INTERRUPT_STATE_NONE);
if (!continue_hw_accelerated())
_recall_drop ++;
/* got recall during irq injection and the guest is ready for
* delivery of IRQ - just continue */
return /* no-wait */ false;
}
/* are we forced to go back to emulation mode ? */
if (!continue_hw_accelerated()) {
/* go back to emulation mode */
_default_handler();
return /* wait */ true;
}
/* check whether we have to request irq injection window */
if (check_to_request_irq_window(_vcpu)) {
_state->discharge();
_state->inj_info.charge(_state->inj_info.value());
_irq_win = true;
return /* no-wait */ false;
}
_default_handler();
return /* wait */ true;
}
inline bool vbox_to_state(VM *pVM, PVMCPU pVCpu)
{
typedef Genode::Vcpu_state::Range Range;
PCPUMCTX pCtx = CPUMQueryGuestCtxPtr(pVCpu);
_state->ip.charge(pCtx->rip);
_state->sp.charge(pCtx->rsp);
_state->ax.charge(pCtx->rax);
_state->bx.charge(pCtx->rbx);
_state->cx.charge(pCtx->rcx);
_state->dx.charge(pCtx->rdx);
_state->bp.charge(pCtx->rbp);
_state->si.charge(pCtx->rsi);
_state->di.charge(pCtx->rdi);
_state->r8.charge(pCtx->r8);
_state->r9.charge(pCtx->r9);
_state->r10.charge(pCtx->r10);
_state->r11.charge(pCtx->r11);
_state->r12.charge(pCtx->r12);
_state->r13.charge(pCtx->r13);
_state->r14.charge(pCtx->r14);
_state->r15.charge(pCtx->r15);
_state->flags.charge(pCtx->rflags.u);
_state->sysenter_cs.charge(pCtx->SysEnter.cs);
_state->sysenter_sp.charge(pCtx->SysEnter.esp);
_state->sysenter_ip.charge(pCtx->SysEnter.eip);
_state->dr7.charge(pCtx->dr[7]);
_state->cr0.charge(pCtx->cr0);
_state->cr2.charge(pCtx->cr2);
_state->cr3.charge(pCtx->cr3);
_state->cr4.charge(pCtx->cr4);
_state->idtr.charge(Range { .limit = pCtx->idtr.cbIdt,
.base = pCtx->idtr.pIdt });
_state->gdtr.charge(Range { .limit = pCtx->gdtr.cbGdt,
.base = pCtx->gdtr.pGdt });
_state->efer.charge(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)) {
Genode::uint64_t *pdpte = pdpte_map(pVM, pCtx->cr3);
_state->pdpte_0.charge(pdpte[0]);
_state->pdpte_1.charge(pdpte[1]);
_state->pdpte_2.charge(pdpte[2]);
_state->pdpte_3.charge(pdpte[3]);
}
_state->star.charge(pCtx->msrSTAR);
_state->lstar.charge(pCtx->msrLSTAR);
_state->cstar.charge(pCtx->msrCSTAR);
_state->fmask.charge(pCtx->msrSFMASK);
_state->kernel_gs_base.charge(pCtx->msrKERNELGSBASE);
/* from HMVMXR0.cpp */
bool interrupt_pending = false;
uint8_t tpr = 0;
uint8_t pending_interrupt = 0;
PDMApicGetTPR(pVCpu, &tpr, &interrupt_pending, &pending_interrupt);
_state->tpr.charge(tpr);
_state->tpr_threshold.charge(0);
if (interrupt_pending) {
const uint8_t pending_priority = (pending_interrupt >> 4) & 0xf;
const uint8_t tpr_priority = (tpr >> 4) & 0xf;
if (pending_priority <= tpr_priority)
_state->tpr_threshold.charge(pending_priority);
else
_state->tpr_threshold.charge(tpr_priority);
}
{
::uint64_t tsc_aux = 0;
auto const rcStrict = CPUMQueryGuestMsr(pVCpu, MSR_K8_TSC_AUX,
&tsc_aux);
Assert(rcStrict == VINF_SUCCESS);
if (rcStrict == VINF_SUCCESS)
_state->tsc_aux.charge(tsc_aux);
}
return true;
}
inline bool state_to_vbox(VM *pVM, PVMCPU pVCpu)
{
PCPUMCTX pCtx = CPUMQueryGuestCtxPtr(pVCpu);
pCtx->rip = _state->ip.value();
pCtx->rsp = _state->sp.value();
pCtx->rax = _state->ax.value();
pCtx->rbx = _state->bx.value();
pCtx->rcx = _state->cx.value();
pCtx->rdx = _state->dx.value();
pCtx->rbp = _state->bp.value();
pCtx->rsi = _state->si.value();
pCtx->rdi = _state->di.value();
pCtx->rflags.u = _state->flags.value();
pCtx->r8 = _state->r8.value();
pCtx->r9 = _state->r9.value();
pCtx->r10 = _state->r10.value();
pCtx->r11 = _state->r11.value();
pCtx->r12 = _state->r12.value();
pCtx->r13 = _state->r13.value();
pCtx->r14 = _state->r14.value();
pCtx->r15 = _state->r15.value();
pCtx->dr[7] = _state->dr7.value();
if (pCtx->SysEnter.cs != _state->sysenter_cs.value())
CPUMSetGuestMsr(pVCpu, MSR_IA32_SYSENTER_CS, _state->sysenter_cs.value());
if (pCtx->SysEnter.esp != _state->sysenter_sp.value())
CPUMSetGuestMsr(pVCpu, MSR_IA32_SYSENTER_ESP, _state->sysenter_sp.value());
if (pCtx->SysEnter.eip != _state->sysenter_ip.value())
CPUMSetGuestMsr(pVCpu, MSR_IA32_SYSENTER_EIP, _state->sysenter_ip.value());
if (pCtx->idtr.cbIdt != _state->idtr.value().limit ||
pCtx->idtr.pIdt != _state->idtr.value().base)
CPUMSetGuestIDTR(pVCpu, _state->idtr.value().base, _state->idtr.value().limit);
if (pCtx->gdtr.cbGdt != _state->gdtr.value().limit ||
pCtx->gdtr.pGdt != _state->gdtr.value().base)
CPUMSetGuestGDTR(pVCpu, _state->gdtr.value().base, _state->gdtr.value().limit);
CPUMSetGuestEFER(pVCpu, _state->efer.value());
if (pCtx->cr0 != _state->cr0.value())
CPUMSetGuestCR0(pVCpu, _state->cr0.value());
if (pCtx->cr2 != _state->cr2.value())
CPUMSetGuestCR2(pVCpu, _state->cr2.value());
if (pCtx->cr3 != _state->cr3.value()) {
CPUMSetGuestCR3(pVCpu, _state->cr3.value());
VMCPU_FF_SET(pVCpu, VMCPU_FF_HM_UPDATE_CR3);
}
if (pCtx->cr4 != _state->cr4.value())
CPUMSetGuestCR4(pVCpu, _state->cr4.value());
if (pCtx->msrSTAR != _state->star.value())
CPUMSetGuestMsr(pVCpu, MSR_K6_STAR, _state->star.value());
if (pCtx->msrLSTAR != _state->lstar.value())
CPUMSetGuestMsr(pVCpu, MSR_K8_LSTAR, _state->lstar.value());
if (pCtx->msrCSTAR != _state->cstar.value())
CPUMSetGuestMsr(pVCpu, MSR_K8_CSTAR, _state->cstar.value());
if (pCtx->msrSFMASK != _state->fmask.value())
CPUMSetGuestMsr(pVCpu, MSR_K8_SF_MASK, _state->fmask.value());
if (pCtx->msrKERNELGSBASE != _state->kernel_gs_base.value())
CPUMSetGuestMsr(pVCpu, MSR_K8_KERNEL_GS_BASE, _state->kernel_gs_base.value());
const uint32_t tpr = _state->tpr.value();
/* reset message transfer descriptor for next invocation */
Assert (!(_state->inj_info.value() & IRQ_INJ_VALID_MASK));
next_utcb.ctrl[0] = _state->ctrl_primary.value();
next_utcb.ctrl[1] = _state->ctrl_secondary.value();
if (_state->intr_state.value() & 3) {
_state->intr_state.charge(_state->intr_state.value());
_state->actv_state.charge(ACTIVITY_STATE_ACTIVE);
}
VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_TO_R3);
CPUMSetChangedFlags(pVCpu, CPUM_CHANGED_FPU_REM);
pVCpu->cpum.s.fUseFlags |= (CPUM_USED_FPU_GUEST | CPUM_USED_FPU_SINCE_REM);
if (_state->intr_state.value() != 0) {
Assert(_state->intr_state.value() == BLOCKING_BY_STI ||
_state->intr_state.value() == BLOCKING_BY_MOV_SS);
EMSetInhibitInterruptsPC(pVCpu, pCtx->rip);
} else
VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS);
PDMApicSetTPR(pVCpu, tpr);
return true;
}
inline bool check_to_request_irq_window(PVMCPU pVCpu)
{
if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS))
return false;
if (!TRPMHasTrap(pVCpu) &&
!VMCPU_FF_IS_PENDING(pVCpu, (VMCPU_FF_INTERRUPT_APIC |
VMCPU_FF_INTERRUPT_PIC)))
return false;
_irq_request++;
unsigned const vector = 0;
_state->inj_info.charge(REQ_IRQWIN_EXIT | vector);
return true;
}
void _irq_window()
{
if (_vm_state != RUNNING)
Genode::error(__func__, " _vm_state=", (int)_vm_state, " exit_reason=", Genode::Hex(_state->exit_reason));
Assert(_vm_state == RUNNING);
_vm_exits ++;
_vm_state = IRQ_WIN;
_blockade_emt.wakeup();
}
void _npt_ept()
{
if (_vm_state != RUNNING)
Genode::error(__func__, " _vm_state=", (int)_vm_state, " exit_reason=", Genode::Hex(_state->exit_reason));
Assert(_vm_state == RUNNING);
_vm_exits ++;
_vm_state = NPT_EPT;
_blockade_emt.wakeup();
}
void _irq_window_pthread()
{
PVMCPU pVCpu = _vcpu;
Assert(_state->flags.value() & X86_EFL_IF);
Assert(!VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS));
Assert(!(_state->inj_info.value() & IRQ_INJ_VALID_MASK));
Assert(_irq_win);
_irq_win = false;
/* request current tpr state from guest, it may block IRQs */
PDMApicSetTPR(pVCpu, _state->tpr_threshold.value());
if (!TRPMHasTrap(pVCpu)) {
bool res = VMCPU_FF_TEST_AND_CLEAR(pVCpu, VMCPU_FF_INTERRUPT_NMI);
if (res)
Genode::log("NMI was set");
if (VMCPU_FF_IS_PENDING(pVCpu, (VMCPU_FF_INTERRUPT_APIC |
VMCPU_FF_INTERRUPT_PIC))) {
uint8_t irq;
int rc = PDMGetInterrupt(pVCpu, &irq);
Assert(RT_SUCCESS(rc));
rc = TRPMAssertTrap(pVCpu, irq, TRPM_HARDWARE_INT);
Assert(RT_SUCCESS(rc));
}
if (!TRPMHasTrap(pVCpu)) {
_irq_drop++;
/* happens if PDMApicSetTPR (see above) mask IRQ */
_state->inj_info.charge(IRQ_INJ_NONE);
Genode::error("virq window pthread aaaaaaa while loop");
return;
}
}
_irq_inject++;
/*
* If we have no IRQ for injection, something with requesting the
* IRQ window went wrong. Probably it was forgotten to be reset.
*/
Assert(TRPMHasTrap(pVCpu));
/* interrupt can be dispatched */
uint8_t u8Vector;
TRPMEVENT enmType;
SVMEVENT Event;
RTGCUINT u32ErrorCode;
RTGCUINTPTR GCPtrFaultAddress;
uint8_t cbInstr;
Event.u = 0;
/* If a new event is pending, then dispatch it now. */
int rc = TRPMQueryTrapAll(pVCpu, &u8Vector, &enmType, &u32ErrorCode, 0, 0);
AssertRC(rc);
Assert(enmType == TRPM_HARDWARE_INT);
Assert(u8Vector != X86_XCPT_NMI);
/* Clear the pending trap. */
rc = TRPMResetTrap(pVCpu);
AssertRC(rc);
Event.n.u8Vector = u8Vector;
Event.n.u1Valid = 1;
Event.n.u32ErrorCode = u32ErrorCode;
Event.n.u3Type = SVM_EVENT_EXTERNAL_IRQ;
_state->inj_info.charge(Event.u);
_state->inj_error.charge(Event.n.u32ErrorCode);
_last_inj_info = _state->inj_info.value();
_last_inj_error = _state->inj_error.value();
/*
Genode::log("type:info:vector ", Genode::Hex(Event.n.u3Type),
Genode::Hex(utcb->inj_info), Genode::Hex(u8Vector),
" intr:actv - ", Genode::Hex(utcb->intr_state),
Genode::Hex(utcb->actv_state), " mtd ",
Genode::Hex(utcb->mtd));
*/
}
inline bool continue_hw_accelerated(bool verbose = false)
{
uint32_t check_vm = VM_FF_HM_TO_R3_MASK | VM_FF_REQUEST
| VM_FF_PGM_POOL_FLUSH_PENDING
| VM_FF_PDM_DMA;
uint32_t check_vcpu = VMCPU_FF_HM_TO_R3_MASK
| VMCPU_FF_PGM_SYNC_CR3
| VMCPU_FF_PGM_SYNC_CR3_NON_GLOBAL
| VMCPU_FF_REQUEST;
if (!VM_FF_IS_PENDING(_vm, check_vm) &&
!VMCPU_FF_IS_PENDING(_vcpu, check_vcpu))
return true;
Assert(!(VM_FF_IS_PENDING(_vm, VM_FF_PGM_NO_MEMORY)));
#define VERBOSE_VM(flag) \
do { \
if (VM_FF_IS_PENDING(_vm, flag)) \
Genode::log("flag ", flag, " pending"); \
} while (0)
#define VERBOSE_VMCPU(flag) \
do { \
if (VMCPU_FF_IS_PENDING(_vcpu, flag)) \
Genode::log("flag ", flag, " pending"); \
} while (0)
if (verbose) {
/*
* VM_FF_HM_TO_R3_MASK
*/
VERBOSE_VM(VM_FF_TM_VIRTUAL_SYNC);
VERBOSE_VM(VM_FF_PGM_NEED_HANDY_PAGES);
/* handled by the assertion above */
/* VERBOSE_VM(VM_FF_PGM_NO_MEMORY); */
VERBOSE_VM(VM_FF_PDM_QUEUES);
VERBOSE_VM(VM_FF_EMT_RENDEZVOUS);
VERBOSE_VM(VM_FF_REQUEST);
VERBOSE_VM(VM_FF_PGM_POOL_FLUSH_PENDING);
VERBOSE_VM(VM_FF_PDM_DMA);
/*
* VMCPU_FF_HM_TO_R3_MASK
*/
VERBOSE_VMCPU(VMCPU_FF_TO_R3);
/* when this flag gets set, a recall request follows */
/* VERBOSE_VMCPU(VMCPU_FF_TIMER); */
VERBOSE_VMCPU(VMCPU_FF_PDM_CRITSECT);
VERBOSE_VMCPU(VMCPU_FF_PGM_SYNC_CR3);
VERBOSE_VMCPU(VMCPU_FF_PGM_SYNC_CR3_NON_GLOBAL);
VERBOSE_VMCPU(VMCPU_FF_REQUEST);
}
#undef VERBOSE_VMCPU
#undef VERBOSE_VM
return false;
}
virtual bool hw_load_state(Genode::Vcpu_state *, VM *, PVMCPU) = 0;
virtual bool hw_save_state(Genode::Vcpu_state *, VM *, PVMCPU) = 0;
virtual int vm_exit_requires_instruction_emulation(PCPUMCTX) = 0;
virtual void pause_vm() = 0;
virtual int attach_memory_to_vm(RTGCPHYS const,
RTGCUINT vbox_fault_reason) = 0;
public:
enum Exit_condition
{
SVM_NPT = 0xfc,
SVM_INVALID = 0xfd,
VCPU_STARTUP = 0xfe,
RECALL = 0xff,
};
Vcpu_handler(Genode::Env &env, size_t stack_size,
Genode::Affinity::Location location,
unsigned int cpu_id)
:
_ep(env, stack_size,
Genode::String<12>("EP-EMT-", cpu_id).string(), location),
_cpu_id(cpu_id)
{
pthread_mutexattr_t _attr;
pthread_mutexattr_init(&_attr);
pthread_cond_init(&_cond_wait, nullptr);
pthread_mutexattr_settype(&_attr, PTHREAD_MUTEX_ERRORCHECK);
pthread_mutex_init(&_mutex, &_attr);
}
unsigned int cpu_id() { return _cpu_id; }
void recall(PVM vm)
{
if (!_vm || !_vcpu) {
_vm = vm;
_vcpu = &vm->aCpus[_cpu_id];
}
if (_vm != vm || _vcpu != &vm->aCpus[_cpu_id])
Genode::error("wrong CPU !?");
_recall_req ++;
if (_irq_win) {
_recall_skip ++;
return;
}
asm volatile ("":::"memory");
if (_vm_state != PAUSED)
pause_vm();
_next_state = PAUSE_EXIT;
#if 0
if (_recall_req % 1000 == 0) {
using Genode::log;
while (other) {
log(other->_cpu_id, " exits=", other->_vm_exits,
" req:skip:drop,inv recall=", other->_recall_req, ":",
other->_recall_skip, ":", other->_recall_drop, ":",
other->_recall_inv, " req:inj:drop irq=",
other->_irq_request, ":", other->_irq_inject, ":",
other->_irq_drop);
other = other->next();
}
}
#endif
}
void halt(Genode::uint64_t const wait_ns)
{
/* calculate timeout */
timespec ts { 0, 0 };
clock_gettime(CLOCK_REALTIME, &ts);
ts = add_timespec_ns(ts, wait_ns);
/* wait for condition or timeout */
pthread_mutex_lock(&_mutex);
pthread_cond_timedwait(&_cond_wait, &_mutex, &ts);
pthread_mutex_unlock(&_mutex);
}
void wake_up()
{
pthread_mutex_lock(&_mutex);
pthread_cond_signal(&_cond_wait);
pthread_mutex_unlock(&_mutex);
}
int run_hw(PVMR0 pVMR0)
{
VM * pVM = reinterpret_cast<VM *>(pVMR0);
PVMCPU pVCpu = &pVM->aCpus[_cpu_id];
PCPUMCTX pCtx = CPUMQueryGuestCtxPtr(pVCpu);
if (!_vm || !_vcpu) {
_vm = pVM;
_vcpu = &pVM->aCpus[_cpu_id];
}
if (_vm != pVM || _vcpu != &pVM->aCpus[_cpu_id])
Genode::error("wrong CPU !?");
/* take the utcb state prepared during the last exit */
_state->ctrl_primary.charge(next_utcb.ctrl[0]);
_state->ctrl_secondary.charge(next_utcb.ctrl[1]);
/* Transfer vCPU state from vbox to Genode format */
if (!vbox_to_state(pVM, pVCpu) ||
!hw_load_state(_state, pVM, pVCpu)) {
Genode::error("loading vCPU state failed");
return VERR_INTERNAL_ERROR;
}
/* check whether to request interrupt window for injection */
_irq_win = check_to_request_irq_window(pVCpu);
/*
* Flag vCPU to be "pokeable" by external events such as interrupts
* from virtual devices. Only if this flag is set, the
* 'vmR3HaltGlobal1NotifyCpuFF' function calls 'SUPR3CallVMMR0Ex'
* with VMMR0_DO_GVMM_SCHED_POKE as argument to indicate such
* events. This function, in turn, will recall the vCPU.
*/
VMCPU_SET_STATE(pVCpu, VMCPUSTATE_STARTED_EXEC);
/* switch to hardware accelerated mode */
switch_to_hw(pCtx);
Assert(_state->actv_state.value() == ACTIVITY_STATE_ACTIVE);
/* see hmR0VmxExitToRing3 - sync recompiler state */
CPUMSetChangedFlags(pVCpu, CPUM_CHANGED_SYSENTER_MSR |
CPUM_CHANGED_LDTR | CPUM_CHANGED_GDTR |
CPUM_CHANGED_IDTR | CPUM_CHANGED_TR |
CPUM_CHANGED_HIDDEN_SEL_REGS |
CPUM_CHANGED_GLOBAL_TLB_FLUSH);
VMCPU_SET_STATE(pVCpu, VMCPUSTATE_STARTED);
/* Transfer vCPU state from Genode to vbox format */
if (!state_to_vbox(pVM, pVCpu) ||
!hw_save_state(_state, pVM, pVCpu)) {
Genode::error("saving vCPU state failed");
return VERR_INTERNAL_ERROR;
}
#ifdef VBOX_WITH_REM
REMFlushTBs(pVM);
#endif
/* track guest mode changes - see VMM/VMMAll/IEMAllCImpl.cpp.h */
PGMChangeMode(pVCpu, pCtx->cr0, pCtx->cr4, pCtx->msrEFER);
int rc = vm_exit_requires_instruction_emulation(pCtx);
/* evaluated in VMM/include/EMHandleRCTmpl.h */
return rc;
}
};
#endif /* _VIRTUALBOX__VCPU_H_ */

View File

@ -1,189 +0,0 @@
/*
* \brief Genode specific VirtualBox SUPLib supplements
* \author Alexander Boettcher
* \author Norman Feske
* \author Christian Helmuth
* \date 2013-11-18
*/
/*
* Copyright (C) 2013-2021 Genode Labs GmbH
*
* This file is distributed under the terms of the GNU General Public License
* version 2.
*/
#ifndef _VIRTUALBOX__VCPU_SVM_H_
#define _VIRTUALBOX__VCPU_SVM_H_
/* Genode includes */
#include <vm_session/handler.h>
/* Genode's VirtualBox includes */
#include "vcpu.h"
#include "svm.h"
class Vcpu_handler_svm : public Vcpu_handler
{
private:
Genode::Vcpu_handler<Vcpu_handler_svm> _handler;
Genode::Vm_connection &_vm_connection;
Genode::Vm_connection::Vcpu _vcpu;
void _svm_default() { _default_handler(); }
void _svm_vintr() { _irq_window(); }
template <unsigned X>
void _svm_npt()
{
bool const unmap = _state->qual_primary.value() & 1;
Genode::addr_t const exit_addr = _state->qual_secondary.value();
RTGCUINT const vbox_errorcode = _state->qual_primary.value();
npt_ept_exit_addr = exit_addr;
npt_ept_unmap = unmap;
npt_ept_errorcode = vbox_errorcode;
_npt_ept();
}
void _svm_startup()
{
/* 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_exit()
{
unsigned const exit = _state->exit_reason;
bool recall_wait = true;
switch (exit) {
case SVM_EXIT_VINTR: _svm_vintr(); break;
case SVM_NPT: _svm_npt<SVM_NPT>(); 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;
case VCPU_STARTUP:
_svm_startup();
_blockade_emt.wakeup();
/* pause - no resume */
break;
default:
Genode::error(__func__, " unknown exit - stop - ",
Genode::Hex(exit));
_vm_state = PAUSED;
return;
}
if (exit == RECALL && !recall_wait) {
_vm_state = RUNNING;
run_vm();
return;
}
/* wait until EMT thread wake's us up */
_sem_handler.down();
/* resume vCPU */
_vm_state = RUNNING;
if (_next_state == RUN)
run_vm();
else
pause_vm(); /* cause pause exit */
}
void run_vm() { _vcpu.run(); }
void pause_vm() { _vcpu.pause(); }
int attach_memory_to_vm(RTGCPHYS const gp_attach_addr,
RTGCUINT vbox_errorcode)
{
return map_memory(_vm_connection, gp_attach_addr, vbox_errorcode);
}
public:
Vcpu_handler_svm(Genode::Env &env, size_t stack_size,
Genode::Affinity::Location location,
unsigned int cpu_id,
Genode::Vm_connection &vm_connection,
Genode::Allocator &alloc)
:
Vcpu_handler(env, stack_size, location, cpu_id),
_handler(_ep, *this, &Vcpu_handler_svm::_handle_exit),
_vm_connection(vm_connection),
_vcpu(_vm_connection, alloc, _handler, _exit_config)
{
/* get state of vcpu */
_state = &_vcpu.state();
_vcpu.run();
/* sync with initial startup exception */
_blockade_emt.block();
}
bool hw_save_state(Genode::Vcpu_state *state, VM * pVM, PVMCPU pVCpu) {
return svm_save_state(state, pVM, pVCpu);
}
bool hw_load_state(Genode::Vcpu_state *state, VM * pVM, PVMCPU pVCpu) {
return svm_load_state(state, pVM, pVCpu);
}
int vm_exit_requires_instruction_emulation(PCPUMCTX)
{
if (_state->exit_reason == RECALL)
return VINF_SUCCESS;
return VINF_EM_RAW_EMULATE_INSTR;
}
};
#endif /* _VIRTUALBOX__VCPU_SVM_H_ */

View File

@ -1,251 +0,0 @@
/*
* \brief Genode specific VirtualBox SUPLib supplements
* \author Alexander Boettcher
* \author Norman Feske
* \author Christian Helmuth
* \date 2013-11-18
*/
/*
* Copyright (C) 2013-2021 Genode Labs GmbH
*
* This file is distributed under the terms of the GNU General Public License
* version 2.
*/
#ifndef _VIRTUALBOX__VCPU_VMX_H_
#define _VIRTUALBOX__VCPU_VMX_H_
/* Genode includes */
#include <vm_session/handler.h>
/* libc includes */
#include <stdlib.h>
/* VirtualBox includes */
#include <VBox/vmm/hm_vmx.h>
/* Genode's VirtualBox includes */
#include "vcpu.h"
#include "vmx.h"
class Vcpu_handler_vmx : public Vcpu_handler
{
private:
Genode::Vcpu_handler<Vcpu_handler_vmx> _handler;
Genode::Vm_connection &_vm_connection;
Genode::Vm_connection::Vcpu _vcpu;
template <unsigned X>
void _vmx_ept()
{
Genode::addr_t const exit_qual = _state->qual_primary.value();
Genode::addr_t const exit_addr = _state->qual_secondary.value();
bool const unmap = exit_qual & 0x38;
RTGCUINT vbox_errorcode = 0;
if (exit_qual & VMX_EXIT_QUALIFICATION_EPT_INSTR_FETCH)
vbox_errorcode |= X86_TRAP_PF_ID;
if (exit_qual & VMX_EXIT_QUALIFICATION_EPT_DATA_WRITE)
vbox_errorcode |= X86_TRAP_PF_RW;
if (exit_qual & VMX_EXIT_QUALIFICATION_EPT_ENTRY_PRESENT)
vbox_errorcode |= X86_TRAP_PF_P;
npt_ept_exit_addr = exit_addr;
npt_ept_unmap = unmap;
npt_ept_errorcode = vbox_errorcode;
_npt_ept();
}
void _vmx_default() { _default_handler(); }
void _vmx_startup()
{
/* configure VM exits to get */
/* from src/VBox/VMM/VMMR0/HWVMXR0.cpp of virtualbox sources */
next_utcb.ctrl[0] = VMX_VMCS_CTRL_PROC_EXEC_HLT_EXIT |
VMX_VMCS_CTRL_PROC_EXEC_MOV_DR_EXIT |
VMX_VMCS_CTRL_PROC_EXEC_UNCOND_IO_EXIT |
/*
VMX_VMCS_CTRL_PROC_EXEC_MONITOR_EXIT |
VMX_VMCS_CTRL_PROC_EXEC_MWAIT_EXIT |
*/
/* VMX_VMCS_CTRL_PROC_EXEC_CR8_LOAD_EXIT |
VMX_VMCS_CTRL_PROC_EXEC_CR8_STORE_EXIT |*/
VMX_VMCS_CTRL_PROC_EXEC_USE_TPR_SHADOW |
VMX_VMCS_CTRL_PROC_EXEC_RDPMC_EXIT;
/* VMX_VMCS_CTRL_PROC_EXEC_PAUSE_EXIT | */
/*
* Disable trapping RDTSC for now as it creates a huge load with
* VM guests that execute it frequently.
*/
// VMX_VMCS_CTRL_PROC_EXEC_RDTSC_EXIT;
next_utcb.ctrl[1] = VMX_VMCS_CTRL_PROC_EXEC2_VIRT_APIC |
VMX_VMCS_CTRL_PROC_EXEC2_WBINVD_EXIT |
VMX_VMCS_CTRL_PROC_EXEC2_UNRESTRICTED_GUEST |
VMX_VMCS_CTRL_PROC_EXEC2_VPID |
VMX_VMCS_CTRL_PROC_EXEC2_RDTSCP |
VMX_VMCS_CTRL_PROC_EXEC2_EPT |
VMX_VMCS_CTRL_PROC_EXEC2_INVPCID;
}
void _vmx_triple()
{
Genode::error("triple fault - dead");
exit(-1);
}
void _vmx_irqwin() { _irq_window(); }
__attribute__((noreturn)) void _vmx_invalid()
{
unsigned const dubious = _state->inj_info.value() |
_state->intr_state.value() |
_state->actv_state.value();
if (dubious)
Genode::warning(__func__, " - dubious -"
" inj_info=", Genode::Hex(_state->inj_info.value()),
" inj_error=", Genode::Hex(_state->inj_error.value()),
" intr_state=", Genode::Hex(_state->intr_state.value()),
" actv_state=", Genode::Hex(_state->actv_state.value()));
Genode::error("invalid guest state - dead");
exit(-1);
}
void _vmx_mov_crx() { _default_handler(); return; }
void _handle_exit()
{
unsigned const exit = _state->exit_reason;
bool recall_wait = true;
switch (exit) {
case VMX_EXIT_TRIPLE_FAULT: _vmx_triple(); break;
case VMX_EXIT_INIT_SIGNAL: _vmx_default(); break;
case VMX_EXIT_INT_WINDOW: _vmx_irqwin(); break;
case VMX_EXIT_TASK_SWITCH: _vmx_default(); break;
case VMX_EXIT_CPUID: _vmx_default(); break;
case VMX_EXIT_HLT: _vmx_default(); break;
/* we don't support tsc offsetting for now - so let the rdtsc exit */
case VMX_EXIT_RDTSC: _vmx_default(); break;
case VMX_EXIT_RDTSCP: _vmx_default(); break;
case VMX_EXIT_VMCALL: _vmx_default(); break;
case VMX_EXIT_IO_INSTR: _vmx_default(); break;
case VMX_EXIT_RDMSR: _vmx_default(); break;
case VMX_EXIT_WRMSR: _vmx_default(); break;
case VMX_EXIT_ERR_INVALID_GUEST_STATE: _vmx_invalid(); break;
case VMX_EXIT_PAUSE: _vmx_default(); break;
case VMX_EXIT_WBINVD: _vmx_default(); break;
case VMX_EXIT_MOV_CRX: _vmx_mov_crx(); break;
case VMX_EXIT_MOV_DRX: _vmx_default(); break;
case VMX_EXIT_XSETBV: _vmx_default(); break;
case VMX_EXIT_TPR_BELOW_THRESHOLD: _vmx_default(); break;
case VMX_EXIT_EPT_VIOLATION: _vmx_ept<VMX_EXIT_EPT_VIOLATION>(); break;
case RECALL:
recall_wait = Vcpu_handler::_recall_handler();
break;
case VCPU_STARTUP:
_vmx_startup();
_blockade_emt.wakeup();
/* pause - no resume */
break;
default:
Genode::error(__func__, " unknown exit - stop - ",
Genode::Hex(exit));
_vm_state = PAUSED;
return;
}
if (exit == RECALL && !recall_wait) {
_vm_state = RUNNING;
run_vm();
return;
}
/* wait until EMT thread wake's us up */
_sem_handler.down();
/* resume vCPU */
_vm_state = RUNNING;
if (_next_state == RUN)
run_vm();
else
pause_vm(); /* cause pause exit */
}
void run_vm() { _vcpu.run(); }
void pause_vm() { _vcpu.pause(); }
int attach_memory_to_vm(RTGCPHYS const gp_attach_addr,
RTGCUINT vbox_errorcode)
{
return map_memory(_vm_connection, gp_attach_addr, vbox_errorcode);
}
public:
Vcpu_handler_vmx(Genode::Env &env, size_t stack_size,
Genode::Affinity::Location location,
unsigned int cpu_id,
Genode::Vm_connection &vm_connection,
Genode::Allocator &alloc)
:
Vcpu_handler(env, stack_size, location, cpu_id),
_handler(_ep, *this, &Vcpu_handler_vmx::_handle_exit),
_vm_connection(vm_connection),
_vcpu(_vm_connection, alloc, _handler, _exit_config)
{
/* get state of vcpu */
_state = &_vcpu.state();
_vcpu.run();
/* sync with initial startup exception */
_blockade_emt.block();
}
bool hw_save_state(Genode::Vcpu_state *state, VM * pVM, PVMCPU pVCpu) {
return vmx_save_state(state, pVM, pVCpu);
}
bool hw_load_state(Genode::Vcpu_state * state, VM * pVM, PVMCPU pVCpu) {
return vmx_load_state(state, pVM, pVCpu);
}
int vm_exit_requires_instruction_emulation(PCPUMCTX pCtx)
{
switch (_state->exit_reason) {
case VMX_EXIT_HLT:
pCtx->rip++;
return VINF_EM_HALT;
case VMX_EXIT_IO_INSTR:
/* EMHandleRCTmpl.h does not distinguish READ/WRITE rc */
return VINF_IOM_R3_IOPORT_WRITE;
case VMX_EXIT_RDMSR:
return VINF_CPUM_R3_MSR_READ;
case VMX_EXIT_WRMSR:
return VINF_CPUM_R3_MSR_WRITE;
case VMX_EXIT_TPR_BELOW_THRESHOLD:
/* the instruction causing the exit has already been executed */
case RECALL:
return VINF_SUCCESS;
case VMX_EXIT_EPT_VIOLATION:
if (_ept_fault_addr_type == PGMPAGETYPE_MMIO)
/* EMHandleRCTmpl.h does not distinguish READ/WRITE rc */
return VINF_IOM_R3_MMIO_READ_WRITE;
case VMX_EXIT_MOV_DRX:
/* looks complicated in original R0 code -> emulate instead */
return VINF_EM_RAW_EMULATE_INSTR;
default:
return VINF_EM_RAW_EMULATE_INSTR;
}
}
};
#endif /* _VIRTUALBOX__VCPU_VMX_H_ */

View File

@ -1,110 +0,0 @@
/*
* \brief Genode specific VirtualBox SUPLib supplements
* \author Norman Feske
* \author Alexander Boettcher
* \author Christian Helmuth
*/
/*
* Copyright (C) 2013-2021 Genode Labs GmbH
*
* This file is distributed under the terms of the GNU General Public License
* version 2.
*/
#ifndef _VIRTUALBOX__VMX_H_
#define _VIRTUALBOX__VMX_H_
#define GENODE_READ_SELREG_REQUIRED(REG) \
(pCtx->REG.Sel != state->REG.value().sel) || \
(pCtx->REG.ValidSel != state->REG.value().sel) || \
(pCtx->REG.fFlags != CPUMSELREG_FLAGS_VALID) || \
(pCtx->REG.u32Limit != state->REG.value().limit) || \
(pCtx->REG.u64Base != state->REG.value().base) || \
(pCtx->REG.Attr.u != sel_ar_conv_from_genode(state->REG.value().ar))
#define GENODE_READ_SELREG(REG) \
pCtx->REG.Sel = state->REG.value().sel; \
pCtx->REG.ValidSel = state->REG.value().sel; \
pCtx->REG.fFlags = CPUMSELREG_FLAGS_VALID; \
pCtx->REG.u32Limit = state->REG.value().limit; \
pCtx->REG.u64Base = state->REG.value().base; \
pCtx->REG.Attr.u = sel_ar_conv_from_genode(state->REG.value().ar)
static inline bool vmx_save_state(Genode::Vcpu_state * state, VM * pVM, PVMCPU pVCpu)
{
PCPUMCTX pCtx = CPUMQueryGuestCtxPtr(pVCpu);
GENODE_READ_SELREG(cs);
GENODE_READ_SELREG(ds);
GENODE_READ_SELREG(es);
GENODE_READ_SELREG(fs);
GENODE_READ_SELREG(gs);
GENODE_READ_SELREG(ss);
if (GENODE_READ_SELREG_REQUIRED(ldtr)) {
GENODE_READ_SELREG(ldtr);
CPUMSetChangedFlags(pVCpu, CPUM_CHANGED_LDTR);
}
if (GENODE_READ_SELREG_REQUIRED(tr)) {
GENODE_READ_SELREG(tr);
CPUMSetChangedFlags(pVCpu, CPUM_CHANGED_TR);
}
return true;
}
#undef GENODE_READ_SELREG_REQUIRED
#undef GENODE_READ_SELREG
enum { VMCS_SEG_UNUSABLE = 0x10000 };
#define GENODE_WRITE_SELREG(REG) \
Assert(pCtx->REG.fFlags & CPUMSELREG_FLAGS_VALID); \
Assert(pCtx->REG.ValidSel == pCtx->REG.Sel); \
state->REG.charge( Segment{ .sel = pCtx->REG.Sel, \
.ar = sel_ar_conv_to_genode(pCtx->REG.Attr.u ? : VMCS_SEG_UNUSABLE), \
.limit = pCtx->REG.u32Limit, \
.base = pCtx->REG.u64Base });
static inline bool vmx_load_state(Genode::Vcpu_state * state, VM * pVM, PVMCPU pVCpu)
{
PCPUMCTX pCtx = CPUMQueryGuestCtxPtr(pVCpu);
typedef Genode::Vcpu_state::Segment Segment;
GENODE_WRITE_SELREG(es);
GENODE_WRITE_SELREG(ds);
GENODE_WRITE_SELREG(fs);
GENODE_WRITE_SELREG(gs);
GENODE_WRITE_SELREG(cs);
GENODE_WRITE_SELREG(ss);
/* ldtr */
if (pCtx->ldtr.Sel == 0) {
state->ldtr.charge(Segment { .sel = 0,
.ar = sel_ar_conv_to_genode(0x82),
.limit = 0,
.base = 0 });
} else {
state->ldtr.charge(Segment { .sel = pCtx->ldtr.Sel,
.ar = sel_ar_conv_to_genode(pCtx->ldtr.Attr.u),
.limit = pCtx->ldtr.u32Limit,
.base = pCtx->ldtr.u64Base });
}
/* tr */
state->tr.charge(Segment { .sel = pCtx->tr.Sel,
.ar = sel_ar_conv_to_genode(pCtx->tr.Attr.u),
.limit = pCtx->tr.u32Limit,
.base = pCtx->tr.u64Base });
return true;
}
#undef GENODE_WRITE_SELREG
#endif /* _VIRTUALBOX__VMX_H_ */

View File

@ -84,11 +84,6 @@ usb_hid_reconnect
vbox5_genode_usb_hid_raw
vbox5_ubuntu_16_04_32
vbox5_ubuntu_16_04_64
vbox5_vm_ubuntu_16_04_32
vbox5_vm_ubuntu_16_04_64
vbox5_vm_win10_64
vbox5_vm_win7_32
vbox5_vm_win7_64
vbox5_win10_64
vbox5_win7_32
vbox5_win7_64