mirror of
https://github.com/genodelabs/genode.git
synced 2024-12-24 07:46:42 +00:00
parent
17a140db3d
commit
484bde4b4b
@ -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 =
|
@ -1,2 +0,0 @@
|
||||
|
||||
VirtualBox runtime for hosting a large VM in the Sculpt scenario
|
@ -1,10 +0,0 @@
|
||||
_/src/vbox5
|
||||
_/src/libc
|
||||
_/src/init
|
||||
_/src/posix
|
||||
_/src/zlib
|
||||
_/src/libiconv
|
||||
_/src/libyuv
|
||||
_/src/stdcxx
|
||||
_/src/vfs
|
||||
_/src/jpeg
|
@ -1 +0,0 @@
|
||||
2023-08-21 464b0638d93864d8748bfa61e6472f21d6f26788
|
@ -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>
|
@ -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
|
||||
|
@ -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" > $@
|
||||
|
@ -1 +0,0 @@
|
||||
2023-08-21 8bc399184344e122bbf80d7130e42fe63f91343c
|
@ -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
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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>
|
||||
|
@ -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"
|
||||
}
|
||||
set virtualbox_binary "virtualbox5-nova"
|
||||
|
||||
create_boot_directory
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
@ -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_ */
|
@ -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 =
|
@ -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 Developer’s 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_ */
|
@ -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_ */
|
@ -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_ */
|
@ -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_ */
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user