diff --git a/libports/ports/libc.mk b/libports/ports/libc.mk
index 915f43003b..cc5f2f7e75 100644
--- a/libports/ports/libc.mk
+++ b/libports/ports/libc.mk
@@ -310,6 +310,7 @@ LIBC_IMPORT_INCLUDES += include/libc-i386/machine/_types.h \
include/libc-i386/machine/param.h \
include/libc-i386/machine/vm.h \
include/libc-i386/machine/specialreg.h \
+ include/libc-i386/machine/npx.h \
include/libc-i386/stdarg.h \
include/libc-i386/float.h
@@ -326,6 +327,7 @@ LIBC_IMPORT_INCLUDES += include/libc-amd64/machine/_types.h \
include/libc-amd64/machine/param.h \
include/libc-amd64/machine/vm.h \
include/libc-amd64/machine/specialreg.h \
+ include/libc-amd64/machine/fpu.h \
include/libc-amd64/stdarg.h \
include/libc-amd64/float.h
diff --git a/ports/lib/import/import-virtualbox_libc_support.mk b/ports/lib/import/import-virtualbox_libc_support.mk
new file mode 100644
index 0000000000..6981d3ed54
--- /dev/null
+++ b/ports/lib/import/import-virtualbox_libc_support.mk
@@ -0,0 +1 @@
+include $(call select_from_repositories,lib/import/import-libc.mk)
diff --git a/ports/lib/mk/foc/virtualbox-hwaccl.mk b/ports/lib/mk/foc/virtualbox-hwaccl.mk
new file mode 100644
index 0000000000..087fd10da4
--- /dev/null
+++ b/ports/lib/mk/foc/virtualbox-hwaccl.mk
@@ -0,0 +1,8 @@
+include $(REP_DIR)/lib/mk/virtualbox-common.inc
+
+SRC_CC = sup.cc
+
+INC_DIR += $(call select_from_repositories,src/lib/libc)
+INC_DIR += $(REP_DIR)/src/virtualbox
+
+vpath sup.cc $(REP_DIR)/src/virtualbox/accloff/
diff --git a/ports/lib/mk/linux/virtualbox-hwaccl.mk b/ports/lib/mk/linux/virtualbox-hwaccl.mk
new file mode 100644
index 0000000000..087fd10da4
--- /dev/null
+++ b/ports/lib/mk/linux/virtualbox-hwaccl.mk
@@ -0,0 +1,8 @@
+include $(REP_DIR)/lib/mk/virtualbox-common.inc
+
+SRC_CC = sup.cc
+
+INC_DIR += $(call select_from_repositories,src/lib/libc)
+INC_DIR += $(REP_DIR)/src/virtualbox
+
+vpath sup.cc $(REP_DIR)/src/virtualbox/accloff/
diff --git a/ports/lib/mk/nova/virtualbox-hwaccl.mk b/ports/lib/mk/nova/virtualbox-hwaccl.mk
new file mode 100644
index 0000000000..e908edddbe
--- /dev/null
+++ b/ports/lib/mk/nova/virtualbox-hwaccl.mk
@@ -0,0 +1,10 @@
+include $(REP_DIR)/lib/mk/virtualbox-common.inc
+
+SRC_CC = sup.cc
+
+INC_DIR += $(call select_from_repositories,src/lib/libc)
+
+INC_DIR += $(VBOX_DIR)/VMM/include
+INC_DIR += $(REP_DIR)/src/virtualbox
+
+vpath sup.cc $(REP_DIR)/src/virtualbox/nova/
diff --git a/ports/lib/mk/okl4/virtualbox-hwaccl.mk b/ports/lib/mk/okl4/virtualbox-hwaccl.mk
new file mode 100644
index 0000000000..087fd10da4
--- /dev/null
+++ b/ports/lib/mk/okl4/virtualbox-hwaccl.mk
@@ -0,0 +1,8 @@
+include $(REP_DIR)/lib/mk/virtualbox-common.inc
+
+SRC_CC = sup.cc
+
+INC_DIR += $(call select_from_repositories,src/lib/libc)
+INC_DIR += $(REP_DIR)/src/virtualbox
+
+vpath sup.cc $(REP_DIR)/src/virtualbox/accloff/
diff --git a/ports/lib/mk/pistachio/virtualbox-hwaccl.mk b/ports/lib/mk/pistachio/virtualbox-hwaccl.mk
new file mode 100644
index 0000000000..087fd10da4
--- /dev/null
+++ b/ports/lib/mk/pistachio/virtualbox-hwaccl.mk
@@ -0,0 +1,8 @@
+include $(REP_DIR)/lib/mk/virtualbox-common.inc
+
+SRC_CC = sup.cc
+
+INC_DIR += $(call select_from_repositories,src/lib/libc)
+INC_DIR += $(REP_DIR)/src/virtualbox
+
+vpath sup.cc $(REP_DIR)/src/virtualbox/accloff/
diff --git a/ports/lib/mk/virtualbox-bios.mk b/ports/lib/mk/virtualbox-bios.mk
new file mode 100644
index 0000000000..a4d3d68523
--- /dev/null
+++ b/ports/lib/mk/virtualbox-bios.mk
@@ -0,0 +1,37 @@
+include $(REP_DIR)/lib/mk/virtualbox-common.inc
+
+ifeq ($(shell which yasm),)
+REQUIRES += installation_of_yasm
+endif
+
+SRC_O += VBoxPcBiosBin.o VBoxVgaBiosBin.o VBoxBiosLogoBin.o
+
+VBox%Bin.o : VBox%Bin.rom
+ $(MSG_CONVERT)$@
+ $(VERBOSE)echo ".global g_ab$*Binary, g_cb$*Binary;" \
+ ".data;" \
+ "g_cb$*Binary:; .long g_ab$*BinaryEnd - g_ab$*Binary;" \
+ ".align 4096;" \
+ "g_ab$*Binary:; .incbin \"$<\";" \
+ "g_ab$*BinaryEnd:;" | \
+ $(AS) $(AS_OPT) -f -o $@ -
+
+VBoxPcBiosBin.rom: Devices/PC/BIOS/VBoxBiosAlternative.asm
+ $(MSG_ASSEM)
+ $(VERBOSE)yasm -f bin -o $@ $<
+
+VBoxVgaBiosBin.rom: Devices/Graphics/BIOS/VBoxVgaBiosAlternative.asm
+ $(MSG_ASSEM)
+ $(VERBOSE)yasm -f bin -o $@ $<
+
+VBoxBiosLogoBin.o: Devices/Graphics/BIOS/ose_logo.bmp
+ $(MSG_CONVERT)$@
+ $(VERBOSE)echo ".global g_abVgaDefBiosLogo, g_cbVgaDefBiosLogo;" \
+ ".data;" \
+ "g_cbVgaDefBiosLogo:; .long g_abVgaDefBiosLogoEnd - g_abVgaDefBiosLogo;" \
+ ".align 4096;" \
+ "g_abVgaDefBiosLogo:; .incbin \"$<\";" \
+ "g_abVgaDefBiosLogoEnd:;" | \
+ $(AS) $(AS_OPT) -f -o $@ -
+
+vpath %.bmp $(VBOX_DIR)
diff --git a/ports/lib/mk/virtualbox-common.inc b/ports/lib/mk/virtualbox-common.inc
new file mode 100644
index 0000000000..23a46df17d
--- /dev/null
+++ b/ports/lib/mk/virtualbox-common.inc
@@ -0,0 +1,66 @@
+VBOX_MACH := $(filter $(SPECS), x86_32 x86_64)
+
+VBOX_MACH_CC_OPT_x86_32 = -DRT_ARCH_X86 -D__X86__ -DHC_ARCH_BITS=32
+VBOX_MACH_ASM_OPT_x86_32 = -f elf32
+VBOX_MACH_CC_OPT_x86_64 = -DRT_ARCH_AMD64 -D__AMD64__ -DHC_ARCH_BITS=64
+VBOX_MACH_ASM_OPT_x86_64 = -f elf64
+
+include $(REP_DIR)/ports/virtualbox.inc
+
+ifeq ($(shell which yasm),)
+REQUIRES += installation_of_yasm
+REQUIRES += installation_of_iasl
+endif
+
+VIRTUALBOX_DIR = $(REP_DIR)/contrib/$(VIRTUALBOX)
+VBOX_DIR = $(VIRTUALBOX_DIR)/src/VBox
+
+VBOX_CC_OPT += -DIN_RING3 -DVBOX -DVBOX_OSE \
+ -DGC_ARCH_BITS=64 \
+ -D_FILE_OFFSET_BITS=64 -DLOG_ENABLED
+
+VBOX_CC_OPT += $(VBOX_MACH_CC_OPT_$(VBOX_MACH))
+
+# Required if on a 32bit host 64bit VMs should be executed
+# VBOX_CC_OPT += -DVBOX_WITH_64_BITS_GUESTS
+
+VBOX_CC_OPT += -DIN_SUP_R3 -DIN_VMM_R3
+
+# we use the libc headers from FreeBSD
+VBOX_CC_OPT += -DRT_OS_FREEBSD
+
+VBOX_CC_OPT += -DVBOX_WITH_REM
+
+VBOX_CC_OPT += -DVBOXBFE_WITHOUT_COM
+VBOX_CC_OPT += -DVBOX_WITHOUT_TESTING_FEATURES
+
+VBOX_CC_OPT += -DUSE_SDL
+
+VBOX_CC_OPT += -DRTLOG_REL_ENABLED -DRT_STRICT -DVBOX_STRICT
+
+VBOX_CC_OPT += -DVBOX_VERSION_MAJOR=$(VIRTUALBOX_VERSION_MAJOR) \
+ -DVBOX_VERSION_MINOR=$(VIRTUALBOX_VERSION_MINOR) \
+ -DVBOX_VERSION_BUILD=$(VIRTUALBOX_VERSION_BUILD)
+
+VBOX_CC_OPT += -DVBOX_HDD_NO_DYNAMIC_BACKENDS
+
+CC_WARN += -Wno-trigraphs
+
+CC_OPT += $(VBOX_CC_OPT)
+
+LIBS += virtualbox_libc_support
+
+INC_DIR += $(REP_DIR)/src/virtualbox/include
+INC_DIR += $(VIRTUALBOX_DIR)/include
+INC_DIR += $(VBOX_DIR)/Devices/build
+
+vpath %.cpp $(VBOX_DIR)
+vpath %.c $(VBOX_DIR)
+vpath %.asm $(VBOX_DIR)
+
+%.o: %.asm
+ $(MSG_ASSEM)$@
+ $(VERBOSE)yasm $(VBOX_MACH_ASM_OPT_$(VBOX_MACH)) -DASM_FORMAT_ELF -D__YASM__ \
+ $(addprefix -I,$(INC_DIR)) $(VBOX_CC_OPT) -o $@ $<
+
+# vi: set ft=make :
diff --git a/ports/lib/mk/virtualbox-devices.mk b/ports/lib/mk/virtualbox-devices.mk
new file mode 100644
index 0000000000..b9b7c29efc
--- /dev/null
+++ b/ports/lib/mk/virtualbox-devices.mk
@@ -0,0 +1,77 @@
+include $(REP_DIR)/lib/mk/virtualbox-common.inc
+
+SRC_CC += Devices/PC/DevFwCommon.cpp
+SRC_CC += Devices/PC/DevPcBios.cpp
+SRC_CC += Devices/Bus/DevPCI.cpp
+SRC_CC += Devices/PC/DevACPI.cpp
+SRC_CC += Devices/PC/ACPI/VBoxAcpi.cpp
+SRC_C += Devices/PC/DevPcArch.c
+SRC_CC += Devices/Input/DevPS2.cpp
+SRC_CC += Devices/Input/PS2K.cpp
+SRC_CC += Devices/PC/DevPit-i8254.cpp
+SRC_CC += Devices/PC/DevPIC.cpp
+SRC_CC += Devices/PC/DevRTC.cpp
+SRC_CC += Devices/PC/DevDMA.cpp
+SRC_CC += Devices/PC/DevAPIC.cpp
+SRC_CC += Devices/Graphics/DevVGA.cpp
+SRC_CC += Devices/Graphics/DevVGA_VBVA.cpp
+SRC_CC += Devices/Graphics/DevVGA_VDMA.cpp
+SRC_CC += Devices/Graphics/HGSMI/HGSMIHost.cpp
+SRC_CC += Devices/Graphics/HGSMI/HGSMIHostHlp.cpp
+SRC_CC += Devices/Graphics/HGSMI/SHGSMIHost.cpp
+SRC_CC += Devices/Storage/DevATA.cpp
+SRC_CC += Devices/Storage/Debug.cpp
+SRC_CC += Devices/Storage/fdc.c
+SRC_CC += Devices/Storage/DrvRawImage.cpp
+SRC_CC += Devices/Network/DevPCNet.cpp
+SRC_CC += Devices/VMMDev/VMMDev.cpp
+SRC_CC += GuestHost/HGSMI/HGSMICommon.cpp
+SRC_CC += Devices/Serial/DevSerial.cpp
+SRC_CC += Devices/PC/DevIoApic.cpp
+
+
+INC_DIR += $(VBOX_DIR)/Devices/build
+INC_DIR += $(VBOX_DIR)/Devices/Bus
+
+CC_WARN += -Wno-unused-but-set-variable
+
+#
+# Definitions needed to compile DevVGA.cpp
+#
+# VBOX_WITH_VDMA is needed because otherwise, the alignment of the
+# VGASTATE::lock member would violate the assertion
+# '!((uintptr_t)pvSample & 7)' in 'stamR3RegisterU'.
+#
+CC_OPT += -DVBOX_WITH_HGSMI -DVBOX_WITH_WDDM -DVBOX_WITH_VDMA
+
+Devices/Graphics/DevVGA.cpp: vbetables.h
+
+vbetables.h: vbetables-gen
+ $(MSG_CONVERT)$@
+ $(VERBOSE)./$^ > $@
+
+vbetables-gen: Devices/Graphics/BIOS/vbetables-gen.c
+ $(MSG_BUILD)$@
+ $(VERBOSE)g++ $(VBOX_CC_OPT) $(addprefix -I,$(INC_DIR)) -o $@ $^
+
+
+
+Devices/PC/ACPI/VBoxAcpi.cpp: vboxaml.hex vboxssdt-standard.hex vboxssdt-cpuhotplug.hex
+
+vboxaml.hex: vbox.dsl
+ iasl -tc -vs -p $@ $^
+
+vboxssdt-standard.hex: vbox-standard.dsl
+ iasl -tc -vs -p $@ $^ && \
+ mv $@ $@.tmp && \
+ sed "s/AmlCode/AmlCodeSsdtStandard/g" <$@.tmp >$@ && \
+ rm $@.tmp
+
+vboxssdt-cpuhotplug.hex: vbox-cpuhotplug.dsl
+ gcc -E -P -x c -o $@.pre $< && \
+ iasl -tc -vs -p $@ $@.pre && \
+ mv $@ $@.tmp && \
+ sed "s/AmlCode/AmlCodeSsdtCpuHotPlug/g" <$@.tmp >$@ && \
+ rm $@.tmp $@.pre
+
+vpath %.dsl $(VBOX_DIR)/Devices/PC
diff --git a/ports/lib/mk/virtualbox-dis.mk b/ports/lib/mk/virtualbox-dis.mk
new file mode 100644
index 0000000000..8e54e6a550
--- /dev/null
+++ b/ports/lib/mk/virtualbox-dis.mk
@@ -0,0 +1,15 @@
+include $(REP_DIR)/lib/mk/virtualbox-common.inc
+
+SRC_CC += VMM/VMMR3/DBGFAddr.cpp
+SRC_CC += VMM/VMMR3/DBGFDisas.cpp
+
+SRC_CC += Disassembler/DisasmCore.cpp
+SRC_CC += Disassembler/DisasmTables.cpp
+SRC_CC += Disassembler/DisasmReg.cpp
+SRC_CC += Disassembler/DisasmTablesX64.cpp
+SRC_CC += Disassembler/DisasmFormatYasm.cpp
+SRC_CC += Disassembler/DisasmFormatBytes.cpp
+
+INC_DIR += $(VBOX_DIR)/VMM/include
+
+CC_OPT += -DVBOX_IN_VMM
diff --git a/ports/lib/mk/virtualbox-drivers.mk b/ports/lib/mk/virtualbox-drivers.mk
new file mode 100644
index 0000000000..a736dad793
--- /dev/null
+++ b/ports/lib/mk/virtualbox-drivers.mk
@@ -0,0 +1,16 @@
+include $(REP_DIR)/lib/mk/virtualbox-common.inc
+
+SRC_CC += Devices/Input/DrvKeyboardQueue.cpp
+SRC_CC += Devices/Input/DrvMouseQueue.cpp
+SRC_CC += Devices/Storage/DrvBlock.cpp
+SRC_CC += Devices/Storage/DrvMediaISO.cpp
+SRC_CC += Devices/Storage/DrvVD.cpp
+SRC_CC += Devices/PC/DrvACPI.cpp
+SRC_CC += Devices/Serial/DrvChar.cpp
+SRC_CC += Devices/Serial/DrvRawFile.cpp
+SRC_CC += Devices/Serial/DrvHostSerial.cpp
+SRC_CC += Main/src-client/MouseImpl.cpp
+
+# includes needed by 'MouseImpl.cpp'
+INC_DIR += $(VBOX_DIR)/Main/include
+INC_DIR += $(VBOX_DIR)/Frontends/VBoxBFE
diff --git a/ports/lib/mk/virtualbox-liblzf.mk b/ports/lib/mk/virtualbox-liblzf.mk
new file mode 100644
index 0000000000..9c5a092c79
--- /dev/null
+++ b/ports/lib/mk/virtualbox-liblzf.mk
@@ -0,0 +1,8 @@
+include $(REP_DIR)/lib/mk/virtualbox-common.inc
+
+LIBLZF_DIR = $(VIRTUALBOX_DIR)/src/libs/liblzf-3.4
+INC_DIR += $(LIBLZF_DIR)
+CC_OPT += -DULTRA_FAST=1 -DHLOG=12 -DSTRICT_ALIGN=0 -DPIC
+SRC_C = lzf_c.c lzf_d.c
+
+vpath % $(LIBLZF_DIR)
diff --git a/ports/lib/mk/virtualbox-recompiler.mk b/ports/lib/mk/virtualbox-recompiler.mk
new file mode 100644
index 0000000000..5cc02308c6
--- /dev/null
+++ b/ports/lib/mk/virtualbox-recompiler.mk
@@ -0,0 +1,29 @@
+include $(REP_DIR)/lib/mk/virtualbox-common.inc
+
+RECOMPILER_DIR = $(VIRTUALBOX_DIR)/src/recompiler
+
+RECOMPILER_SRC_C = cpu-exec.c cutils.c exec.c host-utils.c tcg-runtime.c \
+ translate-all.c VBoxRecompiler.c \
+ tcg/tcg-dyngen.c tcg/tcg.c \
+ fpu/softfloat-native.c \
+ target-i386/helper.c target-i386/op_helper.c \
+ target-i386/translate.c
+
+SRC_C = $(addprefix recompiler/,$(RECOMPILER_SRC_C))
+
+INC_DIR += $(VBOX_DIR)/VMM/include
+INC_DIR += $(RECOMPILER_DIR)/Sun/crt
+INC_DIR += $(RECOMPILER_DIR)/Sun
+INC_DIR += $(RECOMPILER_DIR)/target-i386
+INC_DIR += $(RECOMPILER_DIR)/tcg
+INC_DIR += $(RECOMPILER_DIR)/tcg/i386
+INC_DIR += $(RECOMPILER_DIR)/fpu
+INC_DIR += $(RECOMPILER_DIR)
+
+CC_OPT += -DIN_REM_R3 \
+ -DREM_INCLUDE_CPU_H -DNEED_CPU_H -DLOG_USE_C99 -D_GNU_SOURCE
+
+CC_WARN += -Wno-unused-but-set-variable]
+
+vpath %.cpp $(VIRTUALBOX_DIR)/src
+vpath %.c $(VIRTUALBOX_DIR)/src
diff --git a/ports/lib/mk/virtualbox-runtime.mk b/ports/lib/mk/virtualbox-runtime.mk
new file mode 100644
index 0000000000..492dbd6f78
--- /dev/null
+++ b/ports/lib/mk/virtualbox-runtime.mk
@@ -0,0 +1,119 @@
+include $(REP_DIR)/lib/mk/virtualbox-common.inc
+
+INC_DIR += $(VBOX_DIR)/Runtime/include
+
+INC_DIR += $(VIRTUALBOX_DIR)/src/libs/liblzf-3.4
+INC_DIR += $(VIRTUALBOX_DIR)/src/libs/zlib-1.2.6
+
+GENERIC_SRC_CC = $(notdir $(wildcard $(VBOX_DIR)/Runtime/generic/*.cpp))
+
+FILTERED_OUT_SRC_CC = RTLogDefaultInit-generic.cpp \
+ RTTimeLocalExplode-generic.cpp \
+ semrw-lockless-generic.cpp \
+ tls-generic.cpp \
+ RTSemEventMultiWait-2-ex-generic.cpp \
+ RTLogWriteStdErr-generic.cpp \
+ RTLogWriteStdOut-generic.cpp \
+ RTMpGetDescription-generic-stub.cpp \
+ RTSemEventWait-2-ex-generic.cpp \
+ RTSemEventWait-generic.cpp \
+ RTSemEventWaitNoResume-2-ex-generic.cpp \
+ RTFileExists-generic.cpp \
+ RTSemMutexRequest-generic.cpp \
+ RTSemMutexRequestDebug-generic.cpp
+
+CC_WARN += -Wno-unused-variable
+
+SRC_CC += Runtime/common/log/logrel.cpp \
+ Runtime/r3/init.cpp \
+ Runtime/common/misc/thread.cpp \
+ $(addprefix Runtime/generic/,$(filter-out $(FILTERED_OUT_SRC_CC), $(GENERIC_SRC_CC)))
+
+SRC_CC += Runtime/common/err/RTErrConvertFromErrno.cpp
+SRC_CC += Runtime/common/alloc/memcache.cpp
+SRC_CC += Runtime/common/checksum/md5.cpp
+SRC_CC += Runtime/common/log/log.cpp
+SRC_CC += Runtime/common/log/log.cpp
+SRC_CC += Runtime/common/log/logellipsis.cpp
+SRC_CC += Runtime/common/log/logrelellipsis.cpp
+SRC_CC += Runtime/common/log/logformat.cpp
+SRC_CC += Runtime/common/misc/assert.cpp
+SRC_CC += Runtime/common/misc/lockvalidator.cpp
+SRC_CC += Runtime/common/misc/once.cpp
+SRC_CC += Runtime/common/misc/sg.cpp
+SRC_CC += Runtime/common/misc/term.cpp
+SRC_CC += Runtime/common/misc/RTAssertMsg1Weak.cpp
+SRC_CC += Runtime/common/misc/RTAssertMsg2AddWeak.cpp
+SRC_CC += Runtime/common/misc/RTAssertMsg2AddWeakV.cpp
+SRC_CC += Runtime/common/misc/RTAssertMsg2Weak.cpp
+SRC_CC += Runtime/common/misc/RTAssertMsg2WeakV.cpp
+SRC_CC += Runtime/common/path/RTPathAbsDup.cpp
+SRC_CC += Runtime/common/path/RTPathCalcRelative.cpp
+SRC_CC += Runtime/common/path/RTPathExt.cpp
+SRC_CC += Runtime/common/path/RTPathFilename.cpp
+SRC_CC += Runtime/common/path/RTPathJoinA.cpp
+SRC_CC += Runtime/common/path/RTPathParse.cpp
+SRC_CC += Runtime/common/path/RTPathStripExt.cpp
+SRC_CC += Runtime/common/path/RTPathStripFilename.cpp
+SRC_CC += Runtime/common/path/RTPathStripTrailingSlash.cpp
+SRC_CC += Runtime/common/rand/rand.cpp
+SRC_CC += Runtime/common/rand/randadv.cpp
+SRC_CC += Runtime/common/rand/randparkmiller.cpp
+SRC_CC += Runtime/common/zip/zip.cpp
+SRC_CC += Runtime/common/string/base64.cpp
+SRC_CC += Runtime/common/string/RTStrCmp.cpp
+SRC_CC += Runtime/common/string/RTStrCopy.cpp
+SRC_CC += Runtime/common/string/RTStrCopyEx.cpp
+SRC_CC += Runtime/common/string/RTStrNCmp.cpp
+SRC_CC += Runtime/common/string/RTStrNLen.cpp
+SRC_CC += Runtime/common/string/simplepattern.cpp
+SRC_CC += Runtime/common/string/straprintf.cpp
+SRC_CC += Runtime/common/string/strformat.cpp
+SRC_CC += Runtime/common/string/strformatrt.cpp
+SRC_CC += Runtime/common/string/strformattype.cpp
+SRC_CC += Runtime/common/string/stringalloc.cpp
+SRC_CC += Runtime/common/string/strprintf.cpp
+SRC_CC += Runtime/common/string/strstrip.cpp
+SRC_CC += Runtime/common/string/strtonum.cpp
+SRC_CC += Runtime/common/string/unidata.cpp
+SRC_CC += Runtime/common/string/utf-16.cpp
+SRC_CC += Runtime/common/string/utf-8-case.cpp
+SRC_CC += Runtime/common/string/utf-8.cpp
+SRC_CC += Runtime/common/table/avlpv.cpp
+SRC_CC += Runtime/common/table/avlroioport.cpp
+SRC_CC += Runtime/common/table/avlrogcphys.cpp
+SRC_CC += Runtime/common/time/time.cpp
+SRC_CC += Runtime/common/time/timeprog.cpp
+SRC_CC += Runtime/common/time/timesup.cpp
+SRC_CC += Runtime/common/time/timesupref.cpp
+SRC_CC += Runtime/r3/alloc.cpp
+SRC_CC += Runtime/r3/fileio.cpp
+SRC_CC += Runtime/r3/path.cpp
+SRC_CC += Runtime/r3/generic/semspinmutex-r3-generic.cpp
+SRC_CC += Runtime/r3/posix/env-posix.cpp
+SRC_CC += Runtime/r3/posix/fileio-posix.cpp
+SRC_CC += Runtime/r3/posix/pipe-posix.cpp
+SRC_CC += Runtime/r3/posix/poll-posix.cpp
+SRC_CC += Runtime/r3/posix/RTTimeNow-posix.cpp
+SRC_CC += Runtime/r3/posix/semeventmulti-posix.cpp
+SRC_CC += Runtime/r3/posix/semevent-posix.cpp
+SRC_CC += Runtime/r3/posix/semmutex-posix.cpp
+SRC_CC += Runtime/r3/posix/thread2-posix.cpp
+SRC_CC += Runtime/r3/posix/thread-posix.cpp
+SRC_CC += Runtime/r3/posix/time-posix.cpp
+SRC_CC += Runtime/r3/posix/tls-posix.cpp
+SRC_CC += Runtime/r3/process.cpp
+SRC_CC += Runtime/r3/stream.cpp
+SRC_CC += Runtime/VBox/log-vbox.cpp
+SRC_S += Runtime/common/asm/ASMAtomicCmpXchgU64.asm
+SRC_S += Runtime/common/asm/ASMAtomicReadU64.asm
+SRC_S += Runtime/common/asm/ASMAtomicUoReadU64.as
+SRC_S += Runtime/common/asm/ASMAtomicXchgU64.asm
+
+SRC_CC += Runtime/common/err/errmsg.cpp
+Runtime/common/err/errmsg.cpp: errmsgdata.h
+errmsgdata.h: $(VIRTUALBOX_DIR)/include/iprt/err.h \
+ $(VIRTUALBOX_DIR)/include/VBox/err.h
+ $(MSG_CONVERT)$@
+ $(VERBOSE)sed -f $(VBOX_DIR)/Runtime/common/err/errmsg.sed $^ > $@
+
diff --git a/ports/lib/mk/virtualbox-storage.mk b/ports/lib/mk/virtualbox-storage.mk
new file mode 100644
index 0000000000..cebc44eeaf
--- /dev/null
+++ b/ports/lib/mk/virtualbox-storage.mk
@@ -0,0 +1,16 @@
+include $(REP_DIR)/lib/mk/virtualbox-common.inc
+
+SRC_CC += Storage/VCICache.cpp
+SRC_CC += Storage/VD.cpp
+SRC_CC += Storage/VMDK.cpp
+SRC_CC += Storage/DMG.cpp
+SRC_CC += Storage/ISCSI.cpp
+SRC_CC += Storage/Parallels.cpp
+SRC_CC += Storage/QCOW.cpp
+SRC_CC += Storage/QED.cpp
+SRC_CC += Storage/RAW.cpp
+SRC_CC += Storage/VD.cpp
+SRC_CC += Storage/VDI.cpp
+SRC_CC += Storage/VHD.cpp
+SRC_CC += Storage/VHDX.cpp
+SRC_CC += Storage/VMDK.cpp
diff --git a/ports/lib/mk/virtualbox-vmm.mk b/ports/lib/mk/virtualbox-vmm.mk
new file mode 100644
index 0000000000..33f241999b
--- /dev/null
+++ b/ports/lib/mk/virtualbox-vmm.mk
@@ -0,0 +1,76 @@
+include $(REP_DIR)/lib/mk/virtualbox-common.inc
+
+SRC_CC += VMM/VMMR3/VM.cpp
+SRC_CC += VMM/VMMAll/VMAll.cpp
+SRC_CC += VMM/VMMAll/VMMAll.cpp
+SRC_CC += VMM/VMMR3/VMM.cpp
+
+SRC_CC += VMM/VMMR3/STAM.cpp
+
+SRC_CC += VMM/VMMR3/SSM.cpp
+
+SRC_CC += VMM/VMMR3/PDM.cpp
+SRC_CC += VMM/VMMR3/PDMBlkCache.cpp
+SRC_CC += VMM/VMMR3/PDMDevice.cpp
+SRC_CC += VMM/VMMR3/PDMQueue.cpp
+SRC_CC += VMM/VMMR3/PDMCritSect.cpp
+SRC_CC += VMM/VMMAll/PDMAll.cpp
+SRC_CC += VMM/VMMAll/PDMAllQueue.cpp
+SRC_CC += VMM/VMMAll/PDMAllCritSect.cpp
+
+SRC_CC += VMM/VMMR3/TM.cpp
+SRC_CC += VMM/VMMAll/TMAll.cpp
+SRC_CC += VMM/VMMAll/TMAllVirtual.cpp
+SRC_CC += VMM/VMMAll/TMAllReal.cpp
+SRC_CC += VMM/VMMAll/TMAllCpu.cpp
+SRC_CC += VMM/VMMAll/TRPMAll.cpp
+
+SRC_CC += VMM/VMMR3/CFGM.cpp
+
+SRC_CC += VMM/VMMR3/PDMDevHlp.cpp
+SRC_CC += VMM/VMMR3/PDMDevMiscHlp.cpp
+SRC_CC += VMM/VMMR3/PDMDriver.cpp
+SRC_CC += VMM/VMMR3/PDMThread.cpp
+
+SRC_CC += VMM/VMMAll/CPUMAllRegs.cpp
+
+SRC_CC += VMM/VMMR3/VMEmt.cpp
+SRC_CC += VMM/VMMR3/VMReq.cpp
+
+SRC_CC += VMM/VMMR3/DBGFInfo.cpp
+
+SRC_CC += VMM/VMMR3/CPUM.cpp
+
+SRC_CC += VMM/VMMAll/EMAll.cpp
+SRC_CC += VMM/VMMR3/EM.cpp
+
+SRC_CC += VMM/VMMR3/TRPM.cpp
+SRC_CC += VMM/VMMAll/SELMAll.cpp
+
+SRC_CC += VMM/VMMAll/PATMAll.cpp
+SRC_CC += VMM/VMMR3/PATM.cpp
+SRC_CC += VMM/VMMR3/PATMPatch.cpp
+SRC_CC += VMM/VMMR3/PATMA.asm
+SRC_CC += VMM/VMMR3/PATMSSM.cpp
+SRC_CC += VMM/VMMR3/PATMGuest.cpp
+
+SRC_CC += VMM/VMMAll/CSAMAll.cpp
+SRC_CC += VMM/VMMR3/CSAM.cpp
+
+SRC_CC += VMM/VMMR3/EMHwaccm.cpp
+
+SRC_CC += VMM/VMMAll/REMAll.cpp
+
+CC_OPT += -DVBOX_IN_VMM
+
+# definitions needed by SSM.cpp
+CC_OPT += -DKBUILD_TYPE=\"debug\" \
+ -DKBUILD_TARGET=\"genode\" \
+ -DKBUILD_TARGET_ARCH=\"x86\"
+
+# definitions needed by VMMAll.cpp
+CC_OPT += -DVBOX_SVN_REV=~0
+
+INC_DIR += $(VBOX_DIR)/VMM/include
+
+CC_WARN += -Wno-unused-but-set-variable
diff --git a/ports/lib/mk/virtualbox-zlib.mk b/ports/lib/mk/virtualbox-zlib.mk
new file mode 100644
index 0000000000..bd7cd9d5b0
--- /dev/null
+++ b/ports/lib/mk/virtualbox-zlib.mk
@@ -0,0 +1,7 @@
+include $(REP_DIR)/lib/mk/virtualbox-common.inc
+
+ZLIB_DIR = $(VIRTUALBOX_DIR)/src/libs/zlib-1.2.6
+INC_DIR += $(ZLIB_DIR)
+SRC_C = $(notdir $(wildcard $(ZLIB_DIR)/*.c))
+
+vpath % $(ZLIB_DIR)
diff --git a/ports/lib/mk/virtualbox_libc_support.inc b/ports/lib/mk/virtualbox_libc_support.inc
new file mode 100644
index 0000000000..fe8b62f22a
--- /dev/null
+++ b/ports/lib/mk/virtualbox_libc_support.inc
@@ -0,0 +1,84 @@
+# FreeBSD libc code
+SRC_C += gen/ldexp.c
+SRC_C += gen/usleep.c
+SRC_C += stdio/ferror.c
+SRC_C += stdio/fflush.c
+SRC_C += stdio/fileno.c
+SRC_C += stdio/findfp.c
+SRC_C += stdio/stdio.c
+SRC_C += string/memchr.c
+SRC_C += string/strncmp.c
+
+# Genode libc code
+SRC_CC += libc/clock_gettime.cc
+SRC_CC += libc/nanosleep.cc
+SRC_CC += libc/file_operations.cc
+SRC_CC += libc/plugin_registry.cc
+SRC_CC += libc/fd_alloc.cc
+SRC_CC += libc/libc_mem_alloc.cc
+SRC_CC += libc/gettimeofday.cc
+SRC_CC += libc/plugin.cc
+SRC_CC += libc/select.cc
+
+# Genode terminal plugin
+SRC_CC += libc_terminal/plugin.cc
+
+# Genode fs plugin
+SRC_CC += libc_fs/plugin.cc
+SRC_CC += libc/pread_pwrite.cc
+
+# Genode lock pipe plugin (needed by VirtualBox "HostSerial" driver)
+SRC_CC += libc_lock_pipe/plugin.cc
+
+# Genode pthread code
+SRC_CC += pthread/semaphore.cc
+SRC_CC += pthread/thread.cc
+LIBS += timed_semaphore
+
+# setjmp/longjmp needed by recompiler
+LIBS += libc-setjmp
+
+INC_DIR += $(LIBC_REP_DIR)/src/lib/libc
+
+vpath %.cc $(LIBC_REP_DIR)/src/lib
+
+# FreeBSD libc FPU math
+FPU_SRC_C = $(wildcard $(LIBC_DIR)/msun/src/*.c) \
+ $(wildcard $(LIBC_DIR)/msun/ld80/*.c) \
+ $(wildcard $(LIBC_DIR)/msun/bsdsrc/*.c)
+SRC_C += $(filter-out e_rem_pio2.c e_rem_pio2f.c s_exp2l.c, $(notdir $(FPU_SRC_C)))
+
+vpath %.c $(LIBC_DIR)/msun/src
+vpath %.c $(LIBC_DIR)/msun/ld80
+vpath %.c $(LIBC_DIR)/msun/bsdsrc
+
+# Disable warnings for selected files, i.e., to suppress
+# 'is static but used in inline function which is not static'
+# messages
+CC_OPT_s_tanf = -w
+CC_OPT_s_tan = -w
+CC_OPT_s_sin = -w
+CC_OPT_s_cos = -w
+CC_OPT_s_cosf = -w
+CC_OPT_s_sinf = -w
+CC_OPT_k_cosf = -w
+CC_OPT_k_sinf = -w
+CC_OPT_k_tanf = -w
+
+# Work-around to get over doubly defined symbols produced by several sources
+# that include 'e_rem_pio2.c' and 'e_rem_pio2f.c'. To avoid symbol clashes,
+# we rename each occurrence by adding the basename of the compilation unit
+# as suffix. (copied from libm.mk)
+CC_OPT_s_sin += -D__ieee754_rem_pio2=__ieee754_rem_pio2_s_sin
+CC_OPT_s_cos += -D__ieee754_rem_pio2=__ieee754_rem_pio2_s_cos
+CC_OPT_s_tan += -D__ieee754_rem_pio2=__ieee754_rem_pio2_s_tan
+CC_OPT_s_sinf += -D__ieee754_rem_pio2f=__ieee754_rem_pio2f_s_sinf
+CC_OPT_s_sinf += -D__kernel_cosdf=__kernel_cosdf_sinf
+CC_OPT_s_cosf += -D__ieee754_rem_pio2f=__ieee754_rem_pio2f_s_cosf
+CC_OPT_s_cosf += -D__kernel_sindf=__kernel_sindf_cosf
+CC_OPT_s_tanf += -D__ieee754_rem_pio2f=__ieee754_rem_pio2f_s_tanf
+
+CC_OPT += -D__inline=inline
+INC_DIR += $(LIBC_DIR)/msun/src $(LIBC_DIR)/msun/ld80 $(LIBC_DIR)/msun/bsdsrc
+
+# vi: set ft=make :
diff --git a/ports/lib/mk/x86_32/virtualbox_libc_support.mk b/ports/lib/mk/x86_32/virtualbox_libc_support.mk
new file mode 100644
index 0000000000..9e77381a96
--- /dev/null
+++ b/ports/lib/mk/x86_32/virtualbox_libc_support.mk
@@ -0,0 +1,7 @@
+include $(REP_DIR)/lib/mk/seoul_libc_support.mk
+
+SRC_C += fenv.c
+
+vpath fenv.c $(LIBC_DIR)/msun/i387
+
+include $(REP_DIR)/lib/mk/virtualbox_libc_support.inc
diff --git a/ports/lib/mk/x86_64/virtualbox_libc_support.mk b/ports/lib/mk/x86_64/virtualbox_libc_support.mk
new file mode 100644
index 0000000000..7849cc9804
--- /dev/null
+++ b/ports/lib/mk/x86_64/virtualbox_libc_support.mk
@@ -0,0 +1,7 @@
+include $(REP_DIR)/lib/mk/seoul_libc_support.mk
+
+SRC_C += fenv.c
+
+vpath fenv.c $(LIBC_DIR)/msun/amd64
+
+include $(REP_DIR)/lib/mk/virtualbox_libc_support.inc
diff --git a/ports/ports/virtualbox.inc b/ports/ports/virtualbox.inc
new file mode 100644
index 0000000000..fd5cc38a42
--- /dev/null
+++ b/ports/ports/virtualbox.inc
@@ -0,0 +1,5 @@
+VIRTUALBOX_VERSION_MAJOR := 4
+VIRTUALBOX_VERSION_MINOR := 2
+VIRTUALBOX_VERSION_BUILD := 16
+
+VIRTUALBOX = virtualbox-$(VIRTUALBOX_VERSION_MAJOR).$(VIRTUALBOX_VERSION_MINOR).$(VIRTUALBOX_VERSION_BUILD)
diff --git a/ports/ports/virtualbox.mk b/ports/ports/virtualbox.mk
new file mode 100644
index 0000000000..a1e84e9f19
--- /dev/null
+++ b/ports/ports/virtualbox.mk
@@ -0,0 +1,81 @@
+include ports/virtualbox.inc
+
+VIRTUALBOX = virtualbox-4.2.16
+VIRTUALBOX_TBZ2 = VirtualBox-4.2.16.tar.bz2
+VIRTUALBOX_URL = http://download.virtualbox.org/virtualbox/4.2.16/$(VIRTUALBOX_TBZ2)
+VIRTUALBOX_MD5 = c4a36e2099a317f4715cd3861cdae238
+
+VIRTUALBOX_CONTENT = src/VBox/VMM \
+ src/VBox/Devices \
+ src/VBox/Runtime \
+ src/VBox/GuestHost/HGSMI \
+ src/VBox/Frontends/VBoxBFE \
+ src/VBox/Storage \
+ src/VBox/Disassembler \
+ src/recompiler \
+ src/VBox/Main/include/MouseImpl.h \
+ src/VBox/Main/include/ConsoleEvents.h \
+ src/VBox/Main/src-client/MouseImpl.cpp \
+ src/libs/zlib-1.2.6 \
+ src/libs/liblzf-3.4 \
+ include/VBox/vmm \
+ include/iprt \
+ $(addprefix include/VBox/,types.h cdefs.h hgcmsvc.h \
+ err.h dis.h disopcode.h \
+ log.h sup.h pci.h param.h \
+ ostypes.h VMMDev.h VMMDev2.h \
+ vusb.h dbg.h version.h \
+ VBoxVideo.h Hardware bioslogo.h \
+ scsi.h HGSMI) \
+ include/VBox/msi.h \
+ include/VBox/DevPCNet.h \
+ include/VBox/asmdefs.mac \
+ include/VBox/err.mac \
+ include/VBox/vd.h \
+ include/VBox/vd-ifs.h \
+ include/VBox/vd-plugin.h \
+ include/VBox/vd-ifs-internal.h \
+ include/VBox/vd-cache-plugin.h
+
+#
+# Interface to top-level prepare Makefile
+#
+PORTS += $(VIRTUALBOX)
+#
+# Check for tools
+#
+$(call check_tool,iasl)
+
+
+PATCHES := $(shell find $(CURDIR)/src/virtualbox/ -name "*.patch")
+
+
+apply_patches:
+ $(VERBOSE)set -e; for p in $(PATCHES); do \
+ echo $$p; \
+ patch -p0 -N -d $(CONTRIB_DIR)/$(VIRTUALBOX) -i $$p; \
+ done
+
+prepare:: $(CONTRIB_DIR)/$(VIRTUALBOX) apply_patches
+
+#
+# Port-specific local rules
+#
+$(DOWNLOAD_DIR)/$(VIRTUALBOX_TBZ2):
+ $(VERBOSE)wget -c -P $(DOWNLOAD_DIR) $(VIRTUALBOX_URL) && touch $@
+
+$(DOWNLOAD_DIR)/$(VIRTUALBOX_SIG):
+ $(VERBOSE)wget -c -P $(DOWNLOAD_DIR) $(VIRTUALBOX_URL_SIG) && touch $@
+
+$(DOWNLOAD_DIR)/$(VIRTUALBOX_TBZ2).verified: $(DOWNLOAD_DIR)/$(VIRTUALBOX_TBZ2)
+ $(VERBOSE)$(HASHVERIFIER) $(DOWNLOAD_DIR)/$(VIRTUALBOX_TBZ2) $(VIRTUALBOX_MD5) md5
+ $(VERBOSE)touch $@
+
+$(CONTRIB_DIR)/$(VIRTUALBOX): $(DOWNLOAD_DIR)/$(VIRTUALBOX_TBZ2).verified
+ $(VERBOSE)tar xfj $(<:.verified=) \
+ --transform "s/$(VIRTUALBOX_TBZ2:.tar.bz2=)/$(VIRTUALBOX)/" \
+ -C $(CONTRIB_DIR) \
+ $(addprefix $(VIRTUALBOX_TBZ2:.tar.bz2=)/,$(VIRTUALBOX_CONTENT)) && \
+ rm $(CONTRIB_DIR)/$(VIRTUALBOX)/src/VBox/Frontends/VBoxBFE/SDLConsole.h && \
+ rm $(CONTRIB_DIR)/$(VIRTUALBOX)/src/VBox/Frontends/VBoxBFE/SDLFramebuffer.h; \
+ if [ $$? -ne 0 ]; then rm -r $(CONTRIB_DIR)/$(VIRTUALBOX); exit 1; fi
diff --git a/ports/run/virtualbox.run b/ports/run/virtualbox.run
new file mode 100644
index 0000000000..95e66f192a
--- /dev/null
+++ b/ports/run/virtualbox.run
@@ -0,0 +1,123 @@
+set build_components {
+ core init virtualbox
+ server/ram_fs
+ drivers/input
+ drivers/framebuffer
+ drivers/timer
+}
+
+lappend_if [have_spec acpi] build_components drivers/acpi
+lappend_if [have_spec pci] build_components drivers/pci
+
+build $build_components
+
+create_boot_directory
+
+set config {
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ }
+
+append_if [have_spec acpi] config {
+
+
+
+
+
+
+
+
+
+
+
+ }
+
+append_if [expr ![have_spec acpi] && [have_spec pci]] config {
+
+
+
+ }
+
+append_if [have_spec ps2] config {
+
+
+
+ }
+
+append_if [have_spec framebuffer] config {
+
+
+
+ }
+
+append_if [have_spec sdl] config {
+
+
+
+
+
+
+ }
+
+append config {
+
+
+
+
+
+
+
+
+
+
+
+}
+
+install_config $config
+
+set boot_modules { core init timer virtualbox ram_fs test.iso }
+
+# platform-specific modules
+lappend_if [have_spec ps2] boot_modules ps2_drv
+lappend_if [have_spec acpi] boot_modules acpi_drv
+lappend_if [have_spec pci] boot_modules pci_drv
+lappend_if [have_spec framebuffer] boot_modules fb_drv
+lappend_if [have_spec linux] boot_modules fb_sdl
+lappend_if [have_spec nova] boot_modules pci_device_pd
+
+build_boot_image $boot_modules
+
+append qemu_args " -m 512 "
+append qemu_args " -cpu phenom "
+
+run_genode_until forever
diff --git a/ports/src/virtualbox/accloff/sup.cc b/ports/src/virtualbox/accloff/sup.cc
new file mode 100644
index 0000000000..4138c24e8b
--- /dev/null
+++ b/ports/src/virtualbox/accloff/sup.cc
@@ -0,0 +1,97 @@
+/*
+ * \brief Genode specific VirtualBox SUPLib supplements.
+ * File used by Genode platforms not supporting hardware
+ * virtualisation features.
+ * \author Alexander Boettcher
+ * \date 2013-11-18
+ */
+
+/*
+ * Copyright (C) 2013 Genode Labs GmbH
+ *
+ * This file is distributed under the terms of the GNU General Public License
+ * version 2.
+ */
+
+/* Genode includes */
+#include
+#include
+
+/* VirtualBox includes */
+#include
+#include
+
+/* Genode's VirtualBox includes */
+#include "sup.h"
+#include "vmm_memory.h"
+
+/* VirtualBox SUPLib interface */
+
+int SUPR3QueryVTxSupported(void)
+{
+ return VERR_INTERNAL_ERROR;
+}
+
+int SUPR3CallVMMR0Fast(PVMR0 pVMR0, unsigned uOperation, VMCPUID idCpu)
+{
+ return VERR_INTERNAL_ERROR;
+}
+
+
+static Genode::Semaphore *r0_halt_sem()
+{
+ static Genode::Semaphore sem;
+ return &sem;
+}
+
+
+int SUPR3CallVMMR0Ex(PVMR0 pVMR0, VMCPUID idCpu, unsigned
+ uOperation, uint64_t u64Arg, PSUPVMMR0REQHDR pReqHdr)
+{
+ switch(uOperation)
+ {
+ case VMMR0_DO_GVMM_CREATE_VM:
+ genode_VMMR0_DO_GVMM_CREATE_VM(pReqHdr);
+ return VINF_SUCCESS;
+
+ case VMMR0_DO_GVMM_SCHED_HALT:
+ r0_halt_sem()->down();
+ return VINF_SUCCESS;
+
+ case VMMR0_DO_GVMM_SCHED_WAKE_UP:
+ r0_halt_sem()->up();
+ return VINF_SUCCESS;
+
+ case VMMR0_DO_VMMR0_INIT:
+ return VINF_SUCCESS;
+
+ case VMMR0_DO_GVMM_SCHED_POLL:
+ /* called by 'vmR3HaltGlobal1Halt' */
+ PDBG("SUPR3CallVMMR0Ex: VMMR0_DO_GVMM_SCHED_POLL");
+ return VINF_SUCCESS;
+
+ default:
+ PERR("SUPR3CallVMMR0Ex: unhandled uOperation %d", uOperation);
+ return VERR_GENERAL_FAILURE;
+ }
+}
+
+
+/**
+ * Dummies and unimplemented stuff.
+ */
+
+uint64_t genode_cpu_hz() {
+ return 1000000000ULL; /* XXX fixed 1GHz return value */
+}
+
+bool Vmm_memory::unmap_from_vm(RTGCPHYS GCPhys)
+{
+ PWRN("%s unimplemented", __func__);
+ return false;
+}
+
+extern "C" int pthread_yield() {
+ PWRN("%s unimplemented", __func__);
+ return 0;
+}
diff --git a/ports/src/virtualbox/acpi.patch b/ports/src/virtualbox/acpi.patch
new file mode 100644
index 0000000000..03a2cf2d03
--- /dev/null
+++ b/ports/src/virtualbox/acpi.patch
@@ -0,0 +1,37 @@
++++ src/VBox/Devices/PC/DevACPI.cpp
+@@ -438,7 +438,9 @@
+ uint32_t u32GPE0BLK; /**< port addr of gen-purp event 0 regs block */
+ uint32_t u32GPE1BLK; /**< port addr of gen-purp event 1 regs block */
+ uint8_t u8PM1EVTLEN; /**< bytes decoded by PM1a_EVT_BLK. >= 4 */
++#define ACPI_PM1_EVT_LEN 0x4
+ uint8_t u8PM1CTLLEN; /**< bytes decoded by PM1b_CNT_BLK. >= 2 */
++#define ACPI_PM1_CNT_LEN 0x2
+ uint8_t u8PM2CTLLEN; /**< bytes decoded by PM2_CNT_BLK. >= 1 or 0 */
+ uint8_t u8PMTMLEN; /**< bytes decoded by PM_TMR_BLK. ==4 */
+ uint8_t u8GPE0BLKLEN; /**< bytes decoded by GPE0_BLK. %2==0 */
+@@ -1842,10 +1844,10 @@
+ } while (0)
+ #define L (GPE0_BLK_LEN / 2)
+
+- R(PM1a_EVT_OFFSET+2, 1, acpiPM1aEnWrite, acpiPm1aEnRead, "ACPI PM1a Enable");
+- R(PM1a_EVT_OFFSET, 1, acpiPM1aStsWrite, acpiPm1aStsRead, "ACPI PM1a Status");
+- R(PM1a_CTL_OFFSET, 1, acpiPM1aCtlWrite, acpiPm1aCtlRead, "ACPI PM1a Control");
+- R(PM_TMR_OFFSET, 1, NULL, acpiPMTmrRead, "ACPI PM Timer");
++ R(PM1a_EVT_OFFSET+2, ACPI_PM1_EVT_LEN / 2, acpiPM1aEnWrite, acpiPm1aEnRead, "ACPI PM1a Enable");
++ R(PM1a_EVT_OFFSET, ACPI_PM1_EVT_LEN / 2, acpiPM1aStsWrite, acpiPm1aStsRead, "ACPI PM1a Status");
++ R(PM1a_CTL_OFFSET, ACPI_PM1_CNT_LEN, acpiPM1aCtlWrite, acpiPm1aCtlRead, "ACPI PM1a Control");
++ R(PM_TMR_OFFSET, 4, NULL, acpiPMTmrRead, "ACPI PM Timer");
+ R(GPE0_OFFSET + L, L, acpiGpe0EnWrite, acpiGpe0EnRead, "ACPI GPE0 Enable");
+ R(GPE0_OFFSET, L, acpiGpe0StsWrite, acpiGpe0StsRead, "ACPI GPE0 Status");
+ #undef L
+@@ -2189,8 +2191,8 @@
+ fadt.u32PMTMRBLK = RT_H2LE_U32(acpiCalcPmPort(pThis, PM_TMR_OFFSET));
+ fadt.u32GPE0BLK = RT_H2LE_U32(acpiCalcPmPort(pThis, GPE0_OFFSET));
+ fadt.u32GPE1BLK = RT_H2LE_U32(acpiCalcPmPort(pThis, GPE1_OFFSET));
+- fadt.u8PM1EVTLEN = 4;
+- fadt.u8PM1CTLLEN = 2;
++ fadt.u8PM1EVTLEN = ACPI_PM1_EVT_LEN;
++ fadt.u8PM1CTLLEN = ACPI_PM1_CNT_LEN;
+ fadt.u8PM2CTLLEN = 0;
+ fadt.u8PMTMLEN = 4;
+ fadt.u8GPE0BLKLEN = GPE0_BLK_LEN;
diff --git a/ports/src/virtualbox/acpi_drv.patch b/ports/src/virtualbox/acpi_drv.patch
new file mode 100644
index 0000000000..dc98e122ab
--- /dev/null
+++ b/ports/src/virtualbox/acpi_drv.patch
@@ -0,0 +1,9 @@
++++ src/VBox/Devices/PC/DrvACPI.cpp
+@@ -44,6 +44,7 @@
+ # include
+ #endif
+
++#undef RT_OS_FREEBSD
+ #ifdef RT_OS_FREEBSD
+ # include
+ # include
diff --git a/ports/src/virtualbox/acpi_more.patch b/ports/src/virtualbox/acpi_more.patch
new file mode 100644
index 0000000000..826700fe4f
--- /dev/null
+++ b/ports/src/virtualbox/acpi_more.patch
@@ -0,0 +1,21 @@
++++ src/VBox/Devices/PC/DevACPI.cpp
+@@ -3254,13 +3256,13 @@
+ } while (0)
+ R(SMI_CMD, 1, acpiSmiWrite, NULL, "ACPI SMI");
+ #ifdef DEBUG_ACPI
+- R(DEBUG_HEX, 1, acpiDhexWrite, NULL, "ACPI Debug hex");
+- R(DEBUG_CHR, 1, acpiDchrWrite, NULL, "ACPI Debug char");
++ R(DEBUG_HEX, 4, acpiDhexWrite, NULL, "ACPI Debug hex");
++// R(DEBUG_CHR, 1, acpiDchrWrite, NULL, "ACPI Debug char");
+ #endif
+- R(BAT_INDEX, 1, acpiBatIndexWrite, NULL, "ACPI Battery status index");
+- R(BAT_DATA, 1, NULL, acpiBatDataRead, "ACPI Battery status data");
+- R(SYSI_INDEX, 1, acpiSysInfoIndexWrite, NULL, "ACPI system info index");
+- R(SYSI_DATA, 1, acpiSysInfoDataWrite, acpiSysInfoDataRead, "ACPI system info data");
++ R(BAT_INDEX, 4, acpiBatIndexWrite, NULL, "ACPI Battery status index");
++ R(BAT_DATA, 4, NULL, acpiBatDataRead, "ACPI Battery status data");
++ R(SYSI_INDEX, 4, acpiSysInfoIndexWrite, NULL, "ACPI system info index");
++ R(SYSI_DATA, 4, acpiSysInfoDataWrite, acpiSysInfoDataRead, "ACPI system info data");
+ R(ACPI_RESET_BLK, 1, acpiResetWrite, NULL, "ACPI Reset");
+ #undef R
+
diff --git a/ports/src/virtualbox/bios_logo.patch b/ports/src/virtualbox/bios_logo.patch
new file mode 100644
index 0000000000..07e148b614
--- /dev/null
+++ b/ports/src/virtualbox/bios_logo.patch
@@ -0,0 +1,32 @@
++++ src/VBox/Devices/Graphics/DevVGA.cpp
+@@ -6024,10 +5984,10 @@
+ #endif /* VBOX_WITH_HGSMI */
+
+ #ifdef CONFIG_BOCHS_VBE
+- rc = PDMDevHlpIOPortRegister(pDevIns, 0x1ce, 1, NULL, vgaIOPortWriteVBEIndex, vgaIOPortReadVBEIndex, NULL, NULL, "VGA/VBE - Index");
++ rc = PDMDevHlpIOPortRegister(pDevIns, 0x1ce, 2, NULL, vgaIOPortWriteVBEIndex, vgaIOPortReadVBEIndex, NULL, NULL, "VGA/VBE - Index");
+ if (RT_FAILURE(rc))
+ return rc;
+- rc = PDMDevHlpIOPortRegister(pDevIns, 0x1cf, 1, NULL, vgaIOPortWriteVBEData, vgaIOPortReadVBEData, NULL, NULL, "VGA/VBE - Data");
++ rc = PDMDevHlpIOPortRegister(pDevIns, 0x1cf, 2, NULL, vgaIOPortWriteVBEData, vgaIOPortReadVBEData, NULL, NULL, "VGA/VBE - Data");
+ if (RT_FAILURE(rc))
+ return rc;
+ #endif /* CONFIG_BOCHS_VBE */
+@@ -6470,7 +6430,7 @@
+ /*
+ * Register I/O Port for the VBE BIOS Extra Data.
+ */
+- rc = PDMDevHlpIOPortRegister(pDevIns, VBE_EXTRA_PORT, 1, NULL, vbeIOPortWriteVBEExtra, vbeIOPortReadVBEExtra, NULL, NULL, "VBE BIOS Extra Data");
++ rc = PDMDevHlpIOPortRegister(pDevIns, VBE_EXTRA_PORT, 2, NULL, vbeIOPortWriteVBEExtra, vbeIOPortReadVBEExtra, NULL, NULL, "VBE BIOS Extra Data");
+ if (RT_FAILURE(rc))
+ return rc;
+ #endif /* VBE_NEW_DYN_LIST */
+@@ -6478,7 +6438,7 @@
+ /*
+ * Register I/O Port for the BIOS Logo.
+ */
+- rc = PDMDevHlpIOPortRegister(pDevIns, LOGO_IO_PORT, 1, NULL, vbeIOPortWriteCMDLogo, vbeIOPortReadCMDLogo, NULL, NULL, "BIOS Logo");
++ rc = PDMDevHlpIOPortRegister(pDevIns, LOGO_IO_PORT, 2, NULL, vbeIOPortWriteCMDLogo, vbeIOPortReadCMDLogo, NULL, NULL, "BIOS Logo");
+ if (RT_FAILURE(rc))
+ return rc;
+
diff --git a/ports/src/virtualbox/cxx_dummies.cc b/ports/src/virtualbox/cxx_dummies.cc
new file mode 100644
index 0000000000..317dfdd121
--- /dev/null
+++ b/ports/src/virtualbox/cxx_dummies.cc
@@ -0,0 +1,45 @@
+/*
+ * \brief Dummy implementations of symbols needed by VirtualBox
+ * \author Norman Feske
+ * \date 2013-08-22
+ */
+
+/*
+ * Copyright (C) 2013 Genode Labs GmbH
+ *
+ * This file is distributed under the terms of the GNU General Public License
+ * version 2.
+ */
+
+/* Genode includes */
+#include
+
+/* VirtualBox includes */
+#include
+
+#define CXX_DUMMY(retval, signature) \
+int signature { \
+ PDBG( #signature " called, not implemented"); \
+ for (;;); \
+ return retval; \
+}
+
+#define CHECKED_CXX_DUMMY(retval, signature) \
+int signature { \
+ PINF( #signature " called, not implemented"); \
+ return retval; \
+}
+
+CXX_DUMMY(-1, VMMR3InitCompleted(VM*, VMINITCOMPLETED))
+CXX_DUMMY(-1, VMMR3InitR0(VM*))
+CXX_DUMMY(-1, VMMR3InitRC(VM*))
+CXX_DUMMY(-1, VMMR3Init(VM*))
+CXX_DUMMY(-1, VMMR3Relocate(VM*, long long))
+CXX_DUMMY(-1, VMMR3Term(VM*))
+CXX_DUMMY(-1, PGMR3InitCompleted(VM*, VMINITCOMPLETED))
+CXX_DUMMY(-1, PGMNotifyNxeChanged(VMCPU*, bool))
+CXX_DUMMY(-1, VMMR3SendSipi(VM*, unsigned int, unsigned int))
+CXX_DUMMY(-1, VMMR3SendInitIpi(VM*, unsigned int))
+CXX_DUMMY(-1, VMMR3EmtRendezvousFF(VM*, VMCPU*))
+CXX_DUMMY(-1, VMMR3YieldStop(VM*))
+CXX_DUMMY(-1, VMMR3EmtRendezvousSetDisabled(VMCPU*, bool))
diff --git a/ports/src/virtualbox/devata.patch b/ports/src/virtualbox/devata.patch
new file mode 100644
index 0000000000..d12bbf2bb5
--- /dev/null
+++ b/ports/src/virtualbox/devata.patch
@@ -0,0 +1,23 @@
++++ src/VBox/Devices/Storage/DevATA.cpp 2014-01-28 15:13:14.903523393 +0100
+@@ -4596,9 +4596,9 @@
+
+ if ((u64ResetTimeStop - pCtl->u64ResetTime) >= 10)
+ {
+- LogRel(("PIIX3 ATA LUN#%d: Async I/O thread probably stuck in operation, interrupting\n", s->iLUN));
++ LogRel(("PIIX3 ATA LUN#%d: Async I/O thread probably stuck in operation, interrupting %llu %llu\n", s->iLUN, u64ResetTimeStop, pCtl->u64ResetTime));
+ pCtl->u64ResetTime = u64ResetTimeStop;
+- RTThreadPoke(pCtl->AsyncIOThread);
++// RTThreadPoke(pCtl->AsyncIOThread);
+ }
+ }
+ #endif
+@@ -4699,6 +4699,9 @@
+ /* Save the timestamp we started the reset. */
+ pCtl->u64ResetTime = RTTimeMilliTS();
+
++ LogRel(("PIIX3 ATA ------------------------------------ reset time %llu\n",
++ pCtl->u64ResetTime));
++
+ /* Issue the reset request now. */
+ ataAsyncIOPutRequest(pCtl, &g_ataResetARequest);
+ #else /* !IN_RING3 */
diff --git a/ports/src/virtualbox/devices.cc b/ports/src/virtualbox/devices.cc
new file mode 100644
index 0000000000..bd899fda57
--- /dev/null
+++ b/ports/src/virtualbox/devices.cc
@@ -0,0 +1,119 @@
+/*
+ * \brief VirtualBox device models
+ * \author Norman Feske
+ * \date 2013-08-20
+ */
+
+/*
+ * Copyright (C) 2013 Genode Labs GmbH
+ *
+ * This file is distributed under the terms of the GNU General Public License
+ * version 2.
+ */
+
+/* Genode includes */
+#include
+
+/* VirtualBox includes */
+#include
+#include
+
+
+extern "C" int VBoxDevicesRegister(PPDMDEVREGCB pCallbacks, uint32_t u32Version)
+{
+ PDBG("VBoxDevicesRegister called");
+
+ int rc = 0;
+
+ /* pcarch */
+ rc = pCallbacks->pfnRegister(pCallbacks, &g_DevicePcArch);
+ if (RT_FAILURE(rc))
+ return rc;
+
+ /* pcbios */
+ rc = pCallbacks->pfnRegister(pCallbacks, &g_DevicePcBios);
+ if (RT_FAILURE(rc))
+ return rc;
+
+ /* pci */
+ rc = pCallbacks->pfnRegister(pCallbacks, &g_DevicePCI);
+ if (RT_FAILURE(rc))
+ return rc;
+
+ /* pckbd */
+ rc = pCallbacks->pfnRegister(pCallbacks, &g_DevicePS2KeyboardMouse);
+ if (RT_FAILURE(rc))
+ return rc;
+
+ /* i8254 */
+ rc = pCallbacks->pfnRegister(pCallbacks, &g_DeviceI8254);
+ if (RT_FAILURE(rc))
+ return rc;
+
+ /* i8259 */
+ rc = pCallbacks->pfnRegister(pCallbacks, &g_DeviceI8259);
+ if (RT_FAILURE(rc))
+ return rc;
+
+ /* mc146818 */
+ rc = pCallbacks->pfnRegister(pCallbacks, &g_DeviceMC146818);
+ if (RT_FAILURE(rc))
+ return rc;
+
+ /* vga */
+ rc = pCallbacks->pfnRegister(pCallbacks, &g_DeviceVga);
+ if (RT_FAILURE(rc))
+ return rc;
+
+ /* piix3ide */
+ rc = pCallbacks->pfnRegister(pCallbacks, &g_DevicePIIX3IDE);
+ if (RT_FAILURE(rc))
+ return rc;
+
+ /* 8237A DMA */
+ rc = pCallbacks->pfnRegister(pCallbacks, &g_DeviceDMA);
+ if (RT_FAILURE(rc))
+ return rc;
+
+ /* Guest - VMM/Host communication */
+ rc = pCallbacks->pfnRegister(pCallbacks, &g_DeviceVMMDev);
+ if (RT_FAILURE(rc))
+ return rc;
+
+ /* ACPI missing */
+
+ /* APIC */
+ rc = pCallbacks->pfnRegister(pCallbacks, &g_DeviceAPIC);
+ if (RT_FAILURE(rc))
+ return rc;
+
+ /* i82078 */
+ rc = pCallbacks->pfnRegister(pCallbacks, &g_DeviceFloppyController);
+ if (RT_FAILURE(rc))
+ return rc;
+
+ /* Ethernet PCNet controller */
+ rc = pCallbacks->pfnRegister(pCallbacks, &g_DevicePCNet);
+ if (RT_FAILURE(rc))
+ return rc;
+
+ /* Serial device */
+ rc = pCallbacks->pfnRegister(pCallbacks, &g_DeviceSerialPort);
+ if (RT_FAILURE(rc))
+ return rc;
+
+ rc = pCallbacks->pfnRegister(pCallbacks, &g_DevicePCIBridge);
+ if (RT_FAILURE(rc))
+ return rc;
+
+ rc = pCallbacks->pfnRegister(pCallbacks, &g_DeviceACPI);
+ if (RT_FAILURE(rc))
+ return rc;
+
+ rc = pCallbacks->pfnRegister(pCallbacks, &g_DeviceIOAPIC);
+ if (RT_FAILURE(rc))
+ return rc;
+
+ return VINF_SUCCESS;
+}
+
diff --git a/ports/src/virtualbox/devpci.patch b/ports/src/virtualbox/devpci.patch
new file mode 100644
index 0000000000..ee6d8be953
--- /dev/null
+++ b/ports/src/virtualbox/devpci.patch
@@ -0,0 +1,10 @@
++++ src/VBox/Devices/Bus/DevPCI.cpp
+@@ -2279,7 +2280,7 @@
+ /*
+ * Register I/O ports and save state.
+ */
+- rc = PDMDevHlpIOPortRegister(pDevIns, 0x0cf8, 1, NULL, pciIOPortAddressWrite, pciIOPortAddressRead, NULL, NULL, "i440FX (PCI)");
++ rc = PDMDevHlpIOPortRegister(pDevIns, 0x0cf8, 4, NULL, pciIOPortAddressWrite, pciIOPortAddressRead, NULL, NULL, "i440FX (PCI)");
+ if (RT_FAILURE(rc))
+ return rc;
+ rc = PDMDevHlpIOPortRegister(pDevIns, 0x0cfc, 4, NULL, pciIOPortDataWrite, pciIOPortDataRead, NULL, NULL, "i440FX (PCI)");
diff --git a/ports/src/virtualbox/drivers.cc b/ports/src/virtualbox/drivers.cc
new file mode 100644
index 0000000000..7796cf036e
--- /dev/null
+++ b/ports/src/virtualbox/drivers.cc
@@ -0,0 +1,47 @@
+/*
+ * \brief VirtualBox host drivers
+ * \author Norman Feske
+ * \date 2013-08-20
+ */
+
+/*
+ * Copyright (C) 2013 Genode Labs GmbH
+ *
+ * This file is distributed under the terms of the GNU General Public License
+ * version 2.
+ */
+
+/* Genode includes */
+#include
+
+/* VirtualBox includes */
+#include
+
+
+extern "C" int VBoxDriversRegister(PCPDMDRVREGCB pCallbacks, uint32_t u32Version)
+{
+ PDBG("VBoxDriversRegister called");
+
+ PDMDRVREG const *drvs[] = {
+ &g_DrvKeyboardQueue,
+ &g_DrvMouseQueue,
+ &g_DrvBlock,
+ &g_DrvMediaISO,
+ &g_DrvACPI,
+ &g_DrvChar,
+ &g_DrvRawImage,
+ &g_DrvRawFile,
+ &g_DrvHostSerial,
+ &g_DrvVD,
+ 0
+ };
+
+ for (unsigned i = 0; drvs[i]; i++) {
+ int rc = pCallbacks->pfnRegister(pCallbacks, drvs[i]);
+ if (RT_FAILURE(rc))
+ return rc;
+ }
+
+ return VINF_SUCCESS;
+}
+
diff --git a/ports/src/virtualbox/dummies.cc b/ports/src/virtualbox/dummies.cc
new file mode 100644
index 0000000000..a0e27877ff
--- /dev/null
+++ b/ports/src/virtualbox/dummies.cc
@@ -0,0 +1,317 @@
+/*
+ * \brief Dummy implementations of symbols needed by VirtualBox
+ * \author Norman Feske
+ * \date 2013-08-22
+ */
+
+/*
+ * Copyright (C) 2013 Genode Labs GmbH
+ *
+ * This file is distributed under the terms of the GNU General Public License
+ * version 2.
+ */
+
+#include
+#include
+
+#include
+#include
+
+extern "C" {
+
+ typedef long DUMMY;
+
+#define DUMMY(retval, name) \
+DUMMY name(void) { \
+ PDBG( #name " called, not implemented, eip=%p", __builtin_return_address(0)); \
+ for (;;); \
+ return retval; \
+}
+
+#define CHECKED_DUMMY(retval, name) \
+DUMMY name(void) { \
+ PINF( #name " called, not implemented, eip=%p", __builtin_return_address(0)); \
+ return retval; \
+}
+
+CHECKED_DUMMY( 0, cpumR3DbgInit)
+CHECKED_DUMMY( 0, DBGFR3Init) /* debugger */
+DUMMY(-1, DBGFR3CoreWrite)
+CHECKED_DUMMY( 0, FTMR3Init) /* fault tolerance manager */
+CHECKED_DUMMY( 0, pdmR3LdrInitU) /* module loader of pluggable device manager */
+CHECKED_DUMMY( 0, PDMR3LdrLoadVMMR0U) /* pretend to have successfully loaded the r0 module */
+CHECKED_DUMMY( 0, pdmR3LoadR3U)
+CHECKED_DUMMY( 0, pthread_atfork)
+CHECKED_DUMMY( 0, pthread_attr_setdetachstate)
+CHECKED_DUMMY( 0, pthread_attr_setstacksize)
+CHECKED_DUMMY( 0, RTMemProtect)
+CHECKED_DUMMY( 0, SELMR3Init) /* selector manager - GDT handling */
+CHECKED_DUMMY( 0, sigfillset)
+CHECKED_DUMMY( 0, vmmR3SwitcherInit) /* world switcher */
+CHECKED_DUMMY(-1, atexit)
+CHECKED_DUMMY(-1, getpid)
+CHECKED_DUMMY(-1, pdmR3FileR3)
+CHECKED_DUMMY(-1, setlocale)
+CHECKED_DUMMY(-1, sigaddset)
+CHECKED_DUMMY(-1, sigemptyset)
+CHECKED_DUMMY(-1, siginterrupt)
+CHECKED_DUMMY(-1, sysctl)
+DUMMY( 0, RTErrCOMGet)
+void CPUMPushHyper() { } /* called by 'VMMR3InitRC', but we don't use GC */
+DUMMY(-1, DBGCRegisterCommands)
+DUMMY(-1, DBGFR3Event)
+DUMMY(-1, DBGFR3EventAssertion)
+DUMMY(-1, DBGFR3EventBreakpoint)
+DUMMY(-1, DBGFR3EventSrc)
+CHECKED_DUMMY( 0, DBGFR3EventSrcV)
+void DBGFR3Relocate() { }
+DUMMY(-1, DBGFR3Term)
+DUMMY(-1, DBGFR3VMMForcedAction)
+
+CHECKED_DUMMY(-4, DBGFR3AsSymbolByAddr) /* -4 == VERR_INVALID_HANDLE */
+
+DUMMY(-1, _flockfile)
+
+int FTMR3SetCheckpoint() { return -1; }
+DUMMY(-1, FTMR3Term)
+int FTMSetCheckpoint() { return 0; }
+DUMMY(-1, _funlockfile)
+DUMMY(-1, _fwalk)
+
+DUMMY(-1, HWACCMInvalidatePage)
+DUMMY(-1, HWACCMFlushTLB)
+DUMMY(-1, HWACCMR3EmulateIoBlock)
+DUMMY(-1, HWACCMR3PatchTprInstr)
+DUMMY(-1, HWACCMR3CheckError)
+DUMMY(-1, HWACCMR3RestartPendingIOInstr)
+void HWACCMR3Relocate() { }
+DUMMY(-1, HWACCMR3Reset)
+DUMMY(-1, HWACCMR3Term)
+DUMMY(-1, HWACMMR3EnablePatching)
+DUMMY(-1, HWACMMR3DisablePatching)
+
+CHECKED_DUMMY( 0, IEMR3Init) /* interpreted execution manager (seems to be just a skeleton) */
+void IEMR3Relocate() { }
+DUMMY(-1, IEMR3Term)
+
+DUMMY(-1, MMHyperR0ToCC)
+DUMMY(-1, MMHyperR0ToR3)
+DUMMY(-1, MMHyperRCToCC)
+DUMMY(-1, MMHyperRCToR3)
+CHECKED_DUMMY(0, MMHyperGetArea)
+
+DUMMY(-1, MMR3HeapAPrintfV)
+CHECKED_DUMMY( 0, MMR3HyperInitFinalize)
+CHECKED_DUMMY( 0, MMR3HyperSetGuard)
+DUMMY(-1, MMR3LockCall)
+DUMMY(-1, MMR3Term)
+DUMMY(-1, MMR3TermUVM)
+DUMMY(-1, PDMR3AsyncCompletionTemplateCreateDriver)
+DUMMY(-1, PDMR3LdrGetInterfaceSymbols)
+CHECKED_DUMMY( 0, PDMR3LdrRelocateU)
+DUMMY(-1, pdmR3LdrTermU)
+
+DUMMY(-1, PGMNotifyNxeChanged)
+DUMMY(-1, PGMPhysGCPtr2GCPhys)
+DUMMY(-1, PGMPhysSimpleReadGCPhys)
+DUMMY(-1, PGMPhysSimpleReadGCPtr)
+DUMMY(-1, PGMPhysSimpleWriteGCPtr)
+DUMMY(-1, PGMSyncCR3)
+
+CHECKED_DUMMY( 0, PGMR3CheckIntegrity)
+CHECKED_DUMMY( 0, PGMR3FinalizeMappings)
+CHECKED_DUMMY( 0, PGMR3InitCompleted)
+CHECKED_DUMMY( 0, PGMR3InitDynMap) /* reserve space for "dynamic mappings" */
+CHECKED_DUMMY( 0, PGMR3InitFinalize)
+
+DUMMY(-1, PGMR3SharedModuleCheckAll)
+DUMMY(-1, PGMR3SharedModuleUnregister)
+DUMMY(-1, PGMR3SharedModuleRegister)
+DUMMY(-1, PGMR3MappingsSize)
+DUMMY(-1, PGMR3MappingsUnfix)
+DUMMY(-1, PGMR3PhysChangeMemBalloon)
+DUMMY(-1, PGMR3MappingsFix)
+CHECKED_DUMMY( 0, PGMR3MappingsDisable)
+DUMMY(-1, PGMR3LockCall)
+DUMMY(-1, PGMR3PhysAllocateHandyPages)
+DUMMY(-1, PGMR3PhysAllocateLargeHandyPage)
+DUMMY(-1, PGMR3PhysChunkMap)
+DUMMY(-1, PGMR3PhysGCPhys2CCPtrExternal)
+DUMMY(-1, PGMR3PhysGCPhys2CCPtrReadOnlyExternal)
+DUMMY(-1, PGMR3PhysMMIO2Deregister)
+DUMMY(-1, PGMR3PhysMMIO2MapKernel)
+DUMMY(-1, PGMR3PhysReadU16)
+DUMMY(-1, PGMR3PhysReadU64)
+DUMMY(-1, PGMR3PhysRomProtect)
+DUMMY(-1, PGMR3PoolGrow)
+void PGMR3Relocate() {}
+DUMMY(-1, PGMR3ResetCpu)
+DUMMY(-1, PGMR3Term)
+
+DUMMY(-1, PGMPrefetchPage)
+DUMMY(-1, PGMGstGetPage)
+DUMMY(-1, PGMGstIsPagePresent)
+DUMMY(-1, PGMShwMakePageReadonly)
+DUMMY(-1, PGMShwMakePageNotPresent)
+DUMMY(-1, PGMPhysIsGCPhysNormal)
+DUMMY(-1, PGMHandlerVirtualChangeInvalidateCallback)
+DUMMY(-1, PGMSetLargePageUsage)
+DUMMY(-1, PGMPhysSimpleDirtyWriteGCPtr)
+DUMMY(-1, PGMGetShadowMode)
+DUMMY(-1, PGMGetHostMode)
+
+CHECKED_DUMMY(0, poll) /* needed by 'DrvHostSerial.cpp' */
+DUMMY(-1, printf)
+DUMMY(-1, pthread_key_delete)
+DUMMY(-1, reallocf)
+DUMMY(-1, RTCrc32);
+DUMMY(-1, RTCrc32Start)
+DUMMY(-1, RTCrc32Finish)
+DUMMY(-1, RTCrc32Process)
+DUMMY(-1, RTMemExecFree)
+DUMMY(-1, RTMemPageFree)
+DUMMY(-1, RTPathHasPath)
+DUMMY(-1, RTPathAppend)
+DUMMY(-1, rtPathPosixRename)
+CHECKED_DUMMY(0, rtProcInitExePath)
+DUMMY(-1, RTSemEventWaitEx)
+
+CHECKED_DUMMY( 0, SELMR3InitFinalize)
+void SELMR3Relocate() { }
+CHECKED_DUMMY( 0, SELMR3DisableMonitoring)
+DUMMY(-1, SELMR3Reset)
+DUMMY(-1, SELMR3Term)
+DUMMY(-1, SELMR3GetSelectorInfo)
+
+DUMMY(-1, libc_select_notify) /* needed for libc_terminal plugin */
+DUMMY(-1, strdup)
+DUMMY(-1, DISInstrToStrEx)
+CHECKED_DUMMY(-1, signal)
+
+DUMMY(-1, strcat)
+DUMMY(-1, strerror)
+DUMMY(-1, strpbrk)
+
+CHECKED_DUMMY( 0, SUPR3SetVMForFastIOCtl)
+DUMMY(-1, SUPR3HardenedLdrLoadPlugIn)
+DUMMY(-1, SUPR3Term)
+
+CHECKED_DUMMY(100000*10, SUPSemEventMultiGetResolution) /* called by 'vmR3HaltGlobal1Init' */
+CHECKED_DUMMY(-1, __swsetup)
+
+DUMMY(-1, VMMR3FatalDump)
+void vmmR3SwitcherRelocate() { }
+CHECKED_DUMMY( 0, VMMR3DisableSwitcher)
+DUMMY(-1, VMMR3GetHostToGuestSwitcher)
+
+DUMMY(-1, pthread_kill)
+DUMMY(-1, sscanf)
+DUMMY(-1, RTHeapSimpleRelocate)
+DUMMY(-1, RTHeapOffsetInit)
+DUMMY(-1, RTHeapSimpleInit)
+DUMMY(-1, RTHeapOffsetFree)
+DUMMY(-1, RTHeapSimpleFree)
+DUMMY(-1, RTAvloU32Get)
+DUMMY(-1, RTAvloU32Remove)
+DUMMY(-1, RTAvloU32GetBestFit)
+CHECKED_DUMMY(0, RTAvloU32RemoveBestFit)
+DUMMY(-1, RTAvlU32Destroy)
+DUMMY(-1, RTAvlU32GetBestFit)
+DUMMY(-1, RTAvloU32DoWithAll)
+DUMMY(-1, RTAvloU32Insert)
+DUMMY(-1, RTAvlU32Get)
+DUMMY(-1, RTAvlU32DoWithAll)
+DUMMY(-1, RTAvlU32Insert)
+
+CHECKED_DUMMY( 0, IOMR3Init)
+int IOMR3IOPortRegisterR0() { return 0; }
+int IOMR3IOPortRegisterRC() { return 0; }
+DUMMY(-1, IOMR3MmioDeregister)
+CHECKED_DUMMY( 0, IOMR3MmioRegisterR0)
+CHECKED_DUMMY( 0, IOMR3MmioRegisterRC)
+void IOMR3Relocate() { }
+DUMMY(-1, IOMR3Reset)
+DUMMY(-1, IOMR3Term)
+
+DUMMY(-1, IOMInterpretOUT)
+DUMMY(-1, IOMInterpretOUTS)
+DUMMY(-1, IOMInterpretIN)
+DUMMY(-1, IOMInterpretINS)
+
+
+DUMMY(-1, DISInstrToStrWithReader)
+
+DUMMY(0, RTPathQueryInfoEx)
+
+DUMMY(-1, RTFileQueryFsSizes)
+
+time_t mktime(tm *) {
+ PERR("mktime not implemented, return 0");
+ return 0;
+}
+
+DUMMY(-1, pthread_mutex_timedlock)
+
+CHECKED_DUMMY( 0, PGMHandlerVirtualDeregister) /* XXX */
+CHECKED_DUMMY( 0, PGMR3HandlerVirtualRegister) /* XXX */
+
+/*
+ * Dummies added for storage
+ */
+DUMMY(-1, closedir)
+DUMMY(-1, readdir_r)
+DUMMY(-1, RTAvlrFileOffsetDestroy)
+DUMMY(-1, RTAvlrFileOffsetGet)
+DUMMY(-1, RTAvlrFileOffsetGetBestFit)
+DUMMY(-1, RTAvlrFileOffsetInsert)
+DUMMY(-1, RTAvlrFileOffsetRemove)
+DUMMY(-1, RTAvlrU64Destroy)
+DUMMY(-1, RTAvlrU64DoWithAll)
+DUMMY(-1, RTAvlrU64GetBestFit)
+DUMMY(-1, RTAvlrU64Insert)
+DUMMY(-1, RTAvlrU64RangeGet)
+DUMMY(-1, RTAvlrU64RangeRemove)
+DUMMY(-1, RTAvlrU64Remove)
+DUMMY(-1, RTDirOpenFiltered)
+DUMMY(-1, RTDirReadEx)
+DUMMY(-1, RTDirClose)
+DUMMY(-1, RTLdrClose)
+DUMMY(-1, RTLdrGetSymbol)
+DUMMY(-1, RTMemDupExTag)
+DUMMY(-1, RTPathQueryInfo)
+DUMMY(-1, rtPathRootSpecLen)
+DUMMY(-1, RTPathStartsWithRoot)
+DUMMY(-1, RTSocketToNative)
+DUMMY(-1, RTStrCatP)
+DUMMY(-1, RTTcpClientCloseEx)
+DUMMY(-1, RTTcpClientConnect)
+DUMMY(-1, RTTcpFlush)
+DUMMY(-1, RTTcpGetLocalAddress)
+DUMMY(-1, RTTcpGetPeerAddress)
+DUMMY(-1, RTTcpRead)
+DUMMY(-1, RTTcpReadNB)
+DUMMY(-1, RTTcpSelectOne)
+DUMMY(-1, RTTcpSelectOneEx)
+DUMMY(-1, RTTcpSetSendCoalescing)
+DUMMY(-1, RTTcpSgWrite)
+DUMMY(-1, RTTcpSgWriteNB)
+DUMMY(-1, RTTcpWrite)
+DUMMY(-1, RTTcpWriteNB)
+DUMMY(-1, strncat)
+
+int __isthreaded;
+
+int sigprocmask() { return 0; }
+int _sigprocmask() { return 0; }
+
+int PGMFlushTLB() { return 0; }
+int PGMInvalidatePage() { return 0; } /* seems to be needed on raw mode only */
+int PGMHandlerPhysicalPageTempOff() { return 0; }
+
+int PGMIsLockOwner() { return 0; } /* assertion in EMRemLock */
+bool IOMIsLockOwner() { return 0; } /* XXX */
+
+int MMHyperIsInsideArea() { return 0; } /* used by dbgfR3DisasInstrRead */
+int PGMPhysReleasePageMappingLock() { return 0; }
+} /* extern "C" */
+
diff --git a/ports/src/virtualbox/fake_pci_vendor.patch b/ports/src/virtualbox/fake_pci_vendor.patch
new file mode 100644
index 0000000000..a9dc0946b6
--- /dev/null
+++ b/ports/src/virtualbox/fake_pci_vendor.patch
@@ -0,0 +1,20 @@
++++ src/VBox/Devices/Graphics/DevVGA.cpp 2013-12-09 10:33:02.168894689 +0100
+@@ -5885,7 +5889,7 @@
+ vgaR3Reset(pDevIns);
+
+ /* The PCI devices configuration. */
+- PCIDevSetVendorId( &pThis->Dev, 0x80ee); /* PCI vendor, just a free bogus value */
++ PCIDevSetVendorId( &pThis->Dev, 0x80ef); /* PCI vendor, just a free bogus value */
+ PCIDevSetDeviceId( &pThis->Dev, 0xbeef);
+ PCIDevSetClassSub( &pThis->Dev, 0x00); /* VGA controller */
+ PCIDevSetClassBase( &pThis->Dev, 0x03);
++++ src/VBox/Devices/VMMDev/VMMDev.cpp 2013-12-09 10:33:15.164894199 +0100
+@@ -3429,7 +3431,7 @@
+ pThis->pDevIns = pDevIns;
+
+ /* PCI vendor, just a free bogus value */
+- PCIDevSetVendorId(&pThis->dev, 0x80ee);
++ PCIDevSetVendorId(&pThis->dev, 0x80ef);
+ /* device ID */
+ PCIDevSetDeviceId(&pThis->dev, 0xcafe);
+ /* class sub code (other type of system peripheral) */
diff --git a/ports/src/virtualbox/guest_memory.h b/ports/src/virtualbox/guest_memory.h
new file mode 100644
index 0000000000..0b6165413b
--- /dev/null
+++ b/ports/src/virtualbox/guest_memory.h
@@ -0,0 +1,357 @@
+/*
+ * \brief Registry of known guest-physical memory regions
+ * \author Norman Feske
+ * \date 2013-09-02
+ *
+ * Contains the mapping of guest-phyiscal to VMM-local addresses.
+ */
+
+/*
+ * Copyright (C) 2013 Genode Labs GmbH
+ *
+ * This file is distributed under the terms of the GNU General Public License
+ * version 2.
+ */
+
+#ifndef _GUEST_MEMORY_H_
+#define _GUEST_MEMORY_H_
+
+/*
+ * Work-around for a naming conflict between the enum definition of PAGE_SIZE
+ * in 'os/attached_ram_dataspace.h' and the VirtualBox #define with the same
+ * name.
+ */
+#define BACKUP_PAGESIZE PAGE_SIZE
+#undef PAGE_SIZE
+
+/* Genode includes */
+#include
+#include
+#include
+#include
+#include
+#include
+
+/* VirtualBox includes */
+#include
+#include
+#include
+
+#define PAGE_SIZE BACKUP_PAGESIZE
+
+
+class Guest_memory
+{
+ struct Region;
+
+ /*
+ * XXX Use AVL tree instead of a linked list
+ */
+
+ typedef Genode::List Region_list;
+ typedef Genode::Lock Lock;
+ typedef Genode::addr_t addr_t;
+
+ private:
+
+ struct Region : Region_list::Element
+ {
+ RTGCPHYS const _GCPhys; /* guest-physical address */
+ RTGCPHYS const _cb; /* size */
+ void * const _pv; /* VMM-local address */
+
+ /*
+ * MMIO-specific members
+ */
+ PPDMDEVINS const _pDevIns;
+ RTHCPTR const _pvUser;
+ PFNIOMMMIOWRITE const _pfnWriteCallback;
+ PFNIOMMMIOREAD const _pfnReadCallback;
+ PFNIOMMMIOFILL const _pfnFillCallback;
+ uint32_t const _fFlags;
+
+ Region(RTGCPHYS const GCPhys, RTGCPHYS const cb, void *const pv,
+ PPDMDEVINS pDevIns,
+ RTHCPTR pvUser,
+ PFNIOMMMIOWRITE pfnWriteCallback,
+ PFNIOMMMIOREAD pfnReadCallback,
+ PFNIOMMMIOFILL pfnFillCallback,
+ uint32_t fFlags)
+ :
+ _GCPhys(GCPhys), _cb(cb), _pv(pv),
+ _pDevIns (pDevIns),
+ _pvUser (pvUser),
+ _pfnWriteCallback (pfnWriteCallback),
+ _pfnReadCallback (pfnReadCallback),
+ _pfnFillCallback (pfnFillCallback),
+ _fFlags (fFlags)
+ { }
+
+ /**
+ * Return true if region contains specified guest-physical area
+ */
+ bool contains(RTGCPHYS GCPhys, size_t size) const
+ {
+ return (_GCPhys <= GCPhys) && (GCPhys < _GCPhys + _cb) &&
+ (_GCPhys + _cb - GCPhys >= size);
+ }
+
+ /**
+ * Return true if region is disjunct to specified guest-physical area
+ */
+ bool disjunct(RTGCPHYS GCPhys, size_t size) const
+ {
+ return (GCPhys + size - 1 < _GCPhys) ||
+ (_GCPhys + _cb - 1 < GCPhys);
+ }
+
+ /**
+ * Return guest-physical base address
+ */
+ RTGCPHYS GCPhys() const { return _GCPhys; }
+
+ /**
+ * Return VMM-local base address
+ */
+ void *pv() const { return _pv; }
+
+ void dump() const
+ {
+ Genode::printf("phys [0x%16lx-0x%16lx] -> virt [0x%16lx-0x%16lx] (dev='%s')\n",
+ (long)_GCPhys, (long)_GCPhys + (long)_cb - 1,
+ (long)_pv, (long)_pv + (long)_cb - 1,
+ _pDevIns && _pDevIns->pReg ? _pDevIns->pReg->szName : 0);
+ }
+
+ void *pv_at_offset(addr_t offset)
+ {
+ if (_pv)
+ return (void *)((addr_t)_pv + (addr_t)offset);
+ return 0;
+ }
+
+ int mmio_write(RTGCPHYS GCPhys, void const *pv, unsigned cb)
+ {
+ if (!_pfnWriteCallback)
+ return VERR_IOM_MMIO_RANGE_NOT_FOUND;
+
+// PDBG("mmio_write(GCPhys=0x%lx, cb=%u)", GCPhys, cb);
+
+ return _pfnWriteCallback(_pDevIns, _pvUser, GCPhys, pv, cb);
+ }
+
+ int mmio_read(RTGCPHYS GCPhys, void *pv, unsigned cb)
+ {
+ if (!_pfnReadCallback)
+ return VERR_IOM_MMIO_RANGE_NOT_FOUND;
+
+// PDBG("mmio_read(GCPhys=0x%lx, cb=%u)", GCPhys, cb);
+
+ return _pfnReadCallback(_pDevIns, _pvUser, GCPhys, pv, cb);
+ }
+ };
+
+ Lock _lock;
+ Region_list _ram_regions;
+ Region_list _rom_regions;
+ Region_list _mmio_regions;
+
+ static Region *_lookup(RTGCPHYS GCPhys, Region_list ®ions, size_t size)
+ {
+ using Genode::addr_t;
+
+ for (Region *r = regions.first(); r; r = r->next())
+ if (r->contains(GCPhys, size))
+ return r;
+
+ return 0;
+ }
+
+ static bool _overlap(RTGCPHYS GCPhys, size_t size,
+ Region_list ®ions)
+ {
+ using Genode::addr_t;
+
+ for (Region *r = regions.first(); r; r = r->next())
+ {
+ if (r->disjunct(GCPhys, size))
+ continue;
+
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * \return looked-up region, or 0 if lookup failed
+ */
+ Region *_lookup(RTGCPHYS GCPhys, size_t size)
+ {
+ using Genode::addr_t;
+
+ /*
+ * ROM regions may alias RAM regions. For the lookup, always
+ * consider ROM regions first.
+ */
+
+ if (Region *r = _lookup(GCPhys, _rom_regions, size))
+ return r;
+
+ if (Region *r = _lookup(GCPhys, _mmio_regions, size))
+ return r;
+
+ if (Region *r = _lookup(GCPhys, _ram_regions, size))
+ return r;
+
+ return 0;
+ }
+
+ public:
+
+ class Region_conflict { };
+
+ /**
+ * \throw Region_conflict
+ */
+ void add_ram_mapping(RTGCPHYS const GCPhys, RTGCPHYS const cb, void * const pv)
+ {
+ /*
+ * XXX check for overlapping regions
+ */
+ _ram_regions.insert(new (Genode::env()->heap())
+ Region(GCPhys, cb, pv, 0, 0, 0, 0, 0, 0));
+ }
+
+ /**
+ * \throw Region_conflict
+ */
+ void add_rom_mapping(RTGCPHYS const GCPhys, RTGCPHYS const cb,
+ void const * const pv, PPDMDEVINS pDevIns)
+ {
+ /*
+ * XXX check for overlapping regions
+ */
+ _rom_regions.insert(new (Genode::env()->heap())
+ Region(GCPhys, cb,
+ (void *)pv, pDevIns, 0, 0, 0, 0, 0));
+ }
+
+ /**
+ * \throw Region_conflict
+ */
+ void add_mmio_mapping(RTGCPHYS const GCPhys, RTGCPHYS const cb,
+ PPDMDEVINS pDevIns,
+ RTHCPTR pvUser,
+ PFNIOMMMIOWRITE pfnWriteCallback,
+ PFNIOMMMIOREAD pfnReadCallback,
+ PFNIOMMMIOFILL pfnFillCallback,
+ uint32_t fFlags)
+ {
+ /*
+ * XXX check for overlapping regions
+ */
+ _mmio_regions.insert(new (Genode::env()->heap())
+ Region(GCPhys, cb, 0,
+ pDevIns, pvUser, pfnWriteCallback,
+ pfnReadCallback, pfnFillCallback, fFlags));
+ }
+
+ void dump() const
+ {
+ Genode::printf("guest-physical to VMM-local RAM mappings:\n");
+ for (Region const *r = _ram_regions.first(); r; r = r->next())
+ r->dump();
+
+ Genode::printf("guest-physical to VMM-local ROM mappings:\n");
+ for (Region const *r = _rom_regions.first(); r; r = r->next())
+ r->dump();
+
+ Genode::printf("guest-physical MMIO regions:\n");
+ for (Region const *r = _mmio_regions.first(); r; r = r->next())
+ r->dump();
+ }
+
+ /**
+ * \return looked-up VMM-local address, or 0 if lookup failed
+ */
+ void *lookup(RTGCPHYS GCPhys, size_t size)
+ {
+ Region *r = _lookup(GCPhys, size);
+ if (!r)
+ return 0;
+
+ return r->pv_at_offset(GCPhys - r->GCPhys());
+ }
+
+ /**
+ * \return looked-up VMM-local address if Guest address is RAM
+ */
+ void *lookup_ram(RTGCPHYS const GCPhys, size_t size,
+ Genode::Flexpage_iterator &it)
+ {
+ if (_overlap(GCPhys, size, _rom_regions))
+ return 0;
+
+ if (_overlap(GCPhys, size, _mmio_regions))
+ return 0;
+
+ if (!_overlap(GCPhys, size, _ram_regions))
+ return 0;
+
+ Region *r = _lookup(GCPhys, _ram_regions, size);
+ if (!r)
+ return 0;
+
+ void * vmm_local = lookup_ram(GCPhys & ~(size * 2UL - 1), size * 2UL, it);
+ if (vmm_local)
+ return vmm_local;
+
+ it = Genode::Flexpage_iterator((addr_t)r->pv_at_offset(GCPhys - r->GCPhys()), size, GCPhys, size, GCPhys - r->GCPhys());
+
+ return r->pv_at_offset(GCPhys - r->GCPhys());
+ }
+
+ /**
+ * \return VirtualBox return code
+ */
+ int mmio_write(PVM pVM, RTGCPHYS GCPhys, uint32_t u32Value, size_t cbValue)
+ {
+ Region *r = _lookup(GCPhys, cbValue);
+
+ if (!r) {
+ PERR("Guest_memory::mmio_write: lookup failed");
+ PERR("GCPhys=0x%x, u32Value=0x%x, cbValue=%zd",
+ GCPhys, u32Value, cbValue);
+ return VERR_IOM_MMIO_RANGE_NOT_FOUND;
+ }
+
+ return r->mmio_write(GCPhys, &u32Value, cbValue);
+ }
+
+ /**
+ * \return VirtualBox return code
+ */
+ int mmio_read(PVM pVM, RTGCPHYS GCPhys, uint32_t *u32Value, size_t cbValue)
+ {
+ Region *r = _lookup(GCPhys, cbValue);
+
+ if (!r) {
+ PERR("Guest_memory::mmio_read: lookup failed");
+ PERR("GCPhys=0x%x, u32Value=0x%x, cbValue=%zd",
+ GCPhys, u32Value, cbValue);
+ return VERR_IOM_MMIO_RANGE_NOT_FOUND;
+ }
+
+ return r->mmio_read(GCPhys, u32Value, cbValue);
+ }
+};
+
+
+/**
+ * Return pointer to singleton instance
+ */
+Guest_memory *guest_memory();
+
+
+#endif /* _GUEST_MEMORY_H_ */
diff --git a/ports/src/virtualbox/hda.patch b/ports/src/virtualbox/hda.patch
new file mode 100644
index 0000000000..1dc374bbf8
--- /dev/null
+++ b/ports/src/virtualbox/hda.patch
@@ -0,0 +1,53 @@
++++ src/VBox/Frontends/VBoxBFE/VBoxBFE.cpp
+@@ -158,6 +160,7 @@
+ static bool g_fReleaseLog = true; /**< Set if we should open the release. */
+ const char *g_pszProgressString;
+ unsigned g_uProgressPercent = ~0U;
++static bool g_fOverlay= false;
+
+
+ /**
+@@ -715,6 +718,8 @@
+ g_fCSAM = false;
+ #endif /* VBOXSDL_ADVANCED_OPTIONS */
+ /* just show the help screen */
++ else if (strcmp(pszArg, "-overlay") == 0)
++ g_fOverlay = true;
+ else
+ {
+ SyntaxError("unrecognized argument '%s'\n", pszArg);
+@@ -1532,7 +1550,7 @@
+ rc = CFGMR3InsertNode(pLunL0, "AttachedDriver", &pDrv); UPDATE_RC();
+ rc = CFGMR3InsertString(pDrv, "Driver", "VD"); UPDATE_RC();
+ rc = CFGMR3InsertNode(pDrv, "Config", &pCfg); UPDATE_RC();
+- rc = CFGMR3InsertString(pCfg, "Path", g_pszHdaFile); UPDATE_RC();
++ rc = CFGMR3InsertString(pCfg, "Type", "HardDisk"); UPDATE_RC();
+
+ if (g_fHdaSpf)
+ {
+@@ -1541,13 +1559,23 @@
+ else
+ {
+ char *pcExt = RTPathExt(g_pszHdaFile);
+- if ((pcExt) && (!strcmp(pcExt, ".vdi")))
++ if ((pcExt) && (!strcmp(pcExt, ".vdi") && !g_fOverlay))
+ {
+ rc = CFGMR3InsertString(pCfg, "Format", "VDI"); UPDATE_RC();
++ rc = CFGMR3InsertString(pCfg, "Path", g_pszHdaFile); UPDATE_RC();
+ }
+ else
+ {
+- rc = CFGMR3InsertString(pCfg, "Format", "VMDK"); UPDATE_RC();
++ /*
++ * Use the overlay.vdi file to store differential changes.
++ * Leave the VMDK file passed as argument unchanged.
++ */
++ PCFGMNODE pParent = 0;
++ rc = CFGMR3InsertString(pCfg, "Format", "VDI"); UPDATE_RC();
++ rc = CFGMR3InsertString(pCfg, "Path", "/ram/overlay.vdi"); UPDATE_RC();
++ rc = CFGMR3InsertNode(pCfg, "Parent", &pParent); UPDATE_RC();
++ rc = CFGMR3InsertString(pParent, "Format", "VDI"); UPDATE_RC();
++ rc = CFGMR3InsertString(pParent, "Path", g_pszHdaFile); UPDATE_RC();
+ }
+ }
+ }
diff --git a/ports/src/virtualbox/hwacc.patch b/ports/src/virtualbox/hwacc.patch
new file mode 100644
index 0000000000..a369e2e530
--- /dev/null
+++ b/ports/src/virtualbox/hwacc.patch
@@ -0,0 +1,16 @@
++++ src/VBox/Frontends/VBoxBFE/VBoxBFE.cpp
+@@ -1273,6 +1279,14 @@
+ rc = CFGMR3InsertInteger(pRoot, "CSAMEnabled", 1); UPDATE_RC();
+ #endif
+
++ /* enable HW virtualization support */
++
++ PCFGMNODE pHWVirtExt = NULL;
++
++ rc = CFGMR3InsertNode(pRoot, "HWVirtExt", &pHWVirtExt); UPDATE_RC();
++ rc = CFGMR3InsertInteger(pHWVirtExt, "Enabled", 1); UPDATE_RC();
++ rc = CFGMR3InsertInteger(pHWVirtExt, "64bitEnabled", 0); UPDATE_RC();
++
+ /*
+ * PDM.
+ */
diff --git a/ports/src/virtualbox/hwaccm.cc b/ports/src/virtualbox/hwaccm.cc
new file mode 100644
index 0000000000..95dd9592d1
--- /dev/null
+++ b/ports/src/virtualbox/hwaccm.cc
@@ -0,0 +1,129 @@
+/*
+ * \brief VirtualBox hardware-acceleration manager
+ * \author Norman Feske
+ * \date 2013-08-20
+ */
+
+/*
+ * Copyright (C) 2013 Genode Labs GmbH
+ *
+ * This file is distributed under the terms of the GNU General Public License
+ * version 2.
+ */
+
+/* Genode includes */
+#include
+
+/* VirtualBox includes */
+#include "HWACCMInternal.h" /* enable access to hwaccm.s.* */
+#include
+#include
+
+/* Genode's VirtualBox includes */
+#include "sup.h"
+
+
+static bool enabled = true;
+
+
+VMMR3DECL(int) HWACCMR3Init(PVM pVM)
+{
+ /*
+ * We always set the fHWACCMEnabled flag. Otherwise, the EM won't
+ * consult us for taking scheduling decisions. The actual switch to
+ * HW accelerated mode is still dependent on the result of the
+ * HWACCMR3CanExecuteGuest function.
+ */
+ pVM->fHWACCMEnabled = true;
+
+ for (VMCPUID i = 0; i < pVM->cCpus; i++)
+ pVM->aCpus[i].hwaccm.s.fActive = false;
+
+ return VINF_SUCCESS;
+}
+
+
+VMMR3_INT_DECL(int) HWACCMR3InitCompleted(PVM pVM, VMINITCOMPLETED enmWhat)
+{
+ enabled = pVM->hwaccm.s.svm.fSupported || pVM->hwaccm.s.vmx.fSupported;
+
+ if (!enabled || enmWhat != VMINITCOMPLETED_RING0)
+ return VINF_SUCCESS;
+
+ int rc = SUPR3CallVMMR0Ex(pVM->pVMR0, 0 /*idCpu*/, VMMR0_DO_HWACC_SETUP_VM, 0, NULL);
+ return rc;
+}
+
+
+VMMR3DECL(bool) HWACCMR3IsVmxPreemptionTimerUsed(PVM pVM)
+{
+ PLOG("HWACCMR3IsVmxPreemptionTimerUsed");
+ return false;
+}
+
+
+VMMR3DECL(bool) HWACCMR3IsActive(PVMCPU pVCpu)
+{
+ return pVCpu->hwaccm.s.fActive;
+}
+
+
+VMMR3DECL(bool) HWACCMR3IsRescheduleRequired(PVM pVM, PCPUMCTX pCtx)
+{
+ /* no re-schedule on AMD-V required - just works */
+/*
+ if (pVM->hwaccm.s.svm.fSupported)
+ return false;
+*/
+ bool reschedule = !CPUMIsGuestInPagedProtectedModeEx(pCtx);
+
+// PLOG("reschedule %u %u %lx", reschedule, HWACCMR3CanExecuteGuest(pVM, pCtx), pCtx->cr0);
+
+ return reschedule;
+}
+
+
+void HWACCMR3PagingModeChanged(PVM pVM, PVMCPU pVCpu, PGMMODE enmShadowMode,
+ PGMMODE enmGuestMode)
+{
+// PLOG("HWACCMR3PagingModeChanged: enmShadowMode=%d enmGuestMode=%d",
+// enmShadowMode, enmGuestMode);
+}
+
+
+VMMR3DECL(bool) HWACCMR3IsEventPending(PVMCPU pVCpu)
+{
+// PLOG("HWACCMR3IsEventPending false");
+ return false;
+}
+
+
+VMMR3DECL(bool) HWACCMR3CanExecuteGuest(PVM pVM, PCPUMCTX pCtx)
+{
+ PVMCPU pVCpu = VMMGetCpu(pVM);
+
+ /* AMD-V just works */
+/*
+ if (pVM->hwaccm.s.svm.fSupported) {
+ pVCpu->hwaccm.s.fActive = true;
+ return true;
+ }
+*/
+ if (!enabled)
+ return false;
+
+ /* enable H/W acceleration in protected mode only */
+ bool res = (pCtx->cr0 & 1) && (pCtx->cr0 & 0x80000000);
+/*
+ static bool on = false;
+
+ if (res)
+ on = true;
+
+ if (on)
+ PLOG("executeguest %lx -> %x", pCtx->cr0, res);
+*/
+ pVCpu->hwaccm.s.fActive = res;
+
+ return res;
+}
diff --git a/ports/src/virtualbox/include/SDLConsole.h b/ports/src/virtualbox/include/SDLConsole.h
new file mode 100644
index 0000000000..213d6b7fd5
--- /dev/null
+++ b/ports/src/virtualbox/include/SDLConsole.h
@@ -0,0 +1,246 @@
+/*
+ * \brief Console implementation of VirtualBox for Genode
+ * \author Alexander Boettcher
+ * \date 2013-10-16
+ */
+
+/*
+ * Copyright (C) 2013 Genode Labs GmbH
+ *
+ * This file is distributed under the terms of the GNU General Public License
+ * version 2.
+ */
+
+/* Genode includes */
+#include
+#include
+#include
+#include
+
+/* included from os/src/drivers/input/ps2 */
+#include
+
+/* VirtualBox includes */
+#include
+#include
+
+/* XXX */
+enum { KMOD_RCTRL = 0, SDLK_RCTRL = 0 };
+
+
+class Scan_code
+{
+ private:
+
+ class Converter
+ {
+ public:
+
+ unsigned char scan_code [Input::KEY_UNKNOWN];
+ unsigned char scan_code_ext [Input::KEY_UNKNOWN];
+
+ private:
+
+ unsigned char _search_scan_code(Input::Keycode keycode)
+ {
+ for (unsigned i = 0; i < SCAN_CODE_SET_1_NUM_KEYS; i++)
+ if (scan_code_set_1[i] == keycode)
+ return i;
+ return 0;
+ }
+
+ unsigned char _search_scan_code_ext(Input::Keycode keycode)
+ {
+ for (unsigned i = 0; i < SCAN_CODE_SET_1_NUM_KEYS; i++)
+ if (scan_code_set_1_0xe0[i] == keycode)
+ return i;
+ return 0;
+ }
+
+ public:
+
+ Converter()
+ {
+ init_scan_code_set_1_0xe0();
+
+ for (unsigned i = 0; i < Input::KEY_UNKNOWN; i++) {
+ scan_code [i] = _search_scan_code ((Input::Keycode)i);
+ scan_code_ext [i] = _search_scan_code_ext((Input::Keycode)i);
+ }
+ }
+ };
+
+ static Converter &converter()
+ {
+ static Converter inst;
+ return inst;
+ }
+
+ Input::Keycode _keycode;
+
+ public:
+
+ Scan_code(Input::Keycode keycode) : _keycode(keycode) { }
+
+ bool is_normal() const { return converter().scan_code[_keycode]; }
+ bool is_ext() const { return converter().scan_code_ext[_keycode]; }
+
+ bool valid() const
+ {
+ return is_normal() || is_ext();
+ }
+
+ unsigned char code() const
+ {
+ return converter().scan_code[_keycode];
+ }
+
+ unsigned char ext() const
+ {
+ return converter().scan_code_ext[_keycode];
+ }
+};
+
+
+class SDLConsole : public Console {
+
+ private:
+
+ Timer::Connection timer;
+ Input::Connection input;
+ Input::Event *_ev_buf;
+ unsigned _ax, _ay;
+
+ bool _key_status[Input::KEY_MAX + 1];
+
+ static bool _is_mouse_button(Input::Keycode keycode)
+ {
+ return keycode == Input::BTN_LEFT
+ || keycode == Input::BTN_RIGHT
+ || keycode == Input::BTN_MIDDLE;
+ }
+
+ public:
+
+ SDLConsole()
+ :
+ Console(),
+ _ev_buf(static_cast(Genode::env()->rm_session()->attach(input.dataspace()))),
+ _ax(0), _ay(0)
+ {
+ for (unsigned i = 0; i <= Input::KEY_MAX; i++)
+ _key_status[i] = 0;
+
+ if (FAILED(gMouse->init(this))) {
+ PERR("mouse init failed");
+ return;
+ }
+
+ mfInitialized = true;
+ }
+
+ void updateTitlebar()
+ {
+ PERR("%s:%s called", __FILE__, __FUNCTION__);
+ }
+
+ void updateTitlebarProgress(const char *, int)
+ {
+ PERR("%s:%s called", __FILE__, __FUNCTION__);
+ }
+
+ void inputGrabStart()
+ {
+ PERR("%s:%s called", __FILE__, __FUNCTION__);
+ }
+
+ void inputGrabEnd()
+ {
+ PERR("%s:%s called", __FILE__, __FUNCTION__);
+ }
+
+ void mouseSendEvent(int)
+ {
+ PERR("%s:%s called", __FILE__, __FUNCTION__);
+ }
+
+ void onMousePointerShapeChange(bool, bool, uint32_t, uint32_t,
+ uint32_t, uint32_t, void *)
+ {
+ PERR("%s:%s called", __FILE__, __FUNCTION__);
+ }
+
+ void progressInfo(PVM, unsigned, void *)
+ {
+ PERR("%s:%s called", __FILE__, __FUNCTION__);
+ }
+
+ CONEVENT eventWait()
+ {
+ while (!input.is_pending()) { timer.msleep(50); }
+
+ for (int i = 0, num_ev = input.flush(); i < num_ev; ++i) {
+ Input::Event &ev = _ev_buf[i];
+
+ bool const is_press = ev.type() == Input::Event::PRESS;
+ bool const is_release = ev.type() == Input::Event::RELEASE;
+ bool const is_key = is_press || is_release;
+ bool const is_motion = ev.type() == Input::Event::MOTION;
+
+ if (is_key) {
+ Scan_code scan_code(ev.keycode());
+
+ unsigned char const release_bit =
+ (ev.type() == Input::Event::RELEASE) ? 0x80 : 0;
+
+ if (scan_code.is_normal())
+ gKeyboard->PutScancode(scan_code.code() | release_bit);
+
+ if (scan_code.is_ext()) {
+ gKeyboard->PutScancode(0xe0);
+ gKeyboard->PutScancode(scan_code.ext() | release_bit);
+ }
+ }
+
+ /*
+ * Track press/release status of keys and buttons. Currently,
+ * only the mouse-button states are actually used.
+ */
+ if (is_press)
+ _key_status[ev.keycode()] = true;
+
+ if (is_release)
+ _key_status[ev.keycode()] = false;
+
+ bool const is_mouse_button_event =
+ is_key && _is_mouse_button(ev.keycode());
+
+ bool const is_mouse_event = is_mouse_button_event || is_motion;
+
+ if (is_mouse_event) {
+ unsigned const buttons = (_key_status[Input::BTN_LEFT] ? 0x1 : 0)
+ | (_key_status[Input::BTN_RIGHT] ? 0x2 : 0)
+ | (_key_status[Input::BTN_MIDDLE] ? 0x4 : 0);
+
+ if (ev.is_absolute_motion()) {
+ int const rx = ev.ax() - _ax; _ax = ev.ax();
+ int const ry = ev.ay() - _ay; _ay = ev.ay();
+ gMouse->PutMouseEvent(rx, ry, 0, 0, buttons);
+ gMouse->PutMouseEventAbsolute(ev.ax(), ev.ay(), 0, 0, buttons);
+ } else if (ev.is_relative_motion())
+ gMouse->PutMouseEvent(ev.rx(), ev.ry(), 0, 0, buttons);
+
+ /* only the buttons changed */
+ else
+ gMouse->PutMouseEvent(0, 0, 0, 0, buttons);
+ }
+ }
+
+ return CONEVENT_NONE;
+ }
+
+ void eventQuit() { PERR("%s:%s called", __FILE__, __FUNCTION__); }
+ void resetKeys(void) { PERR("%s:%s called", __FILE__, __FUNCTION__); }
+ VMMDev *getVMMDev() { /*PERR("%s:%s called", __FILE__, __FUNCTION__);*/ return 0; }
+ Display *getDisplay() { return gDisplay; }
+};
diff --git a/ports/src/virtualbox/include/SDLFramebuffer.h b/ports/src/virtualbox/include/SDLFramebuffer.h
new file mode 100644
index 0000000000..3a89c2b3fa
--- /dev/null
+++ b/ports/src/virtualbox/include/SDLFramebuffer.h
@@ -0,0 +1,110 @@
+/*
+ * \brief Framebuffer implementation of VirtualBox for Genode
+ * \author Alexander Boettcher
+ * \date 2013-10-16
+ */
+
+/*
+ * Copyright (C) 2013 Genode Labs GmbH
+ *
+ * This file is distributed under the terms of the GNU General Public License
+ * version 2.
+ */
+
+/* Genode includes */
+#define Framebuffer FramebufferGenode
+#include
+#undef Framebuffer
+
+/* VirtualBox includes */
+#include "Framebuffer.h"
+
+#include
+
+class SDLFramebuffer : public Framebuffer
+{
+ private:
+
+ FramebufferGenode::Connection _fb;
+ FramebufferGenode::Mode const _fb_mode;
+ void * _fb_base;
+ RTCRITSECT mUpdateLock;
+
+ public:
+
+ SDLFramebuffer ()
+ :
+ _fb_mode(_fb.mode()),
+ _fb_base(Genode::env()->rm_session()->attach(_fb.dataspace()))
+ {
+ int rc = RTCritSectInit(&mUpdateLock);
+ if (rc != VINF_SUCCESS)
+ PERR("Lock could not be initalized");
+ }
+
+ HRESULT getWidth(ULONG * width)
+ {
+ *width = _fb_mode.width();
+ return S_OK;
+ }
+
+ HRESULT getHeight(ULONG * height)
+ {
+ *height = _fb_mode.height();
+ return S_OK;
+ }
+
+ HRESULT Lock() { return RTCritSectEnter(&mUpdateLock); }
+
+ HRESULT Unlock() { return RTCritSectLeave(&mUpdateLock); }
+
+ HRESULT getAddress(uintptr_t * addr)
+ {
+ *addr = reinterpret_cast(_fb_base);
+ return S_OK;
+ }
+
+ HRESULT getBitsPerPixel(ULONG * bits)
+ {
+ *bits = _fb_mode.bytes_per_pixel() * 8;
+ return S_OK;
+ }
+
+ HRESULT getLineSize(ULONG * line)
+ {
+ *line = _fb_mode.width() * _fb_mode.bytes_per_pixel();
+ return S_OK;
+ }
+
+ HRESULT NotifyUpdate(ULONG x, ULONG y, ULONG w, ULONG h)
+ {
+ _fb.refresh(x, y, w, h);
+ return S_OK;
+ }
+
+ HRESULT RequestResize(ULONG x, ULONG y, BOOL * finished)
+ {
+ PERR("ignore resize request to %lux%lu", x, y);
+ Genode::size_t const num_pixels = _fb_mode.width()*_fb_mode.height();
+ Genode::memset(_fb_base, 0, num_pixels*_fb_mode.bytes_per_pixel());
+ _fb.refresh(0, 0, _fb_mode.width(), _fb_mode.height());
+ *finished = true;
+ return S_OK;
+ }
+
+ HRESULT GetVisibleRegion(BYTE *, ULONG, ULONG *) { PERR("%s:%s called", __FILE__, __FUNCTION__); return E_NOTIMPL; }
+ HRESULT SetVisibleRegion(BYTE *, ULONG) { PERR("%s:%s called", __FILE__, __FUNCTION__); return E_NOTIMPL; }
+
+ HRESULT ProcessVHWACommand(BYTE *) { PERR("%s:%s called", __FILE__, __FUNCTION__); return E_NOTIMPL; }
+
+ void repaint() { PERR("%s:%s called", __FILE__, __FUNCTION__); }
+ void resize() { PERR("%s:%s called", __FILE__, __FUNCTION__); }
+
+ void update(int, int, int, int) { PERR("%s:%s called", __FILE__, __FUNCTION__); }
+ bool getFullscreen() { PERR("%s:%s called", __FILE__, __FUNCTION__); }
+ void setFullscreen(bool) { PERR("%s:%s called", __FILE__, __FUNCTION__); }
+ int getYOffset() { PERR("%s:%s called", __FILE__, __FUNCTION__); }
+ int getHostXres() { PERR("%s:%s called", __FILE__, __FUNCTION__); }
+ int getHostYres() { PERR("%s:%s called", __FILE__, __FUNCTION__); }
+ int getHostBitsPerPixel() { PERR("%s:%s called", __FILE__, __FUNCTION__); }
+};
diff --git a/ports/src/virtualbox/include/dtrace/VBoxVMM.h b/ports/src/virtualbox/include/dtrace/VBoxVMM.h
new file mode 100644
index 0000000000..a7ec925186
--- /dev/null
+++ b/ports/src/virtualbox/include/dtrace/VBoxVMM.h
@@ -0,0 +1,15 @@
+/*
+ * \brief Dummy stubs needed by 'PDMAll.cpp'
+ * \author Norman Feske
+ * \date 2013-08-25
+ */
+
+#ifndef _DTRACE__VBOXVMM_H_
+#define _DTRACE__VBOXVMM_H_
+
+#define VBOXVMM_PDM_IRQ_GET(...) do { } while (0)
+#define VBOXVMM_PDM_IRQ_HIGH(...) do { } while (0)
+#define VBOXVMM_PDM_IRQ_LOW(...) do { } while (0)
+#define VBOXVMM_PDM_IRQ_HILO(...) do { } while (0)
+
+#endif /* _DTRACE__VBOXVMM_H_ */
diff --git a/ports/src/virtualbox/include/list b/ports/src/virtualbox/include/list
new file mode 100644
index 0000000000..2a4ba09b4b
--- /dev/null
+++ b/ports/src/virtualbox/include/list
@@ -0,0 +1,4 @@
+/*
+ * \brief Dummy stubs needed by 'src/VBox/Frontends/VBoxBFE/VirtualBoxBase.h'
+ * \author Alexander Boettcher
+ */
diff --git a/ports/src/virtualbox/include/map b/ports/src/virtualbox/include/map
new file mode 100644
index 0000000000..2a4ba09b4b
--- /dev/null
+++ b/ports/src/virtualbox/include/map
@@ -0,0 +1,4 @@
+/*
+ * \brief Dummy stubs needed by 'src/VBox/Frontends/VBoxBFE/VirtualBoxBase.h'
+ * \author Alexander Boettcher
+ */
diff --git a/ports/src/virtualbox/include/product-generated.h b/ports/src/virtualbox/include/product-generated.h
new file mode 100644
index 0000000000..680eafa952
--- /dev/null
+++ b/ports/src/virtualbox/include/product-generated.h
@@ -0,0 +1,10 @@
+#ifndef ___product_generated_h___
+#define ___product_generated_h___
+
+#define VBOX_VENDOR "Oracle Corporation"
+#define VBOX_VENDOR_SHORT "Oracle"
+#define VBOX_PRODUCT "Oracle VM VirtualBox"
+#define VBOX_BUILD_PUBLISHER "_OSE"
+#define VBOX_C_YEAR "2013"
+
+#endif
diff --git a/ports/src/virtualbox/include/version-generated.h b/ports/src/virtualbox/include/version-generated.h
new file mode 100644
index 0000000000..6a79818c28
--- /dev/null
+++ b/ports/src/virtualbox/include/version-generated.h
@@ -0,0 +1,11 @@
+#ifndef ___version_generated_h___
+#define ___version_generated_h___
+
+#define VBOX_VERSION_MAJOR 4
+#define VBOX_VERSION_MINOR 2
+#define VBOX_VERSION_BUILD 16
+#define VBOX_VERSION_STRING_RAW "4.2.16"
+#define VBOX_VERSION_STRING "4.2.16_OSE"
+#define VBOX_API_VERSION_STRING "4_2"
+
+#endif
diff --git a/ports/src/virtualbox/iommio.cc b/ports/src/virtualbox/iommio.cc
new file mode 100644
index 0000000000..397764bbc1
--- /dev/null
+++ b/ports/src/virtualbox/iommio.cc
@@ -0,0 +1,76 @@
+/*
+ * \brief VirtualBox Memory-mapped I/O monitor
+ * \author Norman Feske
+ * \date 2013-09-02
+ */
+
+/*
+ * Copyright (C) 2013 Genode Labs GmbH
+ *
+ * This file is distributed under the terms of the GNU General Public License
+ * version 2.
+ */
+
+/* Genode includes */
+#include
+
+/* VirtualBox includes */
+#include
+#include
+
+/* local includes */
+#include "guest_memory.h"
+
+
+int IOMR3MmioRegisterR3(PVM pVM, PPDMDEVINS pDevIns, RTGCPHYS GCPhysStart,
+ uint32_t cbRange, RTHCPTR pvUser,
+ R3PTRTYPE(PFNIOMMMIOWRITE) pfnWriteCallback,
+ R3PTRTYPE(PFNIOMMMIOREAD) pfnReadCallback,
+ R3PTRTYPE(PFNIOMMMIOFILL) pfnFillCallback,
+ uint32_t fFlags, const char *pszDesc)
+{
+ PLOG("IOMR3MmioRegisterR3: GCPhys=0x%lx cb=0x%zx pszDesc=%s rd=%p wr=%p fl=%p",
+ (long)GCPhysStart, (size_t)cbRange, pszDesc,
+ pfnWriteCallback, pfnReadCallback, pfnFillCallback);
+
+ REMR3NotifyHandlerPhysicalRegister(pVM, PGMPHYSHANDLERTYPE_MMIO,
+ GCPhysStart, cbRange, true);
+
+ guest_memory()->add_mmio_mapping(GCPhysStart, cbRange,
+ pDevIns, pvUser, pfnWriteCallback,
+ pfnReadCallback, pfnFillCallback, fFlags);
+
+ return VINF_SUCCESS;
+
+}
+
+
+VBOXSTRICTRC IOMMMIOWrite(PVM pVM, RTGCPHYS GCPhys, uint32_t u32Value, size_t cbValue)
+{
+// PDBG("GCPhys=0x%x, u32Value=0x%x, cbValue=%zd", GCPhys, u32Value, cbValue);
+
+ return guest_memory()->mmio_write(pVM, GCPhys, u32Value, cbValue);
+}
+
+
+VBOXSTRICTRC IOMMMIORead(PVM pVM, RTGCPHYS GCPhys, uint32_t *pu32Value,
+ size_t cbValue)
+{
+// PDBG("GCPhys=0x%x, cbValue=%zd", GCPhys, cbValue);
+
+ return guest_memory()->mmio_read(pVM, GCPhys, pu32Value, cbValue);
+}
+
+
+int IOMMMIOMapMMIO2Page(PVM pVM, RTGCPHYS GCPhys, RTGCPHYS GCPhysRemapped,
+ uint64_t fPageFlags)
+{
+ PDBG("called - %lx %lx", GCPhys, GCPhysRemapped);
+ return VINF_SUCCESS;
+}
+
+int IOMMMIOResetRegion(PVM pVM, RTGCPHYS GCPhys)
+{
+ PDBG("called - %lx", GCPhys);
+ return VINF_SUCCESS;
+}
diff --git a/ports/src/virtualbox/ioport.cc b/ports/src/virtualbox/ioport.cc
new file mode 100644
index 0000000000..11d794669b
--- /dev/null
+++ b/ports/src/virtualbox/ioport.cc
@@ -0,0 +1,273 @@
+/*
+ * \brief VirtualBox I/O port monitor
+ * \author Norman Feske
+ * \date 2013-09-02
+ */
+
+/*
+ * Copyright (C) 2013 Genode Labs GmbH
+ *
+ * This file is distributed under the terms of the GNU General Public License
+ * version 2.
+ */
+
+/* Genode includes */
+#include
+#include
+#include
+#include
+
+/* VirtualBox includes */
+#include
+#include
+#include
+
+class Guest_ioports
+{
+ struct Range;
+
+ /*
+ * XXX Use AVL tree instead of a linked list
+ */
+
+ typedef Genode::List Range_list;
+ typedef Genode::Lock Lock;
+
+ private:
+
+ struct Range : Range_list::Element
+ {
+ PPDMDEVINS _pDevIns;
+ RTIOPORT _PortStart;
+ RTUINT _cPorts;
+ RTHCPTR _pvUser;
+ PFNIOMIOPORTOUT _pfnOutCallback;
+ PFNIOMIOPORTIN _pfnInCallback;
+ PFNIOMIOPORTOUTSTRING _pfnOutStringCallback;
+ PFNIOMIOPORTINSTRING _pfnInStringCallback;
+
+ /**
+ * Return true if range contains specified subrange
+ */
+ bool contains(RTIOPORT PortStart, RTUINT cPorts) const
+ {
+ return (PortStart >= _PortStart)
+ && (PortStart + cPorts - 1 <= _PortStart + _cPorts - 1);
+ }
+
+ bool partof(RTIOPORT PortStart, RTUINT cPorts) const
+ {
+ return (PortStart <= _PortStart)
+ && (PortStart + cPorts - 1 >= _PortStart + _cPorts - 1);
+ }
+
+ Range(PPDMDEVINS pDevIns,
+ RTIOPORT PortStart,
+ RTUINT cPorts,
+ RTHCPTR pvUser,
+ PFNIOMIOPORTOUT pfnOutCallback,
+ PFNIOMIOPORTIN pfnInCallback,
+ PFNIOMIOPORTOUTSTRING pfnOutStringCallback,
+ PFNIOMIOPORTINSTRING pfnInStringCallback)
+ :
+ _pDevIns (pDevIns),
+ _PortStart (PortStart),
+ _cPorts (cPorts),
+ _pvUser (pvUser),
+ _pfnOutCallback (pfnOutCallback),
+ _pfnInCallback (pfnInCallback),
+ _pfnOutStringCallback (pfnOutStringCallback),
+ _pfnInStringCallback (pfnInStringCallback)
+ { }
+
+ VBOXSTRICTRC write(RTIOPORT port, uint32_t u32Value, unsigned cb)
+ {
+ if (!_pfnOutCallback)
+ return VINF_IOM_R3_IOPORT_WRITE;
+
+// PDBG("IOPORT write Port=0x%lx", (long)port);
+ VBOXSTRICTRC rc = PDMCritSectEnter(_pDevIns->CTX_SUFF(pCritSectRo),
+ VINF_IOM_R3_IOPORT_WRITE);
+ if (rc != VINF_SUCCESS)
+ return rc;
+
+ rc = _pfnOutCallback(_pDevIns, _pvUser, port, u32Value, cb);
+
+ PDMCritSectLeave(_pDevIns->CTX_SUFF(pCritSectRo));
+
+ return rc;
+ }
+
+ VBOXSTRICTRC read(RTIOPORT port, uint32_t *pu32Value, unsigned cb)
+ {
+ if (!_pfnInCallback)
+ return VINF_IOM_R3_IOPORT_READ;
+
+ VBOXSTRICTRC rc = PDMCritSectEnter(_pDevIns->CTX_SUFF(pCritSectRo),
+ VINF_IOM_R3_IOPORT_READ);
+ if (rc != VINF_SUCCESS)
+ return rc;
+
+ rc = _pfnInCallback(_pDevIns, _pvUser, port, pu32Value, cb);
+ if (rc != VINF_SUCCESS)
+ PDBG("IOPORT read port=0x%x failed - callback %p eip %p",
+ port, _pfnInCallback, __builtin_return_address(0));
+
+ PDMCritSectLeave(_pDevIns->CTX_SUFF(pCritSectRo));
+
+ return rc;
+ }
+ };
+
+ Lock _lock;
+ Range_list _ranges;
+
+ Range *_lookup(RTIOPORT PortStart, RTUINT cPorts)
+ {
+ for (Range *r = _ranges.first(); r; r = r->next())
+ if (r->contains(PortStart, cPorts))
+ return r;
+
+ return 0;
+ }
+
+ public:
+
+ int add_range(PPDMDEVINS pDevIns,
+ RTIOPORT PortStart, RTUINT cPorts, RTHCPTR pvUser,
+ R3PTRTYPE(PFNIOMIOPORTOUT) pfnOutCallback,
+ R3PTRTYPE(PFNIOMIOPORTIN) pfnInCallback,
+ R3PTRTYPE(PFNIOMIOPORTOUTSTRING) pfnOutStringCallback,
+ R3PTRTYPE(PFNIOMIOPORTINSTRING) pfnInStringCallback)
+ {
+ Range *r = _lookup(PortStart, cPorts);
+ if (r)
+ return VERR_GENERAL_FAILURE;
+
+ _ranges.insert(new (Genode::env()->heap())
+ Range(pDevIns, PortStart, cPorts, pvUser,
+ pfnOutCallback, pfnInCallback,
+ pfnOutStringCallback, pfnInStringCallback));
+
+ return VINF_SUCCESS;
+ }
+
+ int remove_range(PPDMDEVINS pDevIns, RTIOPORT PortStart, RTUINT cPorts)
+ {
+ bool deleted = false;
+
+ for (Range *r = _ranges.first(); r;)
+ {
+ if (!r->partof(PortStart, cPorts)) {
+ r = r->next();
+ continue;
+ }
+
+ deleted = true;
+
+ PERR("delete %x+%x", r->_PortStart, r->_cPorts);
+
+ Range *s = r;
+ r = r->next();
+ _ranges.remove(s);
+ }
+
+ return deleted ? VINF_SUCCESS : VERR_GENERAL_FAILURE;
+ }
+
+ VBOXSTRICTRC write(RTIOPORT Port, uint32_t u32Value, size_t cbValue)
+ {
+ Range *r = _lookup(Port, cbValue);
+ if (r)
+ return r->write(Port, u32Value, cbValue);
+
+ char c = u32Value & 0xff;
+// PWRN("attempted to write to non-existing port 0x%lx+%u %c (%02x)", Port, cbValue,
+// c >= 32 && c <= 176 ? c : '.', c);
+ return VINF_SUCCESS;
+// return VERR_GENERAL_FAILURE; /* recompiler does not like this */
+ }
+
+ VBOXSTRICTRC read(RTIOPORT port, uint32_t *pu32Value, unsigned cbValue)
+ {
+ Range *r = _lookup(port, cbValue);
+ if (r) {
+ VBOXSTRICTRC err = r->read(port, pu32Value, cbValue);
+ if (err != VERR_IOM_IOPORT_UNUSED)
+ return err;
+ }
+
+// PWRN("attempted to read from non-existing port 0x%x+%u %p", port, cbValue, r);
+
+ switch (cbValue)
+ {
+ case 1:
+ *reinterpret_cast(pu32Value) = 0xFFU;
+ break;
+ case 2:
+ *reinterpret_cast(pu32Value) = 0xFFFFU;
+ break;
+ case 4:
+ *reinterpret_cast(pu32Value) = 0xFFFFFFFFU;
+ break;
+ default:
+ PERR("Invalid I/O port (%x) access of size (%x)", port, cbValue);
+ return VERR_IOM_INVALID_IOPORT_SIZE;
+ }
+ return VINF_SUCCESS;
+// return VERR_IOM_IOPORT_UNUSED; /* recompiler does not like this */
+ }
+};
+
+
+/**
+ * Return pointer to singleton instance
+ */
+Guest_ioports *guest_ioports()
+{
+ static Guest_ioports inst;
+ return &inst;
+}
+
+
+int
+IOMR3IOPortRegisterR3(PVM pVM, PPDMDEVINS pDevIns,
+ RTIOPORT PortStart, RTUINT cPorts, RTHCPTR pvUser,
+ R3PTRTYPE(PFNIOMIOPORTOUT) pfnOutCallback,
+ R3PTRTYPE(PFNIOMIOPORTIN) pfnInCallback,
+ R3PTRTYPE(PFNIOMIOPORTOUTSTRING) pfnOutStringCallback,
+ R3PTRTYPE(PFNIOMIOPORTINSTRING) pfnInStringCallback,
+ const char *pszDesc)
+{
+ PLOG("register I/O port range 0x%x-0x%x '%s'",
+ PortStart, PortStart + cPorts - 1, pszDesc);
+
+ return guest_ioports()->add_range(pDevIns, PortStart, cPorts, pvUser,
+ pfnOutCallback, pfnInCallback,
+ pfnOutStringCallback, pfnInStringCallback);
+}
+
+
+int IOMR3IOPortDeregister(PVM pVM, PPDMDEVINS pDevIns, RTIOPORT PortStart,
+ RTUINT cPorts)
+{
+ PLOG("deregister I/O port range 0x%x-0x%x",
+ PortStart, PortStart + cPorts - 1);
+
+ return guest_ioports()->remove_range(pDevIns, PortStart, cPorts);
+}
+
+
+VMMDECL(VBOXSTRICTRC) IOMIOPortWrite(PVM pVM, RTIOPORT Port, uint32_t u32Value,
+ size_t cbValue)
+{
+// PDBG("IOMIOPortWrite Port=0x%lx cbValue=%zd", (long)Port, cbValue);
+ return guest_ioports()->write(Port, u32Value, cbValue);
+}
+
+
+VMMDECL(VBOXSTRICTRC) IOMIOPortRead(PVM pVM, RTIOPORT Port, uint32_t *pu32Value,
+ size_t cbValue)
+{
+ return guest_ioports()->read(Port, pu32Value, cbValue);
+}
diff --git a/ports/src/virtualbox/libc.cc b/ports/src/virtualbox/libc.cc
new file mode 100644
index 0000000000..94609348e0
--- /dev/null
+++ b/ports/src/virtualbox/libc.cc
@@ -0,0 +1,127 @@
+/*
+ * \brief VirtualBox runtime (RT)
+ * \author Norman Feske
+ * \date 2013-08-20
+ */
+
+/*
+ * Copyright (C) 2013 Genode Labs GmbH
+ *
+ * This file is distributed under the terms of the GNU General Public License
+ * version 2.
+ */
+
+/* Genode includes */
+#include
+#include
+
+/* libc includes */
+#include
+#include
+
+/* libc memory allocator */
+#include
+
+/* VirtualBox includes */
+#include
+
+using Genode::size_t;
+
+
+/*
+ * We cannot use the libc's version of malloc because it does not satisfies
+ * the alignment constraints asserted by 'Runtime/r3/alloc.cpp'.
+ */
+
+extern "C" void *malloc(size_t size)
+{
+ return Libc::mem_alloc()->alloc(size, Genode::log2(RTMEM_ALIGNMENT));
+}
+
+
+extern "C" void *calloc(size_t nmemb, size_t size)
+{
+ void *ret = malloc(nmemb*size);
+ Genode::memset(ret, 0, nmemb*size);
+ return ret;
+}
+
+
+extern "C" void free(void *ptr)
+{
+ Libc::mem_alloc()->free(ptr);
+}
+
+
+extern "C" void *realloc(void *ptr, Genode::size_t size)
+{
+ if (!ptr)
+ return malloc(size);
+
+ if (!size) {
+ free(ptr);
+ return 0;
+ }
+
+ /* determine size of old block content (without header) */
+ unsigned long old_size = Libc::mem_alloc()->size_at(ptr);
+
+ /* do not reallocate if new size is less than the current size */
+ if (size <= old_size)
+ return ptr;
+
+ /* allocate new block */
+ void *new_addr = malloc(size);
+
+ /* copy content from old block into new block */
+ if (new_addr)
+ Genode::memcpy(new_addr, ptr, Genode::min(old_size, (unsigned long)size));
+
+ /* free old block */
+ free(ptr);
+
+ return new_addr;
+}
+
+
+extern "C" char *getenv(const char *name)
+{
+ /*
+ * Logging to the pseudo file '/log' is done via the libc plugin provided
+ * by 'logging.cc'.
+ */
+ if (Genode::strcmp(name, "VBOX_LOG_DEST") == 0 ||
+ Genode::strcmp(name, "VBOX_RELEASE_LOG_DEST") == 0)
+ return (char *)"file=log";
+
+ if (Genode::strcmp(name, "VBOX_LOG") == 0 ||
+ Genode::strcmp(name, "VBOX_RELEASE_LOG") == 0)
+ return (char *)"+rem_dias.e.l.f"
+ "+rem_printf.e.l.f"
+// "+rem_run.e.l.f"
+// "+pgm.e.l.f"
+ "+pdm"
+// "+dev_pic.e.l.f"
+// "+dev_apic.e.l.f"
+ ;
+
+ if (Genode::strcmp(name, "VBOX_LOG_FLAGS") == 0 ||
+ Genode::strcmp(name, "VBOX_RELEASE_LOG_FLAGS") == 0)
+ return (char *)"thread";
+
+ PWRN("getenv called for non-existent variable \"%s\"", name);
+ return 0;
+}
+
+
+extern "C" int sigaction(int signum, const struct sigaction *act,
+ struct sigaction *oldact)
+{
+ /*
+ * Break infinite loop at 'VBox/Runtime/r3/init.cpp' :451
+ */;
+ if (oldact)
+ oldact->sa_flags = SA_SIGINFO;
+
+ return 0;
+}
diff --git a/ports/src/virtualbox/logger.cc b/ports/src/virtualbox/logger.cc
new file mode 100644
index 0000000000..5d9dcf390f
--- /dev/null
+++ b/ports/src/virtualbox/logger.cc
@@ -0,0 +1,149 @@
+/*
+ * \brief Redirect VirtualBox LOG output to Genode LOG
+ * \author Norman Feske
+ * \date 2013-08-23
+ */
+
+/*
+ * Copyright (C) 2013 Genode Labs GmbH
+ *
+ * This file is distributed under the terms of the GNU General Public License
+ * version 2.
+ */
+
+/* libc plugin interface */
+#include
+#include
+
+/* libc includes */
+#include
+#include
+#include
+
+/* interface to 'log_console' */
+extern "C" int stdout_write(const char *);
+
+
+namespace {
+
+ struct Plugin_context : Libc::Plugin_context { };
+
+ class Plugin : public Libc::Plugin
+ {
+ private:
+
+ Plugin_context _context;
+
+ Libc::File_descriptor *_fd;
+
+ char const *log_file_name() const { return "/log"; }
+
+ bool _match(char const *name) const
+ {
+ return strcmp(name, log_file_name()) == 0;
+ }
+
+ public:
+
+ Plugin() :
+ _fd(Libc::file_descriptor_allocator()->alloc(this, &_context))
+ { }
+
+ bool supports_stat(const char *path)
+ {
+ return _match(path);
+ }
+
+ bool supports_open(const char *path, int flags)
+ {
+ return _match(path);
+ }
+
+ int stat(const char *path, struct stat *buf)
+ {
+ bool const match = _match(path);
+ if (buf && match) {
+ Genode::memset(buf, 0, sizeof(struct stat));
+ buf->st_mode = S_IFCHR;
+ }
+
+ errno = match ? 0 : ENOENT;
+ return match ? 0 : -1;
+ }
+
+ Libc::File_descriptor *open(const char *pathname, int flags)
+ {
+ return _match(pathname) ? _fd : 0;
+ }
+
+ int fcntl(Libc::File_descriptor *fd, int cmd, long arg)
+ {
+ switch (cmd) {
+ case F_GETFL: return O_WRONLY;
+ default: PERR("fcntl(): command %d not supported", cmd); return -1;
+ }
+ }
+
+ int fstat(Libc::File_descriptor *, struct stat *buf)
+ {
+ /*
+ * The following values were obtained with small test program that
+ * calls fstat for stdout on linux.
+ */
+ buf->st_dev = 11;
+ buf->st_ino = 4;
+ buf->st_mode = 8592;
+ buf->st_nlink = 1;
+ buf->st_uid = 0;
+ buf->st_gid = 0;
+ buf->st_rdev = 34818;
+ buf->st_size = 0;
+ buf->st_blksize = 1024;
+ buf->st_blocks = 0;
+
+ return 0;
+ }
+
+ ssize_t write(Libc::File_descriptor *fd, const void *buf, ::size_t count)
+ {
+ if (fd != _fd) {
+ errno = EBADF;
+ return -1;
+ }
+
+ char *src = (char *)buf;
+
+ /* count does not include the trailing '\0' */
+ int orig_count = count;
+ while (count > 0) {
+ char tmp[128];
+ int curr_count= count > sizeof(tmp) - 1 ? sizeof(tmp) - 1 : count;
+ strncpy(tmp, src, curr_count);
+ tmp[curr_count > 0 ? curr_count : 0] = 0;
+ stdout_write(tmp);
+ count -= curr_count;
+ src += curr_count;
+ }
+ return orig_count;
+ }
+
+ int ioctl(Libc::File_descriptor *, int request, char *)
+ {
+ /*
+ * Some programs or libraries use to perform 'TIOCGETA'
+ * operations on stdout, in particular the termios module of
+ * Python. Those programs may break if 'tcgetattr' return with
+ * an error. We pretend to be more successful than we really
+ * are to make them happy.
+ */
+ return 0;
+ }
+ };
+
+} /* unnamed namespace */
+
+
+void __attribute__((constructor)) init_libc_log(void)
+{
+ static Plugin plugin;
+}
diff --git a/ports/src/virtualbox/main.cc b/ports/src/virtualbox/main.cc
new file mode 100644
index 0000000000..0b05fd3c08
--- /dev/null
+++ b/ports/src/virtualbox/main.cc
@@ -0,0 +1,214 @@
+/*
+ * \brief Port of VirtualBox to Genode
+ * \author Norman Feske
+ * \date 2013-08-20
+ */
+
+/*
+ * Copyright (C) 2013 Genode Labs GmbH
+ *
+ * This file is distributed under the terms of the GNU General Public License
+ * version 2.
+ */
+
+/* Genode includes */
+#include
+#include
+
+#include
+#include
+
+/* libc includes */
+#include
+
+/* Virtualbox includes of VBoxBFE */
+#include
+#include
+
+void *operator new (Genode::size_t size) {
+ return Genode::env()->heap()->alloc(size); }
+
+void operator delete(void * p) {
+ if (Genode::env()->heap()->need_size_for_free()) {
+ PERR("leaking memory - delete operator is missing size information");
+ return;
+ }
+ Genode::env()->heap()->free(p, 0);
+}
+
+extern "C" {
+
+/* string conversion function currently does not convert ... */
+int RTStrCurrentCPToUtf8Tag(char **ppszString, char *pszString,
+ const char *pszTag)
+{
+ /* dangerous */
+ *ppszString = pszString;
+ return 0;
+}
+
+/* don't use 'Runtime/r3/posix/utf8-posix.cpp' because it depends on libiconv */
+int RTStrUtf8ToCurrentCPTag(char **ppszString, char *pszString,
+ const char *pszTag)
+{
+ /* dangerous */
+ *ppszString = pszString;
+ return 0;
+}
+
+
+char * RTPathRealDup(const char *pszPath)
+{
+ /* dangerous */
+ return (char *)pszPath;
+}
+
+
+bool RTPathExists(const char *pszPath)
+{
+ return true;
+}
+
+
+/* make output of Virtualbox visible */
+size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream)
+{
+ if (!stream || !ptr ||
+ !(fileno(stdout) == fileno(stream) || fileno(stderr) == fileno(stream)))
+ return EOF;
+
+ char const * cptr = reinterpret_cast(ptr);
+ for (size_t j = 0; j < nmemb; j++)
+ for (size_t i = 0; i < size; i++)
+ Genode::printf("%c", cptr[j * size + i]);
+
+ return nmemb;
+}
+
+int fprintf(FILE *stream, const char *format, ...) /* called by RTAssertMsg1 */
+{
+ if (!stream ||
+ !(fileno(stdout) == fileno(stream) || fileno(stderr) == fileno(stream)))
+ return EOF;
+
+ va_list list;
+ va_start(list, format);
+
+ Genode::vprintf(format, list);
+
+ va_end(list);
+
+ return 0;
+}
+
+int fputs(const char *s, FILE *stream) /* called by RTAssertMsg2Weak */
+{
+ if (!stream ||
+ !(fileno(stdout) == fileno(stream) || fileno(stderr) == fileno(stream)))
+ return EOF;
+
+ fwrite(s, Genode::strlen(s), 1, stream);
+}
+
+/* our libc provides a _nanosleep function */
+int _nanosleep(const struct timespec *req, struct timespec *rem);
+int nanosleep(const struct timespec *req, struct timespec *rem) {
+ return _nanosleep(req, rem); }
+
+
+/*
+ * Genode way of using a configuration. Wrap VBox main until we throught it
+ * out eventually.
+ */
+
+/* main function of VBox is in Frontends/VBoxBFE/VBoxBFE.cpp */
+extern "C" DECLEXPORT(int) TrustedMain (int argc, char **argv, char **envp);
+
+int main(int, char **)
+{
+ static char c_mem[16];
+ static char c_type[4];
+ static char c_file[128];
+ static bool bOverlay = false;
+
+ int argc = 9;
+ char * argv[argc + 1];
+
+ /* request max available memory */
+ size_t vm_size = Genode::env()->ram_session()->avail();
+
+ enum { VMM_MEMORY = 64 * 1024 * 1024 /* let a bit memory for the VMM */ };
+ if (vm_size < VMM_MEMORY) {
+ PERR("not enough memory available - need %u, available only %zu "
+ "- exit", VMM_MEMORY, vm_size);
+ return 1;
+ }
+ vm_size -= VMM_MEMORY;
+
+ try {
+ using namespace Genode;
+
+ Xml_node node = config()->xml_node().sub_node("image");
+ Xml_node::Attribute type = node.attribute("type");
+ Xml_node::Attribute file = node.attribute("file");
+ try {
+ Xml_node::Attribute overlay = node.attribute("overlay");
+ overlay.value(c_type, sizeof(c_type));
+ if (!strcmp(c_type, "yes"))
+ bOverlay = true;
+ } catch (...) { }
+ type.value(c_type, sizeof(c_type));
+ file.value(c_file, sizeof(c_file));
+ } catch (...) {
+ PERR("C++ exception during xml parsing");
+ return 2;
+ }
+
+ argv[0] = (char *)"virtualbox";
+ argv[1] = (char *)"-m";
+
+ Genode::snprintf(c_mem, sizeof(c_mem), "%u", vm_size / 1024 / 1024);
+ argv[2] = c_mem;
+ argv[3] = (char *)"-boot";
+
+ if (!Genode::strcmp(c_type, "iso")) {
+ argv[4] = (char *)"d";
+ argv[5] = (char *)"-cdrom";
+ } else
+ if (!Genode::strcmp(c_type, "vdi")) {
+ argv[4] = (char *)"c";
+ argv[5] = (char *)"-hda";
+ } else {
+ PERR("invalid configuration - abort");
+ return 3;
+ }
+
+ argv[6] = c_file;
+ argv[7] = (char *)"-ioapic";
+
+ if (9 > argc + 1) {
+ PERR("argc argv misconfiguration - abort");
+ return 4;
+ }
+
+ if (bOverlay)
+ argv[8] = (char *)"-overlay";
+ else {
+ argc -= 1;
+ argv[8] = 0;
+ }
+ argv[9] = 0;
+
+ PINF("start %s image '%s' with %zu MB Guest memory=%zu",
+ c_type, c_file, vm_size / 1024 / 1024,
+ Genode::env()->ram_session()->avail());
+
+ if (RT_FAILURE(RTR3InitExe(argc, (char ***)&argv, 0))) {
+ PERR("Intialization of VBox Runtime failed.");
+ return 5;
+ }
+
+ return TrustedMain(argc, argv, NULL);
+}
+
+} /* EXTERN "C" */
diff --git a/ports/src/virtualbox/mm.cc b/ports/src/virtualbox/mm.cc
new file mode 100644
index 0000000000..5c9ab123d7
--- /dev/null
+++ b/ports/src/virtualbox/mm.cc
@@ -0,0 +1,313 @@
+/*
+ * \brief VirtualBox memory manager (MMR3)
+ * \author Norman Feske
+ * \date 2013-08-20
+ */
+
+/*
+ * Copyright (C) 2013 Genode Labs GmbH
+ *
+ * This file is distributed under the terms of the GNU General Public License
+ * version 2.
+ */
+
+/* Genode includes */
+#include
+#include
+
+/* VirtualBox includes */
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+/* libc memory allocator */
+#include
+
+#include "util.h"
+
+
+int MMR3Init(PVM pVM)
+{
+ PDBG("MMR3Init called, not implemented");
+ return VINF_SUCCESS;
+}
+
+
+int MMR3InitUVM(PUVM pUVM)
+{
+ PDBG("MMR3InitUVM called, not implemented");
+ return VINF_SUCCESS;
+}
+
+
+void *MMR3HeapAllocU(PUVM pUVM, MMTAG enmTag, size_t cbSize)
+{
+ return Libc::mem_alloc()->alloc(cbSize, Genode::log2(RTMEM_ALIGNMENT));
+}
+
+
+/**
+ * Return alignment to be used for allocations of given tag
+ */
+static unsigned align_by_mmtag(MMTAG enmTag)
+{
+ switch (enmTag) {
+ case MM_TAG_PDM_DEVICE:
+ case MM_TAG_PDM_DEVICE_USER:
+ return 12;
+ default:
+ return Genode::log2(RTMEM_ALIGNMENT);
+ }
+}
+
+
+/**
+ * Round allocation size for a given tag
+ */
+static size_t round_size_by_mmtag(MMTAG enmTag, size_t cb)
+{
+ return Genode::align_addr(cb, align_by_mmtag(enmTag));
+}
+
+
+void *MMR3HeapAlloc(PVM pVM, MMTAG enmTag, size_t cbSize)
+{
+ size_t const rounded_size = round_size_by_mmtag(enmTag, cbSize);
+
+ void *ret = Libc::mem_alloc()->alloc(rounded_size, align_by_mmtag(enmTag));
+
+// PINF("MMR3HeapAlloc: enmTag=%d cbSize=0x%zx -> 0x%p (0x%zx)",
+// enmTag, cbSize, ret, rounded_size);
+
+ return ret;
+}
+
+
+void *MMR3HeapAllocZ(PVM pVM, MMTAG enmTag, size_t cbSize)
+{
+ void * const ret = MMR3HeapAlloc(pVM, enmTag, cbSize);
+
+ if (ret)
+ Genode::memset(ret, 0, cbSize);
+
+ return ret;
+}
+
+
+int MMR3HeapAllocZEx(PVM pVM, MMTAG enmTag, size_t cbSize, void **ppv)
+{
+ *ppv = MMR3HeapAllocZ(pVM, enmTag, cbSize);
+
+ return VINF_SUCCESS;
+}
+
+
+int MMR3HyperAllocOnceNoRel(PVM pVM, size_t cb, unsigned uAlignment,
+ MMTAG enmTag, void **ppv)
+{
+ unsigned const align_log2 = uAlignment ? Genode::log2(uAlignment)
+ : align_by_mmtag(enmTag);
+
+ size_t const rounded_size = round_size_by_mmtag(enmTag, cb);
+
+ void *ret = Libc::mem_alloc()->alloc(rounded_size, align_log2);
+ if (ret)
+ Genode::memset(ret, 0, cb);
+
+ PINF("MMR3HyperAllocOnceNoRel: enmTag=%d align_log2=%u cb=0x%zx -> 0x%p",
+ enmTag, align_log2, cb, ret);
+
+ *ppv = ret;
+
+ return VINF_SUCCESS;
+}
+
+
+int MMR3HyperAllocOnceNoRelEx(PVM pVM, size_t cb, uint32_t uAlignment,
+ MMTAG enmTag, uint32_t fFlags, void **ppv)
+{
+ return MMR3HyperAllocOnceNoRel(pVM, cb, uAlignment, enmTag, ppv);
+}
+
+
+int MMHyperAlloc(PVM pVM, size_t cb, unsigned uAlignment, MMTAG enmTag, void **ppv)
+{
+ AssertRelease(align_by_mmtag(enmTag) >= uAlignment);
+
+ *ppv = MMR3HeapAllocZ(pVM, enmTag, cb);
+ return VINF_SUCCESS;
+}
+
+
+int MMHyperFree(PVM pVM, void *pv)
+{
+ Libc::mem_alloc()->free(pv);
+
+ return VINF_SUCCESS;
+}
+
+
+void MMR3HeapFree(void *pv) { Libc::mem_alloc()->free(pv); }
+
+
+RTR0PTR MMHyperR3ToR0(PVM pVM, RTR3PTR R3Ptr) { return (RTR0PTR)R3Ptr; }
+RTRCPTR MMHyperR3ToRC(PVM pVM, RTR3PTR R3Ptr) { return to_rtrcptr(R3Ptr); }
+RTR0PTR MMHyperCCToR0(PVM pVM, void *pv) { return (RTR0PTR)pv; }
+RTRCPTR MMHyperCCToRC(PVM pVM, void *pv) { return to_rtrcptr(pv); }
+
+
+uint64_t MMR3PhysGetRamSize(PVM pVM)
+{
+ PDBG("MMR3PhysGetRamSize called, return 0");
+
+ /* when called from REMR3Init, it is expected to return 0 */
+ return 0;
+}
+
+
+int MMR3HyperMapHCPhys(PVM pVM, void *pvR3, RTR0PTR pvR0, RTHCPHYS HCPhys,
+ size_t cb, const char *pszDesc, PRTGCPTR pGCPtr)
+{
+ PDBG("pszDesc=%s", pszDesc);
+
+ *pGCPtr = (RTGCPTR)HCPhys;
+
+ return VINF_SUCCESS;
+}
+
+
+int MMR3HyperReserve(PVM pVM, unsigned cb, const char *pszDesc, PRTGCPTR pGCPtr)
+{
+ PINF("MMR3HyperReserve: cb=0x%x, pszDesc=%s", cb, pszDesc);
+
+ return VINF_SUCCESS;
+}
+
+
+int MMR3HyperMapMMIO2(PVM pVM, PPDMDEVINS pDevIns, uint32_t iRegion,
+ RTGCPHYS off, RTGCPHYS cb, const char *pszDesc,
+ PRTRCPTR pRCPtr)
+{
+ PLOG("MMR3HyperMapMMIO2: pszDesc=%s iRegion=%u off=0x%lx cb=0x%zx",
+ pszDesc, iRegion, (long)off, (size_t)cb);
+
+
+
+ return VINF_SUCCESS;
+}
+
+
+/*
+ * Based on 'VBox/VMM/VMMR3/MM.cpp'
+ */
+int MMR3InitPaging(PVM pVM)
+{
+ /*
+ * Query the CFGM values.
+ */
+ int rc;
+ PCFGMNODE pMMCfg = CFGMR3GetChild(CFGMR3GetRoot(pVM), "MM");
+ if (!pMMCfg)
+ {
+ rc = CFGMR3InsertNode(CFGMR3GetRoot(pVM), "MM", &pMMCfg);
+ AssertRCReturn(rc, rc);
+ }
+
+ /** @cfgm{RamSize, uint64_t, 0, 16TB, 0}
+ * Specifies the size of the base RAM that is to be set up during
+ * VM initialization.
+ */
+ uint64_t cbRam;
+ rc = CFGMR3QueryU64(CFGMR3GetRoot(pVM), "RamSize", &cbRam);
+ if (rc == VERR_CFGM_VALUE_NOT_FOUND)
+ cbRam = 0;
+ else
+ AssertMsgRCReturn(rc, ("Configuration error: Failed to query integer \"RamSize\", rc=%Rrc.\n", rc), rc);
+ cbRam &= X86_PTE_PAE_PG_MASK;
+
+ /** @cfgm{RamHoleSize, uint32_t, 0, 4032MB, 512MB}
+ * Specifies the size of the memory hole. The memory hole is used
+ * to avoid mapping RAM to the range normally used for PCI memory regions.
+ * Must be aligned on a 4MB boundary. */
+ uint32_t cbRamHole;
+ rc = CFGMR3QueryU32Def(CFGMR3GetRoot(pVM), "RamHoleSize", &cbRamHole, MM_RAM_HOLE_SIZE_DEFAULT);
+ uint64_t const offRamHole = _4G - cbRamHole;
+
+ /*
+ * Make the initial memory reservation with GMM.
+ */
+ PDBG("GMMR3InitialReservation missing");
+
+ /*
+ * If RamSize is 0 we're done now.
+ */
+ if (cbRam < PAGE_SIZE)
+ {
+ Log(("MM: No RAM configured\n"));
+ return VINF_SUCCESS;
+ }
+
+ /*
+ * Setup the base ram (PGM).
+ */
+ if (cbRam > offRamHole)
+ {
+ rc = PGMR3PhysRegisterRam(pVM, 0, offRamHole, "Base RAM");
+ if (RT_SUCCESS(rc))
+ rc = PGMR3PhysRegisterRam(pVM, _4G, cbRam - offRamHole, "Above 4GB Base RAM");
+ }
+ else
+ rc = PGMR3PhysRegisterRam(pVM, 0, RT_MIN(cbRam, offRamHole), "Base RAM");
+
+ LogFlow(("MMR3InitPaging: returns %Rrc\n", rc));
+ return rc;
+}
+
+
+char * MMR3HeapStrDup(PVM pVM, MMTAG enmTag, const char *psz)
+{
+ size_t cch = strlen(psz) + 1;
+ char *pszDup = (char *)MMR3HeapAllocU(pVM->pUVM, enmTag, cch);
+ if (pszDup)
+ memcpy(pszDup, psz, cch);
+
+ return pszDup;
+}
+
+
+char * MMR3HeapAPrintfVU(PUVM pUVM, MMTAG enmTag, const char *pszFormat, va_list va)
+{
+ /*
+ * The lazy bird way.
+ */
+ char *psz;
+ int cch = RTStrAPrintfV(&psz, pszFormat, va);
+ if (cch < 0)
+ return NULL;
+ Assert(psz[cch] == '\0');
+ char *pszRet = (char *)MMR3HeapAllocU(pUVM, enmTag, cch + 1);
+ if (pszRet)
+ memcpy(pszRet, psz, cch + 1);
+ RTStrFree(psz);
+ return pszRet;
+}
+
+
+extern "C" {
+
+char * MMR3HeapAPrintf(PVM pVM, MMTAG enmTag, const char *pszFormat, ...)
+{
+ va_list va;
+ va_start(va, pszFormat);
+ char *psz = MMR3HeapAPrintfVU(pVM->pUVM, enmTag, pszFormat, va);
+ va_end(va);
+ return psz;
+}
+
+}
diff --git a/ports/src/virtualbox/nova/sup.cc b/ports/src/virtualbox/nova/sup.cc
new file mode 100644
index 0000000000..fd755eb35b
--- /dev/null
+++ b/ports/src/virtualbox/nova/sup.cc
@@ -0,0 +1,234 @@
+/*
+ * \brief Genode/Nova specific VirtualBox SUPLib supplements
+ * \author Alexander Boettcher
+ * \author Norman Feske
+ * \author Christian Helmuth
+ */
+
+/*
+ * Copyright (C) 2013-2014 Genode Labs GmbH
+ *
+ * This file is distributed under the terms of the GNU General Public License
+ * version 2.
+ */
+
+/* Genode includes */
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+
+/* NOVA includes that come with Genode */
+#include
+
+/* VirtualBox includes */
+#include "HWACCMInternal.h" /* enable access to hwaccm.s.* */
+#include "CPUMInternal.h" /* enable access to cpum.s.* */
+#include
+#include
+#include
+
+/* Genode's VirtualBox includes */
+#include "vcpu.h"
+#include "vcpu_svm.h"
+#include "vcpu_vmx.h"
+
+
+static Vcpu_handler *vcpu_handler = 0;
+
+
+static Genode::Semaphore *r0_halt_sem()
+{
+ static Genode::Semaphore sem;
+ return &sem;
+}
+
+
+/* Genode specific function */
+
+void SUPR3QueryHWACCLonGenodeSupport(VM * pVM) {
+ try {
+ using namespace Genode;
+
+ Rom_connection hip_rom("hypervisor_info_page");
+
+ Nova::Hip * const hip = env()->rm_session()->attach(hip_rom.dataspace());
+
+ if (!hip)
+ return;
+
+ pVM->hwaccm.s.svm.fSupported = hip->has_feature_svm();
+ pVM->hwaccm.s.vmx.fSupported = hip->has_feature_vmx();
+
+ } catch (...) {
+ PWRN("No hardware acceleration available - execution will be slow!");
+ } /* if we get an exception let hardware support off */
+}
+
+
+void SUPR3QueryHWACCLonGenodeCreateVM(VM * pVM)
+{
+ bool svm = pVM->hwaccm.s.svm.fSupported;
+
+ if (!svm && !pVM->hwaccm.s.vmx.fSupported) {
+ PERR("SVM nor VMX supported by hardware accelerated code called !");
+ return;
+ }
+
+ Assert(!vcpu_handler);
+
+ if (svm)
+ vcpu_handler = new Vcpu_handler_svm();
+ else
+ vcpu_handler = new Vcpu_handler_vmx();
+
+}
+
+
+/* VirtualBox SUPLib interface */
+int SUPR3QueryVTxSupported(void)
+{
+ return VINF_SUCCESS;
+}
+
+
+int SUPR3CallVMMR0Fast(PVMR0 pVMR0, unsigned uOperation, VMCPUID idCpu)
+{
+ switch (uOperation)
+ {
+ case SUP_VMMR0_DO_HWACC_RUN:
+ {
+
+ VM * pVM = reinterpret_cast(pVMR0);
+ PVMCPU pVCpu = &pVM->aCpus[idCpu];
+ PCPUMCTX pCtx = CPUMQueryGuestCtxPtr(pVCpu);
+
+ return vcpu_handler->run_hw(pVMR0, idCpu);
+ }
+
+ default:
+ break;
+
+ }
+ return VERR_INTERNAL_ERROR;
+}
+
+
+int SUPR3CallVMMR0Ex(PVMR0 pVMR0, VMCPUID idCpu, unsigned
+ uOperation, uint64_t u64Arg, PSUPVMMR0REQHDR pReqHdr)
+{
+ static unsigned counter = 0;
+
+ switch(uOperation)
+ {
+ case VMMR0_DO_GVMM_CREATE_VM:
+ genode_VMMR0_DO_GVMM_CREATE_VM(pReqHdr);
+ return VINF_SUCCESS;
+
+ case VMMR0_DO_GVMM_SCHED_HALT:
+// counter ++;
+// PERR("halt %u", counter);
+ r0_halt_sem()->down();
+// PERR("halt - done");
+ return VINF_SUCCESS;
+
+ case VMMR0_DO_GVMM_SCHED_WAKE_UP:
+// counter ++;
+// PERR("sched wake up %u", counter);
+ r0_halt_sem()->up();
+ return VINF_SUCCESS;
+
+ case VMMR0_DO_GVMM_SCHED_POLL:
+ /* called by 'vmR3HaltGlobal1Halt' */
+// PDBG("SUPR3CallVMMR0Ex: VMMR0_DO_GVMM_SCHED_POLL");
+ return VINF_SUCCESS;
+
+ case VMMR0_DO_VMMR0_INIT:
+ {
+ VM * pVM = reinterpret_cast(pVMR0);
+ SUPR3QueryHWACCLonGenodeSupport(pVM);
+ return VINF_SUCCESS;
+ }
+ case VMMR0_DO_HWACC_SETUP_VM:
+ {
+ VM * pVM = reinterpret_cast(pVMR0);
+ SUPR3QueryHWACCLonGenodeCreateVM(pVM);
+ return VINF_SUCCESS;
+ }
+ case VMMR0_DO_HWACC_ENABLE:
+ return VINF_SUCCESS;
+
+ case VMMR0_DO_GVMM_SCHED_POKE:
+ {
+ /* XXX only do one of it - either recall or up - not both XXX */
+ vcpu_handler->recall();
+ r0_halt_sem()->up();
+ return VINF_SUCCESS;
+ }
+
+ default:
+ PERR("SUPR3CallVMMR0Ex: unhandled uOperation %d", uOperation);
+ return VERR_GENERAL_FAILURE;
+ }
+}
+
+
+/**
+ * Various support stuff - base-nova specific.
+ */
+uint64_t genode_cpu_hz() {
+ static uint64_t cpu_freq = 0;
+
+ if (!cpu_freq) {
+ try {
+ using namespace Genode;
+
+ Rom_connection hip_rom("hypervisor_info_page");
+
+ Nova::Hip * const hip = env()->rm_session()->attach(hip_rom.dataspace());
+
+ cpu_freq = hip->tsc_freq * 1000;
+
+ } catch (...) {
+ PERR("could not read out CPU frequency.");
+ Genode::Lock lock;
+ lock.lock();
+ }
+ }
+
+ return cpu_freq;
+}
+
+
+extern "C" int pthread_yield() {
+ Nova::ec_ctrl(Nova::EC_YIELD);
+ return 0;
+}
+
+
+bool Vmm_memory::unmap_from_vm(RTGCPHYS GCPhys)
+{
+ size_t const size = 1;
+
+ Region *r = _lookup_unsynchronized(GCPhys, size);
+ if (!r) return false;
+
+ using Genode::addr_t;
+ addr_t const vmm_local = (addr_t)r->local_addr();
+
+ Assert(vmm_local);
+ Assert(!((r->size() - 1) & vmm_local));
+
+ using namespace Nova;
+ unsigned const order = Genode::log2(r->size() >> PAGE_SIZE_LOG2);
+
+ Rights rwx(true, true, true);
+ revoke(Mem_crd(vmm_local >> PAGE_SIZE_LOG2, order, rwx), false);
+
+ return true;
+}
diff --git a/ports/src/virtualbox/nova/svm.h b/ports/src/virtualbox/nova/svm.h
new file mode 100644
index 0000000000..60c02c88b5
--- /dev/null
+++ b/ports/src/virtualbox/nova/svm.h
@@ -0,0 +1,112 @@
+/*
+ * \brief Genode/Nova specific VirtualBox SUPLib supplements
+ * \author Norman Feske
+ * \author Alexander Boettcher
+ */
+
+/*
+ * Copyright (C) 2013-2014 Genode Labs GmbH
+ *
+ * This file is distributed under the terms of the GNU General Public License
+ * version 2.
+ */
+
+#ifndef _GENODE_VIRTUALBOX_SVM__H_
+#define _GENODE_VIRTUALBOX_SVM__H_
+
+/* based on HWSVMR0.h - adjusted to Genode/Nova */
+
+#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 = utcb->REG.sel; \
+ pCtx->REG.ValidSel = utcb->REG.sel; \
+ pCtx->REG.fFlags = CPUMSELREG_FLAGS_VALID; \
+ pCtx->REG.u32Limit = utcb->REG.limit; \
+ pCtx->REG.u64Base = utcb->REG.base; \
+ pCtx->REG.Attr.u = sel_ar_conv_from_nova(utcb->REG.ar)
+
+static inline bool svm_save_state(Nova::Utcb * utcb, 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);
+
+ 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);
+
+ 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); \
+ utcb->REG.sel = pCtx->REG.Sel; \
+ utcb->REG.limit = pCtx->REG.u32Limit; \
+ utcb->REG.base = pCtx->REG.u64Base; \
+ utcb->REG.ar = sel_ar_conv_to_nova(pCtx->REG.Attr.u)
+
+static inline bool svm_load_state(Nova::Utcb * utcb, VM * pVM, PVMCPU pVCpu)
+{
+ PCPUMCTX pCtx = CPUMQueryGuestCtxPtr(pVCpu);
+
+#ifdef __x86_64__
+ utcb->mtd |= Nova::Mtd::EFER;
+ utcb->efer = pCtx->msrEFER | MSR_K6_EFER_SVME;
+ /* unimplemented */
+ if (CPUMIsGuestInLongModeEx(pCtx))
+ return false;
+ utcb->efer &= ~MSR_K6_EFER_LME;
+#endif
+
+ utcb->mtd |= Nova::Mtd::ESDS;
+ GENODE_WRITE_SELREG(es);
+ GENODE_WRITE_SELREG(ds);
+
+ utcb->mtd |= Nova::Mtd::FSGS;
+ GENODE_WRITE_SELREG(fs);
+ GENODE_WRITE_SELREG(gs);
+
+ utcb->mtd |= Nova::Mtd::CSSS;
+ GENODE_WRITE_SELREG(cs);
+ GENODE_WRITE_SELREG(ss);
+
+ /* ldtr */
+ utcb->mtd |= Nova::Mtd::LDTR;
+ GENODE_WRITE_SELREG(ldtr);
+
+ /* tr */
+ utcb->mtd |= Nova::Mtd::TR;
+ GENODE_WRITE_SELREG(tr);
+
+ return true;
+}
+
+#undef GENODE_WRITE_SELREG
+
+#endif /* _GENODE_VIRTUALBOX_SVM__H_ */
diff --git a/ports/src/virtualbox/nova/vcpu.h b/ports/src/virtualbox/nova/vcpu.h
new file mode 100644
index 0000000000..380fbad83c
--- /dev/null
+++ b/ports/src/virtualbox/nova/vcpu.h
@@ -0,0 +1,756 @@
+/*
+ * \brief Genode/Nova specific VirtualBox SUPLib supplements
+ * \author Alexander Boettcher
+ * \author Norman Feske
+ * \author Christian Helmuth
+ */
+
+/*
+ * Copyright (C) 2013-2014 Genode Labs GmbH
+ *
+ * This file is distributed under the terms of the GNU General Public License
+ * version 2.
+ */
+
+#ifndef _VCPU_H__
+#define _VCPU_H__
+
+/* Genode includes */
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+
+/* NOVA includes that come with Genode */
+#include
+
+/* VirtualBox includes */
+#include
+#include
+#include
+
+/* Genode's VirtualBox includes */
+#include "sup.h"
+#include "guest_memory.h"
+#include "vmm_memory.h"
+
+/*
+ * VirtualBox stores segment attributes in Intel format using a 32-bit
+ * value. NOVA represents the attributes in packet format using a 16-bit
+ * value.
+ */
+static inline Genode::uint16_t sel_ar_conv_to_nova(Genode::uint32_t v)
+{
+ return (v & 0xff) | ((v & 0x1f000) >> 4);
+}
+
+
+static inline Genode::uint32_t sel_ar_conv_from_nova(Genode::uint16_t v)
+{
+ return (v & 0xff) | (((uint32_t )v << 4) & 0x1f000);
+}
+
+extern "C" int MMIO2_MAPPED_SYNC(PVM pVM, RTGCPHYS GCPhys, size_t cbWrite);
+
+
+class Vcpu_handler : public Vmm::Vcpu_dispatcher
+{
+ private:
+
+ enum { STACK_SIZE = 4096 };
+
+ Genode::Cap_connection _cap_connection;
+ Vmm::Vcpu_other_pd _vcpu;
+
+ Genode::addr_t _ec_sel = 0;
+
+
+ void fpu_save(char * data) {
+ Assert(!(reinterpret_cast(data) & 0xF));
+ asm volatile ("fxsave %0" : "=m" (*data));
+ }
+
+ void fpu_load(char * data) {
+ Assert(!(reinterpret_cast(data) & 0xF));
+ asm volatile ("fxrstor %0" : : "m" (*data));
+ }
+
+ protected:
+
+ /* unlocked by first startup exception */
+ Genode::Lock _lock_startup;
+ Genode::Lock _signal_vcpu;
+ Genode::Lock _signal_emt;
+
+ PVM _current_vm;
+ PVMCPU _current_vcpu;
+ unsigned _current_exit_cond;
+
+ __attribute__((noreturn)) void _default_handler(unsigned cond)
+ {
+ using namespace Nova;
+ using namespace Genode;
+
+ Thread_base *myself = Thread_base::myself();
+ Utcb *utcb = reinterpret_cast(myself->utcb());
+
+ /* tell caller what happened */
+ _current_exit_cond = cond;
+
+ PVMCPU pVCpu = _current_vcpu;
+ PCPUMCTX pCtx = CPUMQueryGuestCtxPtr(pVCpu);
+
+ fpu_save(reinterpret_cast(&pCtx->fpu));
+
+ /* unblock caller */
+ _signal_emt.unlock();
+
+ /* block myself */
+ _signal_vcpu.lock();
+
+ fpu_load(reinterpret_cast(&pCtx->fpu));
+ utcb->mtd |= Mtd::FPU;
+
+ Nova::reply(myself->stack_top());
+ }
+
+
+ template
+ __attribute__((noreturn)) inline
+ void _exc_memory(Genode::Thread_base * myself, Nova::Utcb * utcb,
+ bool unmap, Genode::addr_t reason)
+ {
+ using namespace Nova;
+ using namespace Genode;
+
+ if (unmap) {
+ PERR("unmap not implemented\n");
+
+ /* deadlock until implemented */
+ _signal_vcpu.lock();
+
+ Nova::reply(myself->stack_top());
+ }
+
+ Flexpage_iterator fli;
+ void *pv = guest_memory()->lookup_ram(reason, 0x1000UL, fli);
+
+ if (!pv) {
+ pv = vmm_memory()->lookup(reason, 0x1000UL);
+ if (pv) { /* XXX */
+ fli = Genode::Flexpage_iterator((addr_t)pv, 0x1000UL,
+ reason, 0x1000UL, reason);
+ int res = MMIO2_MAPPED_SYNC(_current_vm, reason, 0x1);
+/*
+ Genode::addr_t fb_phys = 0xf0000000UL;
+ Genode::addr_t fb_size = 0x00400000UL;
+ pv = vmm_memory()->lookup(fb_phys, fb_size);
+
+ fli = Genode::Flexpage_iterator((addr_t)pv, fb_size,
+ fb_phys, fb_size, fb_phys);
+ int res = MMIO2_MAPPED_SYNC(_current_vm, fb_phys, fb_size);
+*/
+ }
+ }
+
+ /* emulator has to take over if fault region is not ram */
+ if (!pv) {
+ /* tell caller what happened */
+ _current_exit_cond = NPT_EPT;
+
+ PVMCPU pVCpu = _current_vcpu;
+ PCPUMCTX pCtx = CPUMQueryGuestCtxPtr(pVCpu);
+
+ fpu_save(reinterpret_cast(&pCtx->fpu));
+
+ /* unblock caller */
+ _signal_emt.unlock();
+
+ /* block myself */
+ _signal_vcpu.lock();
+
+ fpu_load(reinterpret_cast(&pCtx->fpu));
+ utcb->mtd |= Mtd::FPU;
+
+ Nova::reply(myself->stack_top());
+ }
+
+ /* fault region is ram - so map it */
+ enum {
+ USER_PD = false, GUEST_PGT = true,
+ READABLE = true, WRITEABLE = true, EXECUTABLE = true
+ };
+ Rights const permission(READABLE, WRITEABLE, EXECUTABLE);
+
+ /* prepare utcb */
+ utcb->set_msg_word(0);
+ utcb->mtd = 0;
+
+ /* add map items until no space is left on utcb anymore */
+ bool res;
+ do {
+ Flexpage flexpage = fli.page();
+ if (!flexpage.valid() || flexpage.log2_order < 12)
+ break;
+
+ /* touch memory - otherwise no mapping will take place */
+ addr_t touch_me = flexpage.addr;
+ while (touch_me < flexpage.addr + (1UL << flexpage.log2_order)) {
+ touch_read(reinterpret_cast(touch_me));
+ touch_me += 0x1000UL;
+ }
+
+ Crd crd = Mem_crd(flexpage.addr >> 12, flexpage.log2_order - 12,
+ permission);
+ res = utcb->append_item(crd, flexpage.hotspot, USER_PD, GUEST_PGT);
+ } while (res);
+
+ Nova::reply(myself->stack_top());
+ }
+
+ /**
+ * Shortcut for calling 'Vmm::Vcpu_dispatcher::register_handler'
+ * with 'Vcpu_dispatcher' as template argument
+ */
+ template
+ void _register_handler(Genode::addr_t exc_base, Nova::Mtd mtd)
+ {
+ if (!register_handler(exc_base, mtd))
+ PERR("could not register handler %lx", exc_base + EV);
+ }
+
+
+ Vmm::Vcpu_other_pd &vcpu() { return _vcpu; }
+
+
+ inline bool vbox_to_utcb(Nova::Utcb * utcb, VM *pVM, PVMCPU pVCpu)
+ {
+ PCPUMCTX pCtx = CPUMQueryGuestCtxPtr(pVCpu);
+
+ using namespace Nova;
+
+ if (utcb->ip != pCtx->rip) {
+ utcb->mtd |= Mtd::EIP;
+ utcb->ip = pCtx->rip;
+ }
+
+ if (utcb->sp != pCtx->rsp) {
+ utcb->mtd |= Mtd::ESP;
+ utcb->sp = pCtx->rsp;
+ }
+
+ if (utcb->ax != pCtx->rax || utcb->bx != pCtx->rbx ||
+ utcb->cx != pCtx->rcx || utcb->dx != pCtx->rdx)
+ {
+ utcb->mtd |= Mtd::ACDB;
+ utcb->ax = pCtx->rax;
+ utcb->bx = pCtx->rbx;
+ utcb->cx = pCtx->rcx;
+ utcb->dx = pCtx->rdx;
+ }
+
+ if (utcb->bp != pCtx->rbp || utcb->si != pCtx->rsi ||
+ utcb->di != pCtx->rdi)
+ {
+ utcb->mtd |= Mtd::EBSD;
+ utcb->bp = pCtx->rbp;
+ utcb->si = pCtx->rsi;
+ utcb->di = pCtx->rdi;
+ }
+
+ if (utcb->flags != pCtx->rflags.u) {
+ utcb->mtd |= Mtd::EFL;
+ utcb->flags = pCtx->rflags.u;
+ }
+
+ if (utcb->sysenter_cs != pCtx->SysEnter.cs ||
+ utcb->sysenter_sp != pCtx->SysEnter.esp ||
+ utcb->sysenter_ip != pCtx->SysEnter.eip)
+ {
+ utcb->mtd |= Mtd::SYS;
+ utcb->sysenter_cs = pCtx->SysEnter.cs;
+ utcb->sysenter_sp = pCtx->SysEnter.esp;
+ utcb->sysenter_ip = pCtx->SysEnter.eip;
+ }
+
+ if (utcb->dr7 != pCtx->dr[7]) {
+ utcb->mtd |= Mtd::DR;
+ utcb->dr7 = pCtx->dr[7];
+ }
+
+ if (utcb->cr0 != pCtx->cr0) {
+ utcb->mtd |= Mtd::CR;
+ utcb->cr0 = pCtx->cr0;
+ }
+
+ if (utcb->cr2 != pCtx->cr2) {
+ utcb->mtd |= Mtd::CR;
+ utcb->cr2 = pCtx->cr2;
+ }
+
+ if (utcb->cr3 != pCtx->cr3) {
+ utcb->mtd |= Mtd::CR;
+ utcb->cr3 = pCtx->cr3;
+ }
+
+ if (utcb->cr4 != pCtx->cr4) {
+ utcb->mtd |= Mtd::CR;
+ utcb->cr4 = pCtx->cr4;
+ }
+
+ if (utcb->idtr.limit != pCtx->idtr.cbIdt ||
+ utcb->idtr.base != pCtx->idtr.pIdt)
+ {
+ utcb->mtd |= Mtd::IDTR;
+ utcb->idtr.limit = pCtx->idtr.cbIdt;
+ utcb->idtr.base = pCtx->idtr.pIdt;
+ }
+
+ if (utcb->gdtr.limit != pCtx->gdtr.cbGdt ||
+ utcb->gdtr.base != pCtx->gdtr.pGdt)
+ {
+ utcb->mtd |= Mtd::GDTR;
+ utcb->gdtr.limit = pCtx->gdtr.cbGdt;
+ utcb->gdtr.base = pCtx->gdtr.pGdt;
+ }
+
+ if (VMCPU_FF_ISSET(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS)) {
+ if (pCtx->rip != EMGetInhibitInterruptsPC(pVCpu)) {
+ PERR("intr_state nothing !=");
+ VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS);
+ utcb->intr_state = 0;
+ while (1) {}
+ }
+
+ }
+
+ return true;
+ }
+
+
+ inline bool utcb_to_vbox(Nova::Utcb * utcb, VM *pVM, PVMCPU pVCpu)
+ {
+ PCPUMCTX pCtx = CPUMQueryGuestCtxPtr(pVCpu);
+
+ pCtx->rip = utcb->ip;
+ pCtx->rsp = utcb->sp;
+
+ pCtx->rax = utcb->ax;
+ pCtx->rbx = utcb->bx;
+ pCtx->rcx = utcb->cx;
+ pCtx->rdx = utcb->dx;
+
+ pCtx->rbp = utcb->bp;
+ pCtx->rsi = utcb->si;
+ pCtx->rdi = utcb->di;
+ pCtx->rflags.u = utcb->flags;
+
+ pCtx->dr[7] = utcb->dr7;
+
+ if (pCtx->SysEnter.cs != utcb->sysenter_cs)
+ CPUMSetGuestMsr(pVCpu, MSR_IA32_SYSENTER_CS, utcb->sysenter_cs);
+
+ if (pCtx->SysEnter.esp != utcb->sysenter_sp)
+ CPUMSetGuestMsr(pVCpu, MSR_IA32_SYSENTER_ESP, utcb->sysenter_sp);
+
+ if (pCtx->SysEnter.eip != utcb->sysenter_ip)
+ CPUMSetGuestMsr(pVCpu, MSR_IA32_SYSENTER_EIP, utcb->sysenter_ip);
+
+ if (pCtx->idtr.cbIdt != utcb->idtr.limit ||
+ pCtx->idtr.pIdt != utcb->idtr.base)
+ CPUMSetGuestIDTR(pVCpu, utcb->idtr.base, utcb->idtr.limit);
+
+ if (pCtx->gdtr.cbGdt != utcb->gdtr.limit ||
+ pCtx->gdtr.pGdt != utcb->gdtr.base)
+ CPUMSetGuestGDTR(pVCpu, utcb->gdtr.base, utcb->gdtr.limit);
+
+ if (pCtx->cr0 != utcb->cr0)
+ CPUMSetGuestCR0(pVCpu, utcb->cr0);
+
+ if (pCtx->cr2 != utcb->cr2)
+ CPUMSetGuestCR2(pVCpu, utcb->cr2);
+
+ if (pCtx->cr3 != utcb->cr3)
+ CPUMSetGuestCR3(pVCpu, utcb->cr3);
+
+ if (pCtx->cr4 != utcb->cr4)
+ CPUMSetGuestCR4(pVCpu, utcb->cr4);
+
+ VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_TO_R3);
+
+ /* tell rem compiler that FPU register changed XXX optimizations ? */
+ CPUMSetChangedFlags(pVCpu, CPUM_CHANGED_FPU_REM); /* redundant ? XXX */
+ pVCpu->cpum.s.fUseFlags |= (CPUM_USED_FPU | CPUM_USED_FPU_SINCE_REM); /* redundant ? XXX */
+
+ if (utcb->intr_state != 0)
+ EMSetInhibitInterruptsPC(pVCpu, pCtx->rip);
+ else
+ VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS);
+
+ return true;
+ }
+
+
+ inline void inj_event(Nova::Utcb * utcb, PVMCPU pVCpu)
+ {
+ PCPUMCTX const pCtx = CPUMQueryGuestCtxPtr(pVCpu);
+
+ if (!TRPMHasTrap(pVCpu)) {
+
+ if (VMCPU_FF_TESTANDCLEAR(pVCpu, VMCPU_FF_INTERRUPT_NMI)) {
+ PDBG("%u hoho", __LINE__);
+ while (1) {}
+ }
+
+ if (VMCPU_FF_ISPENDING(pVCpu, (VMCPU_FF_INTERRUPT_APIC|VMCPU_FF_INTERRUPT_PIC))) {
+
+ if (!(utcb->flags & X86_EFL_IF)) {
+
+ unsigned vector = 0;
+ utcb->inj_info = 0x1000 | vector;
+ utcb->mtd |= Nova::Mtd::INJ;
+
+ } else
+ if (!VMCPU_FF_ISSET(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS)) {
+
+ uint8_t irq;
+ int rc = PDMGetInterrupt(pVCpu, &irq);
+ Assert(RT_SUCCESS(rc));
+
+ rc = TRPMAssertTrap(pVCpu, irq, TRPM_HARDWARE_INT);
+ Assert(RT_SUCCESS(rc));
+ } else
+ PWRN("pending interrupt blocked due to INHIBIT flag");
+ }
+ }
+
+ /* can an interrupt be dispatched ? */
+ if (!TRPMHasTrap(pVCpu) || !(utcb->flags & X86_EFL_IF) ||
+ VMCPU_FF_ISSET(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS))
+ return;
+
+ #ifdef VBOX_STRICT
+ if (TRPMHasTrap(pVCpu)) {
+ uint8_t u8Vector;
+ int const rc = TRPMQueryTrapAll(pVCpu, &u8Vector, 0, 0, 0);
+ AssertRC(rc);
+ }
+ #endif
+
+ /* interrupt can be dispatched */
+ uint8_t u8Vector;
+ TRPMEVENT enmType;
+ SVM_EVENT Event;
+ RTGCUINT u32ErrorCode;
+
+ Event.au64[0] = 0;
+
+ /* If a new event is pending, then dispatch it now. */
+ int rc = TRPMQueryTrapAll(pVCpu, &u8Vector, &enmType, &u32ErrorCode, 0);
+ AssertRC(rc);
+ Assert(pCtx->eflags.Bits.u1IF == 1 || enmType == TRPM_TRAP);
+ Assert(enmType != TRPM_SOFTWARE_INT);
+
+ /* Clear the pending trap. */
+ rc = TRPMResetTrap(pVCpu);
+ AssertRC(rc);
+
+ Event.n.u8Vector = u8Vector;
+ Event.n.u1Valid = 1;
+ Event.n.u32ErrorCode = u32ErrorCode;
+
+ Assert(enmType == TRPM_HARDWARE_INT);
+
+ Event.n.u3Type = SVM_EVENT_EXTERNAL_IRQ;
+
+ utcb->inj_info = Event.au64[0];
+ utcb->inj_error = Event.n.u32ErrorCode;
+
+ utcb->mtd |= Nova::Mtd::INJ;
+
+/*
+ PDBG("type:info:vector %x:%x:%x",
+ Event.n.u3Type, utcb->inj_info, u8Vector);
+*/
+ }
+
+
+ inline void irq_win(Nova::Utcb * utcb, PVMCPU pVCpu)
+ {
+ Assert(utcb->flags & X86_EFL_IF);
+
+ Nova::mword_t const mtd = Nova::Mtd::INJ;
+ utcb->mtd = ~mtd;
+ }
+
+ virtual bool hw_load_state(Nova::Utcb *, VM *, PVMCPU) = 0;
+ virtual bool hw_save_state(Nova::Utcb *, VM *, PVMCPU) = 0;
+
+ public:
+
+ enum Exit_condition
+ {
+ SVM_NPT = 0xfc,
+ SVM_INVALID = 0xfd,
+
+ VCPU_STARTUP = 0xfe,
+
+ RECALL = 0xff,
+ EMULATE_INSTR = 0x100
+ };
+
+
+ Vcpu_handler()
+ :
+ Vmm::Vcpu_dispatcher(STACK_SIZE, _cap_connection),
+ _ec_sel(Genode::cap_map()->insert()),
+ _lock_startup(Genode::Lock::LOCKED),
+ _signal_emt(Genode::Lock::LOCKED),
+ _signal_vcpu(Genode::Lock::LOCKED)
+ { }
+
+ void start() {
+ _vcpu.start(_ec_sel);
+
+ /* wait until vCPU thread is up */
+ _lock_startup.lock();
+ }
+
+ void recall()
+ {
+ using namespace Nova;
+
+ if (ec_ctrl(EC_RECALL, _ec_sel) != NOVA_OK) {
+ PERR("recall failed");
+ Genode::Lock lock(Genode::Lock::LOCKED);
+ lock.lock();
+ }
+ }
+
+ inline void dump_register_state(PCPUMCTX pCtx)
+ {
+ PINF("pCtx");
+ PLOG("ip:sp:efl ax:bx:cx:dx:si:di %llx:%llx:%llx"
+ " %llx:%llx:%llx:%llx:%llx:%llx",
+ pCtx->rip, pCtx->rsp, pCtx->rflags.u, pCtx->rax, pCtx->rbx,
+ pCtx->rcx, pCtx->rdx, pCtx->rsi, pCtx->rdi);
+
+ PLOG("cs.attr.n.u4LimitHigh=0x%x", pCtx->cs.Attr.n.u4LimitHigh);
+
+ PLOG("cs base:limit:sel:ar %llx:%x:%x:%x", pCtx->cs.u64Base,
+ pCtx->cs.u32Limit, pCtx->cs.Sel, pCtx->cs.Attr.u);
+ PLOG("ds base:limit:sel:ar %llx:%x:%x:%x", pCtx->ds.u64Base,
+ pCtx->ds.u32Limit, pCtx->ds.Sel, pCtx->ds.Attr.u);
+ PLOG("es base:limit:sel:ar %llx:%x:%x:%x", pCtx->es.u64Base,
+ pCtx->es.u32Limit, pCtx->es.Sel, pCtx->es.Attr.u);
+ PLOG("fs base:limit:sel:ar %llx:%x:%x:%x", pCtx->fs.u64Base,
+ pCtx->fs.u32Limit, pCtx->fs.Sel, pCtx->fs.Attr.u);
+ PLOG("gs base:limit:sel:ar %llx:%x:%x:%x", pCtx->gs.u64Base,
+ pCtx->gs.u32Limit, pCtx->gs.Sel, pCtx->gs.Attr.u);
+ PLOG("ss base:limit:sel:ar %llx:%x:%x:%x", pCtx->ss.u64Base,
+ pCtx->ss.u32Limit, pCtx->ss.Sel, pCtx->ss.Attr.u);
+
+ PLOG("cr0:cr2:cr3:cr4 %llx:%llx:%llx:%llx",
+ pCtx->cr0, pCtx->cr2, pCtx->cr3, pCtx->cr4);
+
+ PLOG("ldtr base:limit:sel:ar %llx:%x:%x:%x", pCtx->ldtr.u64Base,
+ pCtx->ldtr.u32Limit, pCtx->ldtr.Sel, pCtx->ldtr.Attr.u);
+ PLOG("tr base:limit:sel:ar %llx:%x:%x:%x", pCtx->tr.u64Base,
+ pCtx->tr.u32Limit, pCtx->tr.Sel, pCtx->tr.Attr.u);
+
+ PLOG("gdtr base:limit %llx:%x", pCtx->gdtr.pGdt, pCtx->gdtr.cbGdt);
+ PLOG("idtr base:limit %llx:%x", pCtx->idtr.pIdt, pCtx->idtr.cbIdt);
+
+ PLOG("dr 0:1:2:3:4:5:6:7 %llx:%llx:%llx:%llx:%llx:%llx:%llx:%llx",
+ pCtx->dr[0], pCtx->dr[1], pCtx->dr[2], pCtx->dr[3],
+ pCtx->dr[4], pCtx->dr[5], pCtx->dr[6], pCtx->dr[7]);
+
+ PLOG("sysenter cs:eip:esp %llx %llx %llx", pCtx->SysEnter.cs,
+ pCtx->SysEnter.eip, pCtx->SysEnter.esp);
+ }
+
+ inline void dump_register_state(Nova::Utcb * utcb)
+ {
+ PINF("utcb");
+ PLOG("ip:sp:efl ax:bx:cx:dx:si:di %lx:%lx:%lx"
+ " %lx:%lx:%lx:%lx:%lx:%lx",
+ utcb->ip, utcb->sp, utcb->flags, utcb->ax, utcb->bx,
+ utcb->cx, utcb->dx, utcb->si, utcb->di);
+
+ PLOG("cs base:limit:sel:ar %lx:%x:%x:%x", utcb->cs.base,
+ utcb->cs.limit, utcb->cs.sel, utcb->cs.ar);
+ PLOG("ds base:limit:sel:ar %lx:%x:%x:%x", utcb->ds.base,
+ utcb->ds.limit, utcb->ds.sel, utcb->ds.ar);
+ PLOG("es base:limit:sel:ar %lx:%x:%x:%x", utcb->es.base,
+ utcb->es.limit, utcb->es.sel, utcb->es.ar);
+ PLOG("fs base:limit:sel:ar %lx:%x:%x:%x", utcb->fs.base,
+ utcb->fs.limit, utcb->fs.sel, utcb->fs.ar);
+ PLOG("gs base:limit:sel:ar %lx:%x:%x:%x", utcb->gs.base,
+ utcb->gs.limit, utcb->gs.sel, utcb->gs.ar);
+ PLOG("ss base:limit:sel:ar %lx:%x:%x:%x", utcb->ss.base,
+ utcb->ss.limit, utcb->ss.sel, utcb->ss.ar);
+
+ PLOG("cr0:cr2:cr3:cr4 %lx:%lx:%lx:%lx",
+ utcb->cr0, utcb->cr2, utcb->cr3, utcb->cr4);
+
+ PLOG("ldtr base:limit:sel:ar %lx:%x:%x:%x", utcb->ldtr.base,
+ utcb->ldtr.limit, utcb->ldtr.sel, utcb->ldtr.ar);
+ PLOG("tr base:limit:sel:ar %lx:%x:%x:%x", utcb->tr.base,
+ utcb->tr.limit, utcb->tr.sel, utcb->tr.ar);
+
+ PLOG("gdtr base:limit %lx:%x", utcb->gdtr.base, utcb->gdtr.limit);
+ PLOG("idtr base:limit %lx:%x", utcb->idtr.base, utcb->idtr.limit);
+
+ PLOG("dr 7 %lx", utcb->dr7);
+
+ PLOG("sysenter cs:eip:esp %lx %lx %lx", utcb->sysenter_cs,
+ utcb->sysenter_ip, utcb->sysenter_sp);
+
+ PLOG("%x %x %x", utcb->intr_state, utcb->actv_state, utcb->mtd);
+ }
+
+ int run_hw(PVMR0 pVMR0, VMCPUID idCpu)
+ {
+ VM * pVM = reinterpret_cast(pVMR0);
+ PVMCPU pVCpu = &pVM->aCpus[idCpu];
+ PCPUMCTX pCtx = CPUMQueryGuestCtxPtr(pVCpu);
+
+ Nova::Utcb *utcb = reinterpret_cast(Thread_base::utcb());
+
+ using namespace Nova;
+ Genode::Thread_base *myself = Genode::Thread_base::myself();
+
+ /* Transfer vCPU state from vBox to Nova format */
+ if (!vbox_to_utcb(utcb, pVM, pVCpu) ||
+ !hw_load_state(utcb, pVM, pVCpu)) {
+
+ PERR("loading vCPU state failed");
+ /* deadlock here */
+ _signal_emt.lock();
+ }
+
+ /* check whether to inject interrupts */
+ inj_event(utcb, pVCpu);
+
+ ResumeExecution:
+
+ /*
+ * 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);
+
+ this->_current_vm = pVM;
+ this->_current_vcpu = pVCpu;
+
+ /* let vCPU run */
+ _signal_vcpu.unlock();
+
+ /* waiting to be woken up */
+ _signal_emt.lock();
+
+ this->_current_vm = 0;
+ this->_current_vcpu = 0;
+
+// CPUMSetChangedFlags(pVCpu, CPUM_CHANGED_GLOBAL_TLB_FLUSH);
+
+ VMCPU_SET_STATE(pVCpu, VMCPUSTATE_STARTED);
+
+ /* Transfer vCPU state from Nova to vBox format */
+ if (!utcb_to_vbox(utcb, pVM, pVCpu) ||
+ !hw_save_state(utcb, pVM, pVCpu)) {
+ PERR("saving vCPU state failed");
+ /* deadlock here */
+ _signal_emt.lock();
+ }
+
+ /* reset message transfer descriptor for next invocation */
+ utcb->mtd = 0;
+
+ if (utcb->intr_state & 3) {
+/*
+ PDBG("reset intr_state - exit reason %u", _current_exit_cond);
+*/
+ utcb->intr_state &= ~3;
+ utcb->mtd |= Mtd::STA;
+ }
+
+ switch (_current_exit_cond)
+ {
+ case RECALL:
+
+ case VMX_EXIT_EPT_VIOLATION:
+ case VMX_EXIT_PORT_IO:
+ case VMX_EXIT_ERR_INVALID_GUEST_STATE:
+ case VMX_EXIT_HLT:
+
+ case SVM_EXIT_IOIO:
+ case SVM_NPT:
+ case SVM_EXIT_HLT:
+ case SVM_INVALID:
+ case SVM_EXIT_MSR:
+
+ case EMULATE_INSTR:
+ return VINF_EM_RAW_EMULATE_INSTR;
+
+ case SVM_EXIT_VINTR:
+ case VMX_EXIT_IRQ_WINDOW:
+ {
+ if (VMCPU_FF_ISSET(pVCpu, VMCPU_FF_INHIBIT_INTERRUPTS)) {
+ if (pCtx->rip != EMGetInhibitInterruptsPC(pVCpu))
+ PERR("inhibit interrupts %x %x", pCtx->rip, EMGetInhibitInterruptsPC(pVCpu));
+ }
+
+ uint32_t check_vm = VM_FF_HWACCM_TO_R3_MASK | VM_FF_REQUEST
+ | VM_FF_PGM_POOL_FLUSH_PENDING
+ | VM_FF_PDM_DMA;
+ uint32_t check_vcpu = VMCPU_FF_HWACCM_TO_R3_MASK
+ | VMCPU_FF_PGM_SYNC_CR3
+ | VMCPU_FF_PGM_SYNC_CR3_NON_GLOBAL
+ | VMCPU_FF_REQUEST;
+
+ if (VM_FF_ISPENDING(pVM, check_vm)
+ || VMCPU_FF_ISPENDING(pVCpu, check_vcpu))
+ {
+ Assert(VM_FF_ISPENDING(pVM, VM_FF_HWACCM_TO_R3_MASK) ||
+ VMCPU_FF_ISPENDING(pVCpu, VMCPU_FF_HWACCM_TO_R3_MASK));
+
+ if (RT_UNLIKELY(VM_FF_ISPENDING(pVM, VM_FF_PGM_NO_MEMORY)))
+ {
+ PERR(" no memory");
+ while (1) {}
+ }
+
+// PERR(" em raw to r3");
+ return VINF_EM_RAW_TO_R3;
+ }
+
+ if ((utcb->intr_state & 3))
+ PERR("irq window with intr_state %x", utcb->intr_state);
+
+ irq_win(utcb, pVCpu);
+
+ goto ResumeExecution;
+ }
+
+ default:
+
+ PERR("unknown exit cond:ip:qual[0],[1] %lx:%lx:%llx:%llx",
+ _current_exit_cond, utcb->ip, utcb->qual[0], utcb->qual[1]);
+
+ while (1) {}
+ }
+
+ return VERR_INTERNAL_ERROR;
+ }
+};
+
+#endif /* _VCPU_H__ */
diff --git a/ports/src/virtualbox/nova/vcpu_svm.h b/ports/src/virtualbox/nova/vcpu_svm.h
new file mode 100644
index 0000000000..62237a9553
--- /dev/null
+++ b/ports/src/virtualbox/nova/vcpu_svm.h
@@ -0,0 +1,134 @@
+/*
+ * \brief Genode/Nova specific VirtualBox SUPLib supplements
+ * \author Alexander Boettcher
+ * \date 2013-11-18
+ */
+
+/*
+ * Copyright (C) 2013 Genode Labs GmbH
+ *
+ * This file is distributed under the terms of the GNU General Public License
+ * version 2.
+ */
+
+/* Genode's VirtualBox includes */
+#include "vcpu.h"
+#include "svm.h"
+
+class Vcpu_handler_svm : public Vcpu_handler
+{
+ private:
+
+ __attribute__((noreturn)) void _svm_vintr() {
+ _default_handler(SVM_EXIT_VINTR);
+ }
+ __attribute__((noreturn)) void _svm_rdtsc() {
+ _default_handler(SVM_EXIT_RDTSC);
+ }
+
+ __attribute__((noreturn)) void _svm_msr() {
+ _default_handler(SVM_EXIT_MSR);
+ }
+
+ __attribute__((noreturn)) void _svm_recall()
+ {
+ _default_handler(SVM_INVALID);
+ }
+
+ __attribute__((noreturn)) void _svm_halt()
+ {
+ _default_handler(SVM_EXIT_HLT);
+ }
+
+ __attribute__((noreturn)) void _svm_ioio()
+ {
+ using namespace Nova;
+ using namespace Genode;
+
+ Thread_base *myself = Thread_base::myself();
+ Utcb *utcb = reinterpret_cast(myself->utcb());
+
+ if (utcb->qual[0] & 0x4) {
+ unsigned ctrl0 = utcb->ctrl[0];
+
+ PERR("invalid gueststate");
+
+ /* deadlock here */
+ _signal_vcpu.lock();
+
+
+ utcb->ctrl[0] = ctrl0;
+ utcb->ctrl[1] = 0;
+ utcb->mtd = Mtd::CTRL;
+
+ Nova::reply(myself->stack_top());
+ }
+
+ _default_handler(SVM_EXIT_IOIO);
+ }
+
+ template
+ __attribute__((noreturn)) void _svm_npt()
+ {
+ using namespace Nova;
+ using namespace Genode;
+
+ Thread_base *myself = Thread_base::myself();
+ Utcb *utcb = reinterpret_cast(myself->utcb());
+
+ _exc_memory(myself, utcb, utcb->qual[0] & 1,
+ utcb->qual[1] & ~((1UL << 12) - 1));
+ }
+
+ __attribute__((noreturn)) void _svm_startup()
+ {
+ using namespace Nova;
+
+ Genode::Thread_base *myself = Genode::Thread_base::myself();
+ Utcb *utcb = reinterpret_cast(myself->utcb());
+
+ /* we are ready, unlock our creator */
+ _lock_startup.unlock();
+
+ /* wait until EMT thread say so */
+ _signal_vcpu.lock();
+
+ Nova::reply(myself->stack_top());
+ }
+
+ public:
+
+ Vcpu_handler_svm()
+ {
+ using namespace Nova;
+
+ typedef Vcpu_handler_svm This;
+
+ register_handler(vcpu().exc_base(), Mtd(Mtd::ALL | Mtd::FPU));
+ register_handler (vcpu().exc_base(), Mtd(Mtd::ALL | Mtd::FPU));
+ register_handler (vcpu().exc_base(), Mtd(Mtd::ALL | Mtd::FPU));
+ register_handler (vcpu().exc_base(), Mtd(Mtd::ALL | Mtd::FPU));
+ register_handler (vcpu().exc_base(), Mtd(Mtd::ALL | Mtd::FPU));
+ register_handler>(vcpu().exc_base(), Mtd(Mtd::ALL | Mtd::FPU));
+ register_handler(vcpu().exc_base(), Mtd(Mtd::ALL | Mtd::FPU));
+ register_handler(vcpu().exc_base(), Mtd(Mtd::ALL | Mtd::FPU));
+
+ start();
+ }
+
+ bool hw_save_state(Nova::Utcb * utcb, VM * pVM, PVMCPU pVCpu) {
+ return svm_save_state(utcb, pVM, pVCpu);
+ }
+
+ bool hw_load_state(Nova::Utcb * utcb, VM * pVM, PVMCPU pVCpu) {
+ return svm_load_state(utcb, pVM, pVCpu);
+ }
+};
diff --git a/ports/src/virtualbox/nova/vcpu_vmx.h b/ports/src/virtualbox/nova/vcpu_vmx.h
new file mode 100644
index 0000000000..fcb04d27b2
--- /dev/null
+++ b/ports/src/virtualbox/nova/vcpu_vmx.h
@@ -0,0 +1,187 @@
+/*
+ * \brief Genode/Nova specific VirtualBox SUPLib supplements
+ * \author Alexander Boettcher
+ * \author Norman Feske
+ * \author Christian Helmuth
+ */
+
+/*
+ * Copyright (C) 2013-2014 Genode Labs GmbH
+ *
+ * This file is distributed under the terms of the GNU General Public License
+ * version 2.
+ */
+
+/* VirtualBox includes */
+#include
+
+#include "vmm_memory.h"
+
+/* Genode's VirtualBox includes */
+#include "vcpu.h"
+#include "vmx.h"
+
+extern "C" int MMIO2_MAPPED_SYNC(PVM pVM, RTGCPHYS GCPhys, size_t cbWrite);
+
+class Vcpu_handler_vmx : public Vcpu_handler
+{
+ private:
+
+ template
+ __attribute__((noreturn)) void _vmx_ept()
+ {
+ using namespace Nova;
+ using namespace Genode;
+
+ Thread_base *myself = Thread_base::myself();
+ Utcb *utcb = reinterpret_cast(myself->utcb());
+
+ _exc_memory(myself, utcb, utcb->qual[0] & 0x38,
+ utcb->qual[1] & ~((1UL << 12) - 1));
+ }
+
+ __attribute__((noreturn)) void _vmx_startup()
+ {
+ Vmm::printf("%s\n", __func__);
+ using namespace Nova;
+
+ Genode::Thread_base *myself = Genode::Thread_base::myself();
+ Utcb *utcb = reinterpret_cast(myself->utcb());
+
+ /* we are ready, unlock our creator */
+ _lock_startup.unlock();
+
+ /* wait until EMT thread say so */
+ _signal_vcpu.lock();
+
+ /* avoid as many as possible VM exits */
+ utcb->mtd |= Mtd::CTRL;
+ utcb->ctrl[0] = 0;
+ utcb->ctrl[1] = 0;
+
+ Nova::reply(myself->stack_top());
+ }
+
+ __attribute__((noreturn)) void _vmx_recall()
+ {
+ _default_handler(RECALL);
+ }
+
+ __attribute__((noreturn)) void _vmx_pause()
+ {
+ _default_handler(EMULATE_INSTR);
+ }
+
+ __attribute__((noreturn)) void _vmx_triple()
+ {
+ Genode::Thread_base *myself = Genode::Thread_base::myself();
+ using namespace Nova;
+
+ Vmm::printf("triple fault - dead\n");
+
+ _signal_vcpu.lock();
+
+ _default_handler(EMULATE_INSTR);
+ }
+
+ __attribute__((noreturn)) void _vmx_msr_write()
+ {
+ _default_handler(EMULATE_INSTR);
+ }
+
+ __attribute__((noreturn)) void _vmx_msr_read()
+ {
+ _default_handler(EMULATE_INSTR);
+ }
+
+ __attribute__((noreturn)) void _vmx_ioio()
+ {
+ _default_handler(VMX_EXIT_PORT_IO);
+ }
+
+ __attribute__((noreturn)) void _vmx_invalid()
+ {
+ _default_handler(VMX_EXIT_ERR_INVALID_GUEST_STATE);
+ }
+
+ __attribute__((noreturn)) void _vmx_init()
+ {
+ _default_handler(EMULATE_INSTR);
+ }
+
+ __attribute__((noreturn)) void _vmx_irqwin()
+ {
+ _default_handler(VMX_EXIT_IRQ_WINDOW);
+ }
+
+ __attribute__((noreturn)) void _vmx_hlt()
+ {
+ _default_handler(VMX_EXIT_HLT);
+ }
+
+ __attribute__((noreturn)) void _vmx_cpuid()
+ {
+ _default_handler(EMULATE_INSTR);
+ }
+
+ __attribute__((noreturn)) void _vmx_rdtsc()
+ {
+ _default_handler(EMULATE_INSTR);
+ }
+
+ __attribute__((noreturn)) void _vmx_vmcall()
+ {
+ _default_handler(EMULATE_INSTR);
+ }
+
+ public:
+
+ Vcpu_handler_vmx()
+ {
+ using namespace Nova;
+
+ typedef Vcpu_handler_vmx This;
+
+ Genode::addr_t const exc_base = vcpu().exc_base();
+
+ register_handler (exc_base, Mtd::ALL | Mtd::FPU);
+ register_handler (exc_base, Mtd::ALL | Mtd::FPU);
+ register_handler (exc_base, Mtd::ALL | Mtd::FPU);
+ register_handler (exc_base, Mtd::ALL | Mtd::FPU);
+ register_handler (exc_base, Mtd::ALL | Mtd::FPU);
+ register_handler (exc_base, Mtd::ALL | Mtd::FPU);
+ register_handler (exc_base, Mtd::ALL | Mtd::FPU);
+ register_handler (exc_base, Mtd::ALL | Mtd::FPU);
+ register_handler (exc_base, Mtd::ALL | Mtd::FPU);
+ register_handler (exc_base, Mtd::ALL | Mtd::FPU);
+ register_handler (exc_base, Mtd::ALL | Mtd::FPU);
+ register_handler (exc_base, Mtd::ALL | Mtd::FPU);
+ register_handler> (exc_base, Mtd::ALL | Mtd::FPU);
+ register_handler
+ (exc_base, Mtd::ALL | Mtd::FPU);
+ register_handler (exc_base, Mtd::ALL | Mtd::FPU);
+
+ start();
+ }
+
+ bool hw_save_state(Nova::Utcb * utcb, VM * pVM, PVMCPU pVCpu) {
+ return vmx_save_state(utcb, pVM, pVCpu);
+ }
+
+ bool hw_load_state(Nova::Utcb * utcb, VM * pVM, PVMCPU pVCpu) {
+ return vmx_load_state(utcb, pVM, pVCpu);
+ }
+};
diff --git a/ports/src/virtualbox/nova/vmx.h b/ports/src/virtualbox/nova/vmx.h
new file mode 100644
index 0000000000..2976f8fec8
--- /dev/null
+++ b/ports/src/virtualbox/nova/vmx.h
@@ -0,0 +1,172 @@
+/*
+ * \brief Genode/Nova specific VirtualBox SUPLib supplements
+ * \author Norman Feske
+ * \author Alexander Boettcher
+ */
+
+/*
+ * Copyright (C) 2013-2014 Genode Labs GmbH
+ *
+ * This file is distributed under the terms of the GNU General Public License
+ * version 2.
+ */
+
+#ifndef _GENODE_VIRTUALBOX_VMX__H_
+#define _GENODE_VIRTUALBOX_VMX__H_
+
+#define GENODE_READ_SELREG_REQUIRED(REG) \
+ (pCtx->REG.Sel != utcb->REG.sel) || \
+ (pCtx->REG.ValidSel != utcb->REG.sel) || \
+ (pCtx->REG.fFlags != CPUMSELREG_FLAGS_VALID) || \
+ (pCtx->REG.u32Limit != utcb->REG.limit) || \
+ (pCtx->REG.u64Base != utcb->REG.base) || \
+ (pCtx->REG.Attr.u != sel_ar_conv_from_nova(utcb->REG.ar))
+
+#define GENODE_READ_SELREG(REG) \
+ pCtx->REG.Sel = utcb->REG.sel; \
+ pCtx->REG.ValidSel = utcb->REG.sel; \
+ pCtx->REG.fFlags = CPUMSELREG_FLAGS_VALID; \
+ pCtx->REG.u32Limit = utcb->REG.limit; \
+ pCtx->REG.u64Base = utcb->REG.base; \
+ pCtx->REG.Attr.u = sel_ar_conv_from_nova(utcb->REG.ar)
+
+static inline bool vmx_save_state(Nova::Utcb * utcb, 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_REQUIRED(REG) \
+ (utcb->REG.sel != pCtx->REG.Sel) || \
+ (utcb->REG.limit != pCtx->REG.u32Limit) || \
+ (utcb->REG.base != pCtx->REG.u64Base) || \
+ ((( pCtx->REG.Sel \
+ || !CPUMIsGuestInPagedProtectedModeEx(pCtx) \
+ || (!pCtx->cs.Attr.n.u1DefBig && !CPUMIsGuestIn64BitCodeEx(pCtx))) \
+ && pCtx->REG.Attr.n.u1Present == 1) ? \
+ utcb->REG.ar != sel_ar_conv_to_nova(pCtx->REG.Attr.u | X86_SEL_TYPE_ACCESSED) : \
+ utcb->REG.ar != sel_ar_conv_to_nova(VMCS_SEG_UNUSABLE) \
+ )
+
+#define GENODE_WRITE_SELREG(REG) \
+ Assert(pCtx->REG.fFlags & CPUMSELREG_FLAGS_VALID); \
+ Assert(pCtx->REG.ValidSel == pCtx->REG.Sel); \
+ utcb->REG.sel = pCtx->REG.Sel; \
+ utcb->REG.limit = pCtx->REG.u32Limit; \
+ utcb->REG.base = pCtx->REG.u64Base; \
+ \
+ /* attribute fixup according to 'VMX_WRITE_SELREG' in 'HWVMXR0.h' */ \
+ if (( pCtx->REG.Sel \
+ || !CPUMIsGuestInPagedProtectedModeEx(pCtx) \
+ || (!pCtx->cs.Attr.n.u1DefBig && !CPUMIsGuestIn64BitCodeEx(pCtx))) \
+ && pCtx->REG.Attr.n.u1Present == 1) \
+ { \
+ utcb->REG.ar = sel_ar_conv_to_nova(pCtx->REG.Attr.u | X86_SEL_TYPE_ACCESSED); \
+ } else { \
+ utcb->REG.ar = sel_ar_conv_to_nova(VMCS_SEG_UNUSABLE); \
+ }
+
+static inline bool vmx_load_state(Nova::Utcb * utcb, VM * pVM, PVMCPU pVCpu)
+{
+ PCPUMCTX pCtx = CPUMQueryGuestCtxPtr(pVCpu);
+
+ if ((GENODE_WRITE_SELREG_REQUIRED(es)) ||
+ (GENODE_WRITE_SELREG_REQUIRED(ds)))
+ {
+ utcb->mtd |= Nova::Mtd::ESDS;
+ GENODE_WRITE_SELREG(es);
+ GENODE_WRITE_SELREG(ds);
+ }
+
+ if ((GENODE_WRITE_SELREG_REQUIRED(fs)) ||
+ (GENODE_WRITE_SELREG_REQUIRED(gs)))
+ {
+ utcb->mtd |= Nova::Mtd::FSGS;
+ GENODE_WRITE_SELREG(fs);
+ GENODE_WRITE_SELREG(gs);
+ }
+
+ if ((GENODE_WRITE_SELREG_REQUIRED(cs)) ||
+ (GENODE_WRITE_SELREG_REQUIRED(ss)))
+ {
+ utcb->mtd |= Nova::Mtd::CSSS;
+ GENODE_WRITE_SELREG(cs);
+ GENODE_WRITE_SELREG(ss);
+ }
+
+ /* ldtr */
+ if (pCtx->ldtr.Sel == 0) {
+ if (utcb->ldtr.sel != 0 ||
+ utcb->ldtr.limit != 0 ||
+ utcb->ldtr.base != 0 ||
+ utcb->ldtr.ar != sel_ar_conv_to_nova(0x82))
+ {
+ utcb->mtd |= Nova::Mtd::LDTR;
+
+ utcb->ldtr.sel = 0;
+ utcb->ldtr.limit = 0;
+ utcb->ldtr.base = 0;
+ utcb->ldtr.ar = sel_ar_conv_to_nova(0x82);
+ }
+ } else {
+ if (utcb->ldtr.sel != pCtx->ldtr.Sel ||
+ utcb->ldtr.limit != pCtx->ldtr.u32Limit ||
+ utcb->ldtr.base != pCtx->ldtr.u64Base ||
+ utcb->ldtr.ar != sel_ar_conv_to_nova(pCtx->ldtr.Attr.u))
+ {
+ utcb->mtd |= Nova::Mtd::LDTR;
+
+ utcb->ldtr.sel = pCtx->ldtr.Sel;
+ utcb->ldtr.limit = pCtx->ldtr.u32Limit;
+ utcb->ldtr.base = pCtx->ldtr.u64Base;
+ utcb->ldtr.ar = sel_ar_conv_to_nova(pCtx->ldtr.Attr.u);
+ }
+ }
+
+ /* tr */
+ Assert(pCtx->tr.Attr.u & X86_SEL_TYPE_SYS_TSS_BUSY_MASK);
+ Assert(!CPUMIsGuestInRealModeEx(pCtx));
+
+ if (utcb->tr.sel != pCtx->tr.Sel ||
+ utcb->tr.limit != pCtx->tr.u32Limit ||
+ utcb->tr.base != pCtx->tr.u64Base ||
+ utcb->tr.ar != sel_ar_conv_to_nova(pCtx->tr.Attr.u))
+ {
+ utcb->mtd |= Nova::Mtd::TR;
+
+ utcb->tr.sel = pCtx->tr.Sel;
+ utcb->tr.limit = pCtx->tr.u32Limit;
+ utcb->tr.base = pCtx->tr.u64Base;
+ utcb->tr.ar = sel_ar_conv_to_nova(pCtx->tr.Attr.u);
+ }
+
+ return true;
+}
+
+#undef GENODE_WRITE_SELREG
+#undef GENODE_WRITE_SELREG_REQUIRED
+
+#endif /* _GENODE_VIRTUALBOX_VMX__H_ */
diff --git a/ports/src/virtualbox/pdm.cc b/ports/src/virtualbox/pdm.cc
new file mode 100644
index 0000000000..89dba21466
--- /dev/null
+++ b/ports/src/virtualbox/pdm.cc
@@ -0,0 +1,127 @@
+/*
+ * \brief VirtualBox pluggable device manager (PDM)
+ * \author Norman Feske
+ * \date 2013-08-20
+ */
+
+/*
+ * Copyright (C) 2013 Genode Labs GmbH
+ *
+ * This file is distributed under the terms of the GNU General Public License
+ * version 2.
+ */
+
+/* Genode includes */
+#include
+#include
+
+/* VirtualBox includes */
+#include
+#include
+#include
+
+#include "util.h"
+
+
+static void RCSymbolDummy()
+{
+ PDBG("unexpected call of RC symbol");
+ for (;;);
+}
+
+
+int PDMR3LdrGetSymbolRC(PVM pVM, const char *pszModule, const char *pszSymbol,
+ PRTRCPTR pRCPtrValue)
+{
+ *pRCPtrValue = to_rtrcptr(RCSymbolDummy);
+ return VINF_SUCCESS;
+}
+
+
+int PDMR3LdrGetSymbolRCLazy(PVM pVM, const char *pszModule,
+ const char *pszSearchPath, const char *pszSymbol,
+ PRTRCPTR pRCPtrValue)
+{
+ *pRCPtrValue = to_rtrcptr(RCSymbolDummy);
+ return VINF_SUCCESS;
+}
+
+
+static void R0SymbolDummy()
+{
+ PDBG("unexpected call of R0 symbol");
+ for (;;);
+}
+
+
+int PDMR3LdrGetSymbolR0(PVM pVM, const char *pszModule, const char *pszSymbol,
+ PRTR0PTR ppvValue)
+{
+ *ppvValue = (RTR0PTR)R0SymbolDummy;
+ return VINF_SUCCESS;
+}
+
+
+int PDMR3LdrGetSymbolR0Lazy(PVM pVM, const char *pszModule,
+ const char *pszSearchPath, const char *pszSymbol,
+ PRTR0PTR ppvValue)
+{
+ *ppvValue = (RTR0PTR)R0SymbolDummy;
+ return VINF_SUCCESS;
+}
+
+
+extern "C" int VBoxDriversRegister(PCPDMDRVREGCB, uint32_t);
+extern "C" int VBoxDevicesRegister(PPDMDEVREGCB, uint32_t);
+
+
+static int dummy_VBoxDriversRegister(PCPDMDRVREGCB, uint32_t) { return VINF_SUCCESS; }
+static int dummy_VBoxDevicesRegister(PPDMDEVREGCB, uint32_t) { return VINF_SUCCESS; }
+
+
+int PDMR3LdrGetSymbolR3(PVM pVM, const char *pszModule, const char *pszSymbol,
+ void **ppvValue)
+{
+ /*
+ * This function is called at initialization time via
+ * PDMR3Init -> pdmR3DrvInit -> pdmR3DrvLoad -> PDMR3LdrGetSymbolR3
+ *
+ * In this case, it is expected to return the pointer to the symbol
+ * called 'VBoxDriversRegister', which is normally contained in the
+ * dynamically loaded VBoxDD module. However, we link the driver
+ * statically to the binary. So we return the local pointer.
+ */
+ if (Genode::strcmp(pszModule, "VBoxDD") == 0) {
+
+ if (Genode::strcmp(pszSymbol, "VBoxDriversRegister") == 0) {
+ *ppvValue = (void *)VBoxDriversRegister;
+ PDBG("return VBoxDriversRegister pointer");
+ return VINF_SUCCESS;
+ }
+
+ if (Genode::strcmp(pszSymbol, "VBoxDevicesRegister") == 0) {
+ *ppvValue = (void *)VBoxDevicesRegister;
+ PDBG("return VBoxDevicesRegister pointer");
+ return VINF_SUCCESS;
+ }
+ }
+
+ if (Genode::strcmp(pszModule, "VBoxDD2") == 0) {
+
+ if (Genode::strcmp(pszSymbol, "VBoxDriversRegister") == 0) {
+ *ppvValue = (void *)dummy_VBoxDriversRegister;
+ return VINF_SUCCESS;
+ }
+
+ if (Genode::strcmp(pszSymbol, "VBoxDevicesRegister") == 0) {
+ *ppvValue = (void *)dummy_VBoxDevicesRegister;
+ return VINF_SUCCESS;
+ }
+ }
+
+ PDBG("pszModule=%s pszSymbol=%s", pszModule, pszSymbol);
+
+ return VERR_SYMBOL_NOT_FOUND;
+}
+
+
diff --git a/ports/src/virtualbox/pdm_queue_irqs.patch b/ports/src/virtualbox/pdm_queue_irqs.patch
new file mode 100644
index 0000000000..5097f6e2dd
--- /dev/null
+++ b/ports/src/virtualbox/pdm_queue_irqs.patch
@@ -0,0 +1,10 @@
++++ src/VBox/VMM/VMMAll/PDMAllQueue.cpp
+@@ -106,7 +106,7 @@
+ # ifdef VBOX_WITH_REM
+ REMR3NotifyQueuePending(pVM); /** @todo r=bird: we can remove REMR3NotifyQueuePending and let VMR3NotifyFF do the work. */
+ # endif
+- VMR3NotifyGlobalFFU(pVM->pUVM, VMNOTIFYFF_FLAGS_DONE_REM);
++ VMR3NotifyGlobalFFU(pVM->pUVM, VMNOTIFYFF_FLAGS_DONE_REM | VMNOTIFYFF_FLAGS_POKE);
+ #endif
+ }
+ STAM_REL_COUNTER_INC(&pQueue->StatInsert);
diff --git a/ports/src/virtualbox/pgm.cc b/ports/src/virtualbox/pgm.cc
new file mode 100644
index 0000000000..a4be343d9e
--- /dev/null
+++ b/ports/src/virtualbox/pgm.cc
@@ -0,0 +1,583 @@
+/*
+ * \brief VirtualBox page manager (PGM)
+ * \author Norman Feske
+ * \date 2013-08-20
+ */
+
+/*
+ * Copyright (C) 2013 Genode Labs GmbH
+ *
+ * This file is distributed under the terms of the GNU General Public License
+ * version 2.
+ */
+
+/* Genode includes */
+#include
+#include
+
+/* VirtualBox includes */
+#include "PGMInternal.h" /* enable access to pgm.s.* */
+#include
+#include
+#include
+#include
+#include
+
+/* local includes */
+#include "util.h"
+#include "vmm_memory.h"
+#include "guest_memory.h"
+
+using Genode::Ram_session;
+using Genode::Rm_session;
+
+
+Vmm_memory *vmm_memory()
+{
+ static Vmm_memory inst(*Genode::env()->ram_session());
+ return &inst;
+}
+
+
+Guest_memory *guest_memory()
+{
+ static Guest_memory inst;
+ return &inst;
+}
+
+
+int PGMR3PhysRomRegister(PVM pVM, PPDMDEVINS pDevIns, RTGCPHYS GCPhys,
+ RTGCPHYS cb, const void *pvBinary, uint32_t cbBinary,
+ uint32_t fFlags, const char *pszDesc)
+{
+ PLOG("PGMR3PhysRomRegister: GCPhys=0x%lx cb=0x%zx pvBinary=0x%p",
+ (long)GCPhys, (size_t)cb, pvBinary);
+
+ try {
+ guest_memory()->add_rom_mapping(GCPhys, cb, pvBinary, pDevIns);
+ guest_memory()->dump();
+
+ /*
+ * XXX Try to understand the fShadowed condition
+ * (see pgmR3PhysRomRegister)
+ */
+ REMR3NotifyPhysRomRegister(pVM, GCPhys, cb, NULL, false /* fShadowed */);
+
+ } catch (Guest_memory::Region_conflict) {
+ return VERR_PGM_MAPPING_CONFLICT; }
+
+ return VINF_SUCCESS;
+}
+
+
+int PGMPhysWrite(PVM pVM, RTGCPHYS GCPhys, const void *pvBuf, size_t cbWrite)
+{
+ void *pv = guest_memory()->lookup(GCPhys, cbWrite);
+/*
+ PLOG("PGMPhysWrite: GCPhys=0x%lx pvBuf=0x%p cbWrite=0x%zx pv=%p",
+ (long)GCPhys, pvBuf, cbWrite, pv);
+*/
+ if (pv) {
+ memcpy(pv, pvBuf, cbWrite);
+ return VINF_SUCCESS;
+ }
+
+ PFNPGMR3PHYSHANDLER pfnHandlerR3 = 0;
+ void *pvUserR3 = 0;
+
+ pv = vmm_memory()->lookup(GCPhys, cbWrite, &pfnHandlerR3, &pvUserR3);
+
+ if (!pv || !pfnHandlerR3 || !pvUserR3) {
+ PERR("PGMPhysWrite skipped: GCPhys=0x%lx pvBuf=0x%p cbWrite=0x%zx",
+ GCPhys, pvBuf, cbWrite);
+ return VERR_GENERAL_FAILURE;
+ }
+
+ int rc = pfnHandlerR3(pVM, GCPhys, 0, 0, cbWrite, PGMACCESSTYPE_WRITE,
+ pvUserR3);
+
+ if (rc == VINF_PGM_HANDLER_DO_DEFAULT) {
+ memcpy(pv, pvBuf, cbWrite);
+ return VINF_SUCCESS;
+ }
+
+ PERR("unexpected %s return code %d", __FUNCTION__, rc);
+ return VERR_GENERAL_FAILURE;
+}
+
+
+int PGMR3PhysWriteExternal(PVM pVM, RTGCPHYS GCPhys, const void *pvBuf,
+ size_t cbWrite, const char *pszWho)
+{
+// PDBG("GCPhys=0x%llx pvBuf=0x%p cbWrite=0x%zx - '%s'",
+// GCPhys, pvBuf, cbWrite, pszWho);
+
+ return PGMPhysWrite(pVM, GCPhys, pvBuf, cbWrite);
+}
+
+
+int PGMPhysRead(PVM pVM, RTGCPHYS GCPhys, void *pvBuf, size_t cbRead)
+{
+ void *pv = guest_memory()->lookup(GCPhys, cbRead);
+
+// PLOG("PGMPhysRead: GCPhys=0x%x pvBuf=0x%p cbRead=0x%zx pv=%p",
+// GCPhys, pvBuf, cbRead, pv);
+
+ if (pv) {
+ memcpy(pvBuf, pv, cbRead);
+ return VINF_SUCCESS;
+ }
+
+ PFNPGMR3PHYSHANDLER pfnHandlerR3 = 0;
+ void *pvUserR3 = 0;
+
+ pv = vmm_memory()->lookup(GCPhys, cbRead, &pfnHandlerR3, &pvUserR3);
+ if (!pv || !pfnHandlerR3 || !pvUserR3) {
+ PERR("PGMPhysRead skipped: GCPhys=0x%lx pvBuf=0x%p cbRead=0x%zx",
+ GCPhys, pvBuf, cbRead);
+ return VERR_GENERAL_FAILURE;
+ }
+
+ memcpy(pvBuf, pv, cbRead);
+ return VINF_SUCCESS;
+}
+
+
+int PGMR3PhysReadExternal(PVM pVM, RTGCPHYS GCPhys, void *pvBuf, size_t cbRead)
+{
+ void *pv = guest_memory()->lookup(GCPhys, cbRead);
+
+// PLOG("PGMPhysReadExternal: GCPhys=0x%x pvBuf=0x%p cbRead=0x%zx pv=%p",
+// GCPhys, pvBuf, cbRead, pv);
+
+ return PGMPhysRead(pVM, GCPhys, pvBuf, cbRead);
+}
+
+
+int PGMR3PhysMMIO2Register(PVM pVM, PPDMDEVINS pDevIns, uint32_t iRegion,
+ RTGCPHYS cb, uint32_t fFlags, void **ppv, const char
+ *pszDesc)
+{
+ *ppv = vmm_memory()->alloc((size_t)cb, pDevIns, iRegion);
+
+ PLOG("PGMR3PhysMMIO2Register: pszDesc=%s iRegion=%u cb=0x%zx -> 0x%p",
+ pszDesc, iRegion, (size_t)cb, *ppv);
+
+ return VINF_SUCCESS;
+}
+
+
+int PGMR3PhysMMIO2Map(PVM pVM, PPDMDEVINS pDevIns, uint32_t iRegion,
+ RTGCPHYS GCPhys)
+{
+ size_t cb = vmm_memory()->map_to_vm(pDevIns, iRegion, GCPhys);
+ if (cb == 0) {
+ PERR("PGMR3PhysMMIO2Map: lookup for pDevIns=%p iRegion=%u failed\n",
+ pDevIns, iRegion);
+ for (;;);
+ }
+
+ PLOG("PGMR3PhysMMIO2Map: pDevIns=%p iRegion=%u cb=0x%zx GCPhys=0x%lx\n",
+ pDevIns, iRegion, cb, (long)GCPhys);
+
+ REMR3NotifyPhysRamRegister(pVM, GCPhys, cb, REM_NOTIFY_PHYS_RAM_FLAGS_MMIO2);
+
+ return VINF_SUCCESS;
+}
+
+
+int PGMR3PhysMMIO2Unmap(PVM pVM, PPDMDEVINS pDevIns, uint32_t iRegion,
+ RTGCPHYS GCPhys)
+{
+ PDBG("called %x %x", GCPhys, iRegion);
+
+ vmm_memory()->map_to_vm(pDevIns, iRegion, 0);
+
+ return VINF_SUCCESS;
+}
+
+
+bool PGMR3PhysMMIO2IsBase(PVM pVM, PPDMDEVINS pDevIns, RTGCPHYS GCPhys)
+{
+ bool res = vmm_memory()->lookup(GCPhys, 1);
+ PDBG("called %x %u", GCPhys, res);
+ return res;
+}
+
+
+int PGMR3HandlerPhysicalRegister(PVM pVM, PGMPHYSHANDLERTYPE enmType,
+ RTGCPHYS GCPhys, RTGCPHYS GCPhysLast,
+ PFNPGMR3PHYSHANDLER pfnHandlerR3,
+ void *pvUserR3, const char *pszModR0,
+ const char *pszHandlerR0, RTR0PTR pvUserR0,
+ const char *pszModRC,
+ const char *pszHandlerRC,
+ RTRCPTR pvUserRC, const char *pszDesc)
+{
+ PLOG("PGMR3HandlerPhysicalRegister: pszDesc=%s %u GCPhys=0x%lx GCPhysLast=0x%lx r3=0x%p\n",
+ pszDesc, enmType, (long)GCPhys, (long)GCPhysLast, (void *)pfnHandlerR3);
+
+ REMR3NotifyHandlerPhysicalRegister(pVM, enmType, GCPhys, GCPhysLast - GCPhys + 1, !!pfnHandlerR3);
+
+ vmm_memory()->add_handler(GCPhys, GCPhysLast - GCPhys + 1, pfnHandlerR3,
+ pvUserR3);
+
+ return VINF_SUCCESS;
+}
+
+
+int PGMHandlerPhysicalDeregister(PVM pVM, RTGCPHYS GCPhys)
+{
+ PDBG("called %x", GCPhys);
+/*
+ for(;;);
+ pgmHandlerPhysicalResetRamFlags(pVM, pCur);
+ REMR3NotifyHandlerPhysicalDeregister(pVM, pCur->enmType, GCPhysStart, GCPhysLast - GCPhysStart + 1, !!pCur->pfnHandlerR3, fRestoreAsRAM);
+*/
+ vmm_memory()->add_handler(GCPhys, GCPhys + 1, 0, 0);
+ return VINF_SUCCESS;
+ return VERR_PGM_HANDLER_NOT_FOUND;
+}
+
+
+int PGMR3PhysRegisterRam(PVM pVM, RTGCPHYS GCPhys, RTGCPHYS cb,
+ const char *pszDesc)
+{
+ PLOG("PGMR3PhysRegisterRam: GCPhys=0x%lx, cb=0x%zx, pszDesc=%s",
+ (long)GCPhys, (size_t)cb, pszDesc);
+
+ try {
+
+ /*
+ * XXX Is this function the right place for the allocation?
+ * The lack of allocation-related VERR_PGM_ error codes suggests
+ * so.
+ */
+ void *pv = vmm_memory()->alloc_ram((size_t)cb);
+
+ guest_memory()->add_ram_mapping(GCPhys, cb, pv);
+
+ guest_memory()->dump();
+
+ REMR3NotifyPhysRamRegister(pVM, GCPhys, cb, REM_NOTIFY_PHYS_RAM_FLAGS_RAM);
+ }
+ catch (Guest_memory::Region_conflict) {
+ return VERR_PGM_MAPPING_CONFLICT; }
+ catch (Ram_session::Alloc_failed) {
+ return VERR_PGM_MAPPING_CONFLICT; /* XXX use a better error code? */ }
+ catch (Rm_session::Attach_failed) {
+ return VERR_PGM_MAPPING_CONFLICT; /* XXX use a better error code? */ }
+
+ return VINF_SUCCESS;
+}
+
+
+int PGMMapSetPage(PVM pVM, RTGCPTR GCPtr, uint64_t cb, uint64_t fFlags)
+{
+ PLOG("PGMMapSetPage: GCPtr=0x%lx cb=0x%lx, flags=0x%lx",
+ (long)GCPtr, (long)cb, (long)fFlags);
+
+ return VINF_SUCCESS;
+}
+
+
+RTHCPHYS PGMGetHyperCR3(PVMCPU pVCpu)
+{
+// PDBG("%s %lx", __func__, CPUMGetHyperCR3(pVCpu));
+ return 1;
+}
+
+
+int PGMR3Init(PVM pVM)
+{
+ /*
+ * Satisfy assertion in VMMR3Init. Normally called via:
+ *
+ * PGMR3Init -> pgmR3InitPaging -> pgmR3ModeDataInit -> InitData -> MapCR3
+ */
+ for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++) {
+ PVMCPU pVCpu = &pVM->aCpus[idCpu];
+ CPUMSetHyperCR3(pVCpu, PGMGetHyperCR3(pVCpu));
+
+ pVCpu->pgm.s.fA20Enabled = true;
+ pVCpu->pgm.s.GCPhysA20Mask = ~((RTGCPHYS)!pVCpu->pgm.s.fA20Enabled << 20);
+ }
+
+ return VINF_SUCCESS;
+}
+
+
+int PGMR3PhysTlbGCPhys2Ptr(PVM pVM, RTGCPHYS GCPhys, bool fWritable, void **ppv)
+{
+ void *pv = guest_memory()->lookup(GCPhys, 1);
+
+ if (!pv) {
+ PERR("PGMR3PhysTlbGCPhys2Ptr: lookup for GCPhys=0x%lx failed", (long)GCPhys);
+ guest_memory()->dump();
+ return VERR_PGM_PHYS_TLB_UNASSIGNED;
+ }
+
+ *ppv = pv;
+
+// PLOG("PGMR3PhysTlbGCPhys2Ptr: GCPhys=0x%lx -> pv=%p", (long)GCPhys, pv);
+
+ return VINF_SUCCESS;
+}
+
+
+void PGMR3PhysSetA20(PVMCPU pVCpu, bool fEnable)
+{
+ if (!pVCpu->pgm.s.fA20Enabled != fEnable) {
+ pVCpu->pgm.s.fA20Enabled = fEnable;
+ REMR3A20Set(pVCpu->pVMR3, pVCpu, fEnable);
+ }
+
+ return;
+}
+
+
+bool PGMPhysIsA20Enabled(PVMCPU pVCpu)
+{
+ return pVCpu->pgm.s.fA20Enabled;
+}
+
+
+void PGMR3PhysWriteU8(PVM pVM, RTGCPHYS GCPhys, uint8_t value)
+{
+ void *pv = guest_memory()->lookup(GCPhys, sizeof(value));
+
+ if (!pv) {
+ PDBG("invalid write attempt");
+ return;
+ }
+
+ *reinterpret_cast(pv) = value;
+}
+
+
+void PGMR3PhysWriteU16(PVM pVM, RTGCPHYS GCPhys, uint16_t value)
+{
+ void *pv = guest_memory()->lookup(GCPhys, sizeof(value));
+
+ if (!pv) {
+ PDBG("invalid write attempt");
+ return;
+ }
+
+ *reinterpret_cast(pv) = value;
+}
+
+
+void PGMR3PhysWriteU32(PVM pVM, RTGCPHYS GCPhys, uint32_t value)
+{
+ void *pv = guest_memory()->lookup(GCPhys, sizeof(value));
+
+ if (!pv) {
+ PDBG("invalid write attempt");
+ return;
+ }
+
+ *reinterpret_cast(pv) = value;
+}
+
+
+uint32_t PGMR3PhysReadU32(PVM pVM, RTGCPHYS GCPhys)
+{
+ void *pv = guest_memory()->lookup(GCPhys, 4);
+
+ if (!pv) {
+ PDBG("invalid read attempt");
+ return 0;
+ }
+
+ return *reinterpret_cast(pv);
+}
+
+
+
+int PGMPhysGCPtr2CCPtrReadOnly(PVMCPU pVCpu, RTGCPTR GCPtr, void const **ppv,
+ PPGMPAGEMAPLOCK pLock)
+{
+ PDBG("not implemented");
+ while (1) {}
+ return VINF_SUCCESS;
+}
+
+
+int PGMR3ChangeMode(PVM pVM, PVMCPU pVCpu, PGMMODE enmGuestMode) {
+
+// Assert(pVCpu->pgm.s.enmShadowMode == PGMMODE_EPT);
+
+// PDBG("not implemented %x %x", pVCpu->pgm.s.enmShadowMode, PGMMODE_EPT);
+
+ pVCpu->pgm.s.enmGuestMode = enmGuestMode;
+
+ HWACCMR3PagingModeChanged(pVM, pVCpu, pVCpu->pgm.s.enmShadowMode, pVCpu->pgm.s.enmGuestMode);
+
+ return VINF_SUCCESS;
+}
+
+int PGMChangeMode(PVMCPU pVCpu, uint64_t cr0, uint64_t cr4, uint64_t efer)
+{
+ PGMMODE enmGuestMode;
+
+ VMCPU_ASSERT_EMT(pVCpu);
+
+ /*
+ * Calc the new guest mode.
+ */
+ if (!(cr0 & X86_CR0_PE))
+ enmGuestMode = PGMMODE_REAL;
+ else if (!(cr0 & X86_CR0_PG))
+ enmGuestMode = PGMMODE_PROTECTED;
+ else if (!(cr4 & X86_CR4_PAE))
+ {
+ bool const fPse = !!(cr4 & X86_CR4_PSE);
+ if (pVCpu->pgm.s.fGst32BitPageSizeExtension != fPse)
+ Log(("PGMChangeMode: CR4.PSE %d -> %d\n", pVCpu->pgm.s.fGst32BitPageSizeExtension, fPse));
+ pVCpu->pgm.s.fGst32BitPageSizeExtension = fPse;
+ enmGuestMode = PGMMODE_32_BIT;
+ }
+ else if (!(efer & MSR_K6_EFER_LME))
+ {
+ if (!(efer & MSR_K6_EFER_NXE))
+ enmGuestMode = PGMMODE_PAE;
+ else
+ enmGuestMode = PGMMODE_PAE_NX;
+ }
+ else
+ {
+ if (!(efer & MSR_K6_EFER_NXE))
+ enmGuestMode = PGMMODE_AMD64;
+ else
+ enmGuestMode = PGMMODE_AMD64_NX;
+ }
+
+ /*
+ * Did it change?
+ */
+ if (pVCpu->pgm.s.enmGuestMode == enmGuestMode)
+ return VINF_SUCCESS;
+
+ /* Flush the TLB */
+// PGM_INVL_VCPU_TLBS(pVCpu);
+ VMCPU_FF_SET(pVCpu, VMCPU_FF_TLB_FLUSH);
+
+// PDBG("not implemented %x %x before", enmGuestMode, pVCpu->pgm.s.enmGuestMode);
+ int rc = PGMR3ChangeMode(pVCpu->CTX_SUFF(pVM), pVCpu, enmGuestMode);
+// PDBG("not implemented %x %x out %p", enmGuestMode, pVCpu->pgm.s.enmGuestMode, __builtin_return_address(0));
+// return VINF_PGM_CHANGE_MODE;
+ return rc;
+}
+
+
+/*
+ * Copied from src/VBox/VMM/VMMAll/PGMAll.cpp
+ */
+
+PGMMODE PGMGetGuestMode(PVMCPU pVCpu) { return pVCpu->pgm.s.enmGuestMode; }
+
+VMMDECL(const char *) PGMGetModeName(PGMMODE enmMode)
+{
+ switch (enmMode)
+ {
+ case PGMMODE_REAL: return "Real";
+ case PGMMODE_PROTECTED: return "Protected";
+ case PGMMODE_32_BIT: return "32-bit";
+ case PGMMODE_PAE: return "PAE";
+ case PGMMODE_PAE_NX: return "PAE+NX";
+ case PGMMODE_AMD64: return "AMD64";
+ case PGMMODE_AMD64_NX: return "AMD64+NX";
+ case PGMMODE_NESTED: return "Nested";
+ case PGMMODE_EPT: return "EPT";
+ default: return "unknown mode value";
+ }
+}
+
+
+int PGMPhysGCPhys2CCPtrReadOnly(PVM pVM, RTGCPHYS GCPhys, void const **ppv, PPGMPAGEMAPLOCK pLock)
+{
+ void *pv = guest_memory()->lookup(GCPhys, 0x1000);
+
+ if (!pv) {
+ PDBG("unknown address pv=%p ppv=%p GCPhys=%llx", pv, ppv, GCPhys);
+
+ guest_memory()->dump();
+
+ return VERR_PGM_INVALID_GC_PHYSICAL_ADDRESS;
+ }
+
+ *ppv = pv;
+
+ PVMCPU pVCpu = VMMGetCpu(pVM);
+
+ return VINF_SUCCESS;
+}
+
+
+int PGMHandlerPhysicalReset(PVM, RTGCPHYS GCPhys)
+{
+ if (!vmm_memory()->unmap_from_vm(GCPhys))
+ PWRN("%s: unbacked region - GCPhys %lx", __func__, GCPhys);
+
+ return VINF_SUCCESS;
+}
+
+
+extern "C" int MMIO2_MAPPED_SYNC(PVM pVM, RTGCPHYS GCPhys, size_t cbWrite)
+{
+ PFNPGMR3PHYSHANDLER pfnHandlerR3 = 0;
+ void *pvUserR3 = 0;
+
+ void * pv = vmm_memory()->lookup(GCPhys, cbWrite, &pfnHandlerR3, &pvUserR3);
+
+ if (!pv || !pfnHandlerR3 || !pvUserR3) {
+ PERR("%s: GCPhys=0x%lx cbWrite=0x%zx", __func__,
+ GCPhys, cbWrite);
+ return VERR_GENERAL_FAILURE;
+ }
+
+ int rc = pfnHandlerR3(pVM, GCPhys, 0, 0, cbWrite, PGMACCESSTYPE_WRITE,
+ pvUserR3);
+
+ if (rc == VINF_PGM_HANDLER_DO_DEFAULT) {
+// PERR("%s: ok %p %lx+%zx", __func__, pfnHandlerR3, GCPhys, cbWrite);
+ return VINF_SUCCESS;
+ }
+
+ PERR("unexpected %s return code %d", __FUNCTION__, rc);
+ return VERR_GENERAL_FAILURE;
+}
+
+
+void PGMR3Reset(PVM pVM)
+{
+ VM_ASSERT_EMT(pVM);
+
+ for (VMCPUID i = 0; i < pVM->cCpus; i++)
+ {
+ int rc = PGMR3ChangeMode(pVM, &pVM->aCpus[i], PGMMODE_REAL);
+ AssertRC(rc);
+ }
+
+ for (VMCPUID i = 0; i < pVM->cCpus; i++)
+ {
+ PVMCPU pVCpu = &pVM->aCpus[i];
+
+ VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_PGM_SYNC_CR3);
+ VMCPU_FF_CLEAR(pVCpu, VMCPU_FF_PGM_SYNC_CR3_NON_GLOBAL);
+
+ if (!pVCpu->pgm.s.fA20Enabled)
+ {
+ pVCpu->pgm.s.fA20Enabled = true;
+ pVCpu->pgm.s.GCPhysA20Mask = ~((RTGCPHYS)!pVCpu->pgm.s.fA20Enabled << 20);
+#ifdef PGM_WITH_A20
+ pVCpu->pgm.s.fSyncFlags |= PGM_SYNC_UPDATE_PAGE_BIT_VIRTUAL;
+ VMCPU_FF_SET(pVCpu, VMCPU_FF_PGM_SYNC_CR3);
+ HWACCMFlushTLB(pVCpu);
+#endif
+ }
+ }
+
+ PERR("clearing ram and rom areas missing !!!!!!!");
+}
diff --git a/ports/src/virtualbox/rt.cc b/ports/src/virtualbox/rt.cc
new file mode 100644
index 0000000000..f038e2113c
--- /dev/null
+++ b/ports/src/virtualbox/rt.cc
@@ -0,0 +1,107 @@
+/*
+ * \brief VirtualBox runtime (RT)
+ * \author Norman Feske
+ * \date 2013-08-20
+ */
+
+/*
+ * Copyright (C) 2013 Genode Labs GmbH
+ *
+ * This file is distributed under the terms of the GNU General Public License
+ * version 2.
+ */
+
+/* Genode includes */
+#include
+#include
+
+/* VirtualBox includes */
+#include
+#include
+#include
+#include
+#include
+#include
+
+
+/*
+ * Called by the recompiler to allocate executable RAM
+ */
+
+void *RTMemExecAllocTag(size_t cb, const char *pszTag) RT_NO_THROW
+{
+ PDBG("size=0x%zx, tag=%s", cb, pszTag);
+
+ /*
+ * XXX error handling is missing
+ */
+
+ using namespace Genode;
+ Ram_dataspace_capability ds = env()->ram_session()->alloc(cb);
+
+ size_t const whole_size = 0;
+ Genode::off_t const offset = 0;
+ bool const executable = true;
+ bool const any_addr = false;
+
+ void *local_addr =
+ env()->rm_session()->attach(ds, whole_size, offset,
+ any_addr, (void *)0, executable);
+
+ return local_addr;
+}
+
+
+void *RTMemPageAllocZTag(size_t cb, const char *pszTag) RT_NO_THROW
+{
+ /*
+ * The RAM dataspace freshly allocated by 'RTMemExecAllocTag' is zeroed
+ * already.
+ */
+ return RTMemExecAllocTag(cb, pszTag);
+}
+
+
+
+void *RTMemPageAllocTag(size_t cb, const char *pszTag) RT_NO_THROW
+{
+ return RTMemPageAllocZTag(cb, pszTag);
+}
+
+
+#include
+
+uint32_t RTBldCfgVersionMajor(void) { return VBOX_VERSION_MAJOR; }
+uint32_t RTBldCfgVersionMinor(void) { return VBOX_VERSION_MINOR; }
+uint32_t RTBldCfgVersionBuild(void) { return VBOX_VERSION_BUILD; }
+uint32_t RTBldCfgRevision(void) { return ~0; }
+
+
+/*
+ * Copied from 'Runtime/r3/posix/timelocal-posix.cpp'
+ */
+
+static int64_t rtTimeLocalUTCOffset(PCRTTIMESPEC pTime, bool fCurrentTime)
+{
+ PDBG("rtTimeLocalUTCOffset called - not implemented");
+ return 0;
+}
+
+
+RTDECL(PRTTIME) RTTimeLocalExplode(PRTTIME pTime, PCRTTIMESPEC pTimeSpec)
+{
+ RTTIMESPEC LocalTime = *pTimeSpec;
+ RTTimeSpecAddNano(&LocalTime, rtTimeLocalUTCOffset(&LocalTime, true /* current time, skip fallback */));
+ pTime = RTTimeExplode(pTime, &LocalTime);
+ if (pTime)
+ pTime->fFlags = (pTime->fFlags & ~RTTIME_FLAGS_TYPE_MASK) | RTTIME_FLAGS_TYPE_LOCAL;
+ return pTime;
+}
+
+
+extern "C" RTDECL(int) RTPathAbs(const char *pszPath, char *pszAbsPath, size_t cchAbsPath)
+{
+ Genode::strncpy(pszAbsPath, pszPath, cchAbsPath);
+ return 0;
+}
+
diff --git a/ports/src/virtualbox/serial.patch b/ports/src/virtualbox/serial.patch
new file mode 100644
index 0000000000..597fb0dad0
--- /dev/null
+++ b/ports/src/virtualbox/serial.patch
@@ -0,0 +1,13 @@
++++ src/VBox/Frontends/VBoxBFE/VBoxBFE.cpp
+@@ -1481,6 +1489,11 @@
+ rc = CFGMR3InsertInteger(pCfg, "IRQ", 4); UPDATE_RC();
+ rc = CFGMR3InsertInteger(pCfg, "IOBase", 0x3f8); UPDATE_RC();
+
++/* rc = CFGMR3InsertNode(pInst, "LUN#0", &pLunL0); UPDATE_RC();
++ rc = CFGMR3InsertString(pLunL0, "Driver", "Host Serial"); UPDATE_RC();
++ rc = CFGMR3InsertNode(pLunL0, "Config", &pLunL1); UPDATE_RC();
++ rc = CFGMR3InsertString(pLunL1, "DevicePath", "/dev/terminal"); UPDATE_RC();
++*/
+ rc = CFGMR3InsertNode(pDev, "1", &pInst); UPDATE_RC();
+ rc = CFGMR3InsertNode(pInst, "Config", &pCfg); UPDATE_RC();
+ rc = CFGMR3InsertInteger(pCfg, "IRQ", 3); UPDATE_RC();
diff --git a/ports/src/virtualbox/sup.cc b/ports/src/virtualbox/sup.cc
new file mode 100644
index 0000000000..7cbbbf66db
--- /dev/null
+++ b/ports/src/virtualbox/sup.cc
@@ -0,0 +1,210 @@
+/*
+ * \brief VirtualBox SUPLib supplements
+ * \author Norman Feske
+ * \date 2013-08-20
+ */
+
+/*
+ * Copyright (C) 2013 Genode Labs GmbH
+ *
+ * This file is distributed under the terms of the GNU General Public License
+ * version 2.
+ */
+
+/* Genode includes */
+#include
+#include
+
+/* Genode/Virtualbox includes */
+#include "sup.h"
+
+/* VirtualBox includes */
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+using Genode::Semaphore;
+
+#define B(x) "\033[00;44m" x "\033[0m"
+
+
+struct Attached_gip : Genode::Attached_ram_dataspace
+{
+ Attached_gip()
+ : Attached_ram_dataspace(Genode::env()->ram_session(), PAGE_SIZE)
+ { }
+};
+
+
+enum {
+ UPDATE_HZ = 250, /* Hz */
+ UPDATE_MS = 1000 / UPDATE_HZ,
+ UPDATE_NS = UPDATE_MS * 1000 * 1000,
+};
+
+
+PSUPGLOBALINFOPAGE g_pSUPGlobalInfoPage;
+
+
+static void _update_tick(PRTTIMER pTimer, void *pvUser, uint64_t iTick)
+{
+ /**
+ * We're using rdtsc here since timer_session->elapsed_ms produces
+ * instable results when the timer service is using the Genode PIC
+ * driver as done for base-nova currently.
+ */
+ static unsigned long long tsc_last = 0;
+
+ unsigned now_low, now_high;
+ asm volatile("rdtsc" : "=a"(now_low), "=d"(now_high) : : "memory");
+
+ unsigned long long tsc_current = now_high;
+ tsc_current <<= 32;
+ tsc_current |= now_low;
+
+ unsigned long long elapsed_tsc = tsc_current - tsc_last;
+ unsigned long elapsed_ms = elapsed_tsc * 1000 / genode_cpu_hz();
+ unsigned long long elapsed_nanots = 1000ULL * 1000 * elapsed_ms;
+
+ tsc_last = tsc_current;
+
+
+
+ SUPGIPCPU *cpu = &g_pSUPGlobalInfoPage->aCPUs[0];
+
+ cpu->u32TransactionId++;
+
+ cpu->u64NanoTS += elapsed_nanots;
+ cpu->u64TSC += elapsed_tsc;
+
+ cpu->u32TransactionId++;
+
+
+
+ asm volatile ("":::"memory");
+}
+
+
+int SUPR3Init(PSUPDRVSESSION *ppSession)
+{
+ static bool initialized(false);
+
+ if (initialized) return VINF_SUCCESS;
+
+ static Attached_gip gip;
+
+ g_pSUPGlobalInfoPage = gip.local_addr();
+
+ /* checked by TMR3Init */
+ g_pSUPGlobalInfoPage->u32Version = SUPGLOBALINFOPAGE_VERSION;
+ g_pSUPGlobalInfoPage->u32Magic = SUPGLOBALINFOPAGE_MAGIC;
+ g_pSUPGlobalInfoPage->u32Mode = SUPGIPMODE_SYNC_TSC;
+ g_pSUPGlobalInfoPage->cCpus = 1;
+ g_pSUPGlobalInfoPage->cPages = 1;
+ g_pSUPGlobalInfoPage->u32UpdateHz = UPDATE_HZ;
+ g_pSUPGlobalInfoPage->u32UpdateIntervalNS = UPDATE_NS;
+// g_pSUPGlobalInfoPage->u64NanoTSLastUpdateHz =
+// g_pSUPGlobalInfoPage->OnlineCpuSet =
+// g_pSUPGlobalInfoPage->PresentCpuSet =
+// g_pSUPGlobalInfoPage->PossibleCpuSet =
+ g_pSUPGlobalInfoPage->cOnlineCpus = 0;
+ g_pSUPGlobalInfoPage->cPresentCpus = 0;
+ g_pSUPGlobalInfoPage->cPossibleCpus = 0;
+ g_pSUPGlobalInfoPage->idCpuMax = 0;
+
+ SUPGIPCPU *cpu = &g_pSUPGlobalInfoPage->aCPUs[0];
+
+ cpu->u32TransactionId = 0;
+ cpu->u32UpdateIntervalTSC = genode_cpu_hz() / UPDATE_HZ;
+ cpu->u64NanoTS = 0ULL;
+ cpu->u64TSC = 0ULL;
+ cpu->u64CpuHz = genode_cpu_hz();
+ cpu->cErrors = 0;
+ cpu->iTSCHistoryHead = 0;
+// cpu->au32TSCHistory[8] =
+ cpu->u32PrevUpdateIntervalNS = UPDATE_NS;
+ cpu->enmState = SUPGIPCPUSTATE_ONLINE;
+ cpu->idCpu = 0;
+ cpu->iCpuSet = 0;
+ cpu->idApic = 0;
+
+ PRTTIMER pTimer;
+
+ RTTimerCreate(&pTimer, UPDATE_MS, _update_tick, 0);
+ RTTimerStart(pTimer, 0);
+
+ initialized = true;
+
+ return VINF_SUCCESS;
+}
+
+
+int SUPR3GipGetPhys(PRTHCPHYS pHCPhys)
+{
+ /*
+ * Return VMM-local address as physical address. This address is
+ * then fed to MMR3HyperMapHCPhys. (TMR3Init)
+ */
+ *pHCPhys = (RTHCPHYS)g_pSUPGlobalInfoPage;
+
+ return VINF_SUCCESS;
+}
+
+
+int SUPSemEventCreate(PSUPDRVSESSION pSession, PSUPSEMEVENT phEvent)
+{
+ *phEvent = (SUPSEMEVENT)new Genode::Semaphore();
+ return VINF_SUCCESS;
+}
+
+
+int SUPSemEventClose(PSUPDRVSESSION pSession, SUPSEMEVENT hEvent)
+{
+ if (hEvent)
+ delete reinterpret_cast(hEvent);
+ return VINF_SUCCESS;
+}
+
+
+int SUPSemEventSignal(PSUPDRVSESSION pSession, SUPSEMEVENT hEvent)
+{
+ if (hEvent)
+ reinterpret_cast(hEvent)->up();
+ else
+ PERR("%s called %lx", __FUNCTION__, hEvent);
+
+ return VINF_SUCCESS;
+}
+
+
+int SUPSemEventWaitNoResume(PSUPDRVSESSION pSession, SUPSEMEVENT hEvent,
+ uint32_t cMillies)
+{
+ if (hEvent && cMillies == RT_INDEFINITE_WAIT)
+ reinterpret_cast(hEvent)->down();
+ else {
+ PERR("%s called %lx millis=%u - not implemented", __FUNCTION__, hEvent, cMillies);
+ reinterpret_cast(hEvent)->down();
+ }
+
+ return VINF_SUCCESS;
+}
+
+
+int SUPR3CallVMMR0(PVMR0 pVMR0, VMCPUID idCpu, unsigned uOperation,
+ void *pvArg)
+{
+ PDBG("SUPR3CallVMMR0 called uOperation=%d", uOperation);
+
+ if (uOperation == VMMR0_DO_CALL_HYPERVISOR) {
+ PDBG("VMMR0_DO_CALL_HYPERVISOR - doing nothing");
+ return VINF_SUCCESS;
+ }
+
+ PDBG("SUPR3CallVMMR0Ex: unhandled uOperation %d", uOperation);
+ for (;;);
+}
diff --git a/ports/src/virtualbox/sup.h b/ports/src/virtualbox/sup.h
new file mode 100644
index 0000000000..36b1db750c
--- /dev/null
+++ b/ports/src/virtualbox/sup.h
@@ -0,0 +1,76 @@
+/*
+ * \brief Common VirtualBox SUPLib supplements
+ * \author Norman Feske
+ * \date 2013-08-20
+ */
+
+/*
+ * Copyright (C) 2013 Genode Labs GmbH
+ *
+ * This file is distributed under the terms of the GNU General Public License
+ * version 2.
+ */
+
+#ifndef _SUP_H_
+#define _SUP_H_
+
+/* Genode includes */
+#include "util/misc_math.h"
+#include "util/string.h"
+
+/* VirtualBox includes */
+#include
+#include
+#include
+
+/* libc memory allocator */
+#include
+
+uint64_t genode_cpu_hz();
+
+void inline genode_VMMR0_DO_GVMM_CREATE_VM(PSUPVMMR0REQHDR pReqHdr)
+{
+ GVMMCREATEVMREQ &req = reinterpret_cast(*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]);
+ VM *pVM = (VM *)Libc::mem_alloc()->alloc(cbVM, Genode::log2(PAGE_SIZE));
+ 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;
+ }
+
+ /* out parameters of the request */
+ req.pVMR0 = pVM->pVMR0;
+ req.pVMR3 = pVM;
+}
+
+#endif /* _SUP_H_ */
diff --git a/ports/src/virtualbox/target.mk b/ports/src/virtualbox/target.mk
new file mode 100644
index 0000000000..afc65a6bba
--- /dev/null
+++ b/ports/src/virtualbox/target.mk
@@ -0,0 +1,34 @@
+VBOX_CC_OPT += -DVBOX_WITH_HARDENING
+
+include $(REP_DIR)/lib/mk/virtualbox-common.inc
+
+TARGET = virtualbox
+SRC_CC = main.cc cxx_dummies.cc devices.cc drivers.cc dummies.cc libc.cc \
+ logger.cc mm.cc pdm.cc pgm.cc rt.cc sup.cc iommio.cc ioport.cc \
+ hwaccm.cc
+
+LIBS += base
+LIBS += config_args
+
+LIBS += virtualbox-bios virtualbox-recompiler virtualbox-runtime \
+ virtualbox-vmm virtualbox-devices virtualbox-drivers \
+ virtualbox-storage virtualbox-zlib virtualbox-liblzf \
+ virtualbox-hwaccl virtualbox-dis
+
+INC_DIR += $(call select_from_repositories,src/lib/libc)
+
+INC_DIR += $(VBOX_DIR)/Runtime/include
+INC_DIR += $(VBOX_DIR)/Frontends/VBoxBFE
+
+SRC_CC += Frontends/VBoxBFE/VBoxBFE.cpp
+SRC_CC += Frontends/VBoxBFE/DisplayImpl.cpp
+SRC_CC += Frontends/VBoxBFE/VMMDevInterface.cpp
+SRC_CC += Frontends/VBoxBFE/KeyboardImpl.cpp
+SRC_CC += Frontends/VBoxBFE/MachineDebuggerImpl.cpp
+SRC_CC += Frontends/VBoxBFE/StatusImpl.cpp
+
+INC_DIR += $(VBOX_DIR)/Main/include
+INC_DIR += $(VBOX_DIR)/VMM/include
+
+# search path to 'scan_code_set_2.h'
+INC_DIR += $(call select_from_repositories,src/drivers/input/ps2)
diff --git a/ports/src/virtualbox/timer.patch b/ports/src/virtualbox/timer.patch
new file mode 100644
index 0000000000..7e546ed338
--- /dev/null
+++ b/ports/src/virtualbox/timer.patch
@@ -0,0 +1,10 @@
++++ src/VBox/VMM/VMMR3/TM.cpp 2014-01-15 16:40:35
+@@ -1901,7 +1901,7 @@
+ #ifdef VBOX_WITH_REM
+ REMR3NotifyTimerPending(pVM, pVCpuDst);
+ #endif
+- VMR3NotifyCpuFFU(pVCpuDst->pUVCpu, VMNOTIFYFF_FLAGS_DONE_REM /** @todo | VMNOTIFYFF_FLAGS_POKE ?*/);
++ VMR3NotifyCpuFFU(pVCpuDst->pUVCpu, VMNOTIFYFF_FLAGS_DONE_REM | VMNOTIFYFF_FLAGS_POKE);
+ STAM_COUNTER_INC(&pVM->tm.s.StatTimerCallbackSetFF);
+ }
+ }
diff --git a/ports/src/virtualbox/util.h b/ports/src/virtualbox/util.h
new file mode 100644
index 0000000000..71714cf730
--- /dev/null
+++ b/ports/src/virtualbox/util.h
@@ -0,0 +1,39 @@
+/*
+ * \brief VirtualBox utilities
+ * \author Christian Helmuth
+ * \date 2013-08-28
+ */
+
+/*
+ * Copyright (C) 2013 Genode Labs GmbH
+ *
+ * This file is distributed under the terms of the GNU General Public License
+ * version 2.
+ */
+
+#ifndef _UTIL_H_
+#define _UTIL_H_
+
+/* VirtualBox includes */
+#include
+
+
+/**
+ * 64bit-aware cast of pointer to RTRCPTR (uint32_t)
+ */
+template
+RTRCPTR to_rtrcptr(T* ptr)
+{
+ return (RTRCPTR)((long)ptr & 0xffffffff);
+}
+
+/**
+ * 64bit-aware cast of RTRCPTR (uint32_t) to pointer
+ */
+template
+T* from_rtrcptr(RTRCPTR rcptr)
+{
+ return (T*)(rcptr | 0L);
+}
+
+#endif /* _UTIL_H_ */
diff --git a/ports/src/virtualbox/vbetables-gen.patch b/ports/src/virtualbox/vbetables-gen.patch
new file mode 100644
index 0000000000..86ccd723a6
--- /dev/null
+++ b/ports/src/virtualbox/vbetables-gen.patch
@@ -0,0 +1,20 @@
+--- src/VBox/Devices/Graphics/BIOS/vbetables-gen.c.orig 2013-11-19 16:09:24.844195101 +0100
++++ src/VBox/Devices/Graphics/BIOS/vbetables-gen.c 2013-11-19 16:09:38.288364715 +0100
+@@ -13,6 +13,7 @@
+
+ ModeInfo modes[] = {
+ /* standard VESA modes */
++#if 0
+ { 640, 400, 8 , 0x100},
+ { 640, 480, 8 , 0x101},
+ { 800, 600, 4 , 0x102},
+@@ -57,6 +58,9 @@
+ { 1152, 864, 16 , 0x14a},
+ { 1152, 864, 24 , 0x14b},
+ { 1152, 864, 32 , 0x14c},
++#else
++{ 800, 600, 16 , 0x111},
++#endif
+ { 0, },
+ };
+
diff --git a/ports/src/virtualbox/vboxbfe.patch b/ports/src/virtualbox/vboxbfe.patch
new file mode 100644
index 0000000000..3a91228ba3
--- /dev/null
+++ b/ports/src/virtualbox/vboxbfe.patch
@@ -0,0 +1,47 @@
++++ src/VBox/Frontends/VBoxBFE/VirtualBoxBase.h
+@@ -24,10 +24,9 @@
+ # include
+ #else
+ # include
++# include // For the AssertComRC macro
+ #endif
+
+-#include // For the AssertComRC macro
+-
+ #include
+ #include
+ #include
++++ src/VBox/Frontends/VBoxBFE/VBoxBFE.cpp
+@@ -1765,19 +1779,19 @@
+ /*
+ * VMM Device
+ */
+- rc = CFGMR3InsertNode(pDevices, "VMMDev", &pDev); UPDATE_RC();
+- rc = CFGMR3InsertNode(pDev, "0", &pInst); UPDATE_RC();
+- rc = CFGMR3InsertNode(pInst, "Config", &pCfg); UPDATE_RC();
+- rc = CFGMR3InsertInteger(pInst, "Trusted", 1); /* boolean */ UPDATE_RC();
+- rc = CFGMR3InsertInteger(pInst, "PCIDeviceNo", 4); UPDATE_RC();
+- rc = CFGMR3InsertInteger(pInst, "PCIFunctionNo", 0); UPDATE_RC();
+- rc = CFGMR3InsertInteger(pCfg, "RamSize", g_u32MemorySizeMB * _1M); UPDATE_RC();
+-
+- /* the VMM device's Main driver */
+- rc = CFGMR3InsertNode(pInst, "LUN#0", &pLunL0); UPDATE_RC();
+- rc = CFGMR3InsertString(pLunL0, "Driver", "HGCM"); UPDATE_RC();
+- rc = CFGMR3InsertNode(pLunL0, "Config", &pCfg); UPDATE_RC();
+- rc = CFGMR3InsertInteger(pCfg, "Object", (uintptr_t)gVMMDev); UPDATE_RC();
++// rc = CFGMR3InsertNode(pDevices, "VMMDev", &pDev); UPDATE_RC();
++// rc = CFGMR3InsertNode(pDev, "0", &pInst); UPDATE_RC();
++// rc = CFGMR3InsertNode(pInst, "Config", &pCfg); UPDATE_RC();
++// rc = CFGMR3InsertInteger(pInst, "Trusted", 1); /* boolean */ UPDATE_RC();
++// rc = CFGMR3InsertInteger(pInst, "PCIDeviceNo", 4); UPDATE_RC();
++// rc = CFGMR3InsertInteger(pInst, "PCIFunctionNo", 0); UPDATE_RC();
++// rc = CFGMR3InsertInteger(pCfg, "RamSize", g_u32MemorySizeMB * _1M); UPDATE_RC();
++//
++// /* the VMM device's Main driver */
++// rc = CFGMR3InsertNode(pInst, "LUN#0", &pLunL0); UPDATE_RC();
++// rc = CFGMR3InsertString(pLunL0, "Driver", "HGCM"); UPDATE_RC();
++// rc = CFGMR3InsertNode(pLunL0, "Config", &pCfg); UPDATE_RC();
++// rc = CFGMR3InsertInteger(pCfg, "Object", (uintptr_t)gVMMDev); UPDATE_RC();
+
+ /*
+ * AC'97 ICH audio
diff --git a/ports/src/virtualbox/vga.patch b/ports/src/virtualbox/vga.patch
new file mode 100644
index 0000000000..71957f4a16
--- /dev/null
+++ b/ports/src/virtualbox/vga.patch
@@ -0,0 +1,12 @@
++++ src/VBox/Devices/Graphics/DevVGA.cpp
+@@ -1845,6 +1846,10 @@
+ dup9 = 0;
+ if (ch >= 0xb0 && ch <= 0xdf && (s->ar[0x10] & 0x04))
+ dup9 = 1;
++
++ if (bgcol == fgcol && fgcol == 0) {
++ fgcol = ~0U;
++ }
+ vga_draw_glyph9(d1, linesize,
+ font_ptr, cheight, fgcol, bgcol, dup9);
+ }
diff --git a/ports/src/virtualbox/vga_fb.patch b/ports/src/virtualbox/vga_fb.patch
new file mode 100644
index 0000000000..cd4e72e5ec
--- /dev/null
+++ b/ports/src/virtualbox/vga_fb.patch
@@ -0,0 +1,18 @@
++++ src/VBox/Devices/Graphics/DevVGA.cpp
+@@ -3468,9 +3475,15 @@
+ int rc;
+ Assert(pThis);
+ Assert(GCPhys >= pThis->GCPhysVRAM);
++ Assert(GCPhys - pThis->GCPhysVRAM + cbBuf <= pThis->vram_size);
+ NOREF(pvPhys); NOREF(pvBuf); NOREF(cbBuf); NOREF(enmAccessType);
+
+- rc = vgaLFBAccess(pVM, pThis, GCPhys, 0);
++ rc = VINF_SUCCESS;
++ size_t offset = 0;
++ while (RT_SUCCESS(rc) && offset < cbBuf) {
++ rc = vgaLFBAccess(pVM, pThis, GCPhys + offset, 0);
++ offset += 1UL << PAGE_SHIFT;
++ }
+ if (RT_SUCCESS(rc))
+ return VINF_PGM_HANDLER_DO_DEFAULT;
+ AssertMsg(rc <= VINF_SUCCESS, ("rc=%Rrc\n", rc));
diff --git a/ports/src/virtualbox/vmdk.patch b/ports/src/virtualbox/vmdk.patch
new file mode 100644
index 0000000000..6679fd904d
--- /dev/null
+++ b/ports/src/virtualbox/vmdk.patch
@@ -0,0 +1,17 @@
++++ src/VBox/Storage/VMDK.cpp 2013-11-25 14:15:48.171143505 +0100
+@@ -6114,7 +6114,6 @@
+ }
+ pExtent->uGrainSectorAbs = uSectorExtentAbs;
+ pExtent->uGrain = uSectorExtentRel / pExtent->cSectorsPerGrain;
+- Assert(uLBA == uSectorExtentRel);
+ }
+ memcpy(pvBuf, (uint8_t *)pExtent->pvGrain + VMDK_SECTOR2BYTE(uSectorInGrain), cbToRead);
+ }
+@@ -6258,7 +6257,6 @@
+ * which is somewhere between expensive and impossible. */
+ rc = VERR_VD_VMDK_INVALID_STATE;
+ pExtent->uGrainSectorAbs = 0;
+- AssertRC(rc);
+ }
+ else
+ {
diff --git a/ports/src/virtualbox/vmm_memory.h b/ports/src/virtualbox/vmm_memory.h
new file mode 100644
index 0000000000..fd8ee1ead2
--- /dev/null
+++ b/ports/src/virtualbox/vmm_memory.h
@@ -0,0 +1,202 @@
+/*
+ * \brief Registry of VMM-local memory regions
+ * \author Norman Feske
+ * \date 2013-09-02
+ */
+
+/*
+ * Copyright (C) 2013 Genode Labs GmbH
+ *
+ * This file is distributed under the terms of the GNU General Public License
+ * version 2.
+ */
+
+#ifndef _VMM_MEMORY_H_
+#define _VMM_MEMORY_H_
+
+/*
+ * Work-around for a naming conflict between the enum definition of PAGE_SIZE
+ * in 'os/attached_ram_dataspace.h' and the VirtualBox #define with the same
+ * name.
+ */
+#define BACKUP_PAGESIZE PAGE_SIZE
+#undef PAGE_SIZE
+
+/* Genode includes */
+#include
+#include
+#include
+#include
+
+#define PAGE_SIZE BACKUP_PAGESIZE
+
+/* VirtualBox includes */
+#include
+
+
+class Vmm_memory
+{
+ struct Region;
+
+ typedef Genode::Ram_session Ram_session;
+ typedef Genode::Rm_session Rm_session;
+ typedef Genode::size_t size_t;
+ typedef Genode::Lock Lock;
+ typedef Genode::Attached_ram_dataspace Attached_ram_dataspace;
+ typedef Genode::List Region_list;
+
+ private:
+
+ struct Region : Region_list::Element, Attached_ram_dataspace
+ {
+ PPDMDEVINS pDevIns;
+ unsigned const iRegion;
+ RTGCPHYS vm_phys;
+ PFNPGMR3PHYSHANDLER pfnHandlerR3;
+ void *pvUserR3;
+
+ Region(Ram_session &ram, size_t size, PPDMDEVINS pDevIns,
+ unsigned iRegion)
+ :
+ Attached_ram_dataspace(&ram, size),
+ pDevIns(pDevIns),
+ iRegion(iRegion),
+ vm_phys(0), pfnHandlerR3(0), pvUserR3(0)
+ { }
+ };
+
+ Lock _lock;
+ Region_list _regions;
+
+ /**
+ * Backing store
+ */
+ Genode::Ram_session &_ram;
+
+ Region *_lookup_unsynchronized(PPDMDEVINS pDevIns, unsigned iRegion)
+ {
+ for (Region *r = _regions.first(); r; r = r->next())
+ if (r->pDevIns == pDevIns && r->iRegion == iRegion)
+ return r;
+ return 0;
+ }
+
+ Region *_lookup_unsynchronized(RTGCPHYS vm_phys, size_t size)
+ {
+ for (Region *r = _regions.first(); r; r = r->next())
+ if (r->vm_phys && r->vm_phys <= vm_phys
+ && vm_phys - r->vm_phys < r->size()
+ && r->size() - (vm_phys - r->vm_phys) >= size)
+ return r;
+
+ return 0;
+ }
+
+ public:
+
+ Vmm_memory(Ram_session &ram) : _ram(ram) { }
+
+ /**
+ * \throw Ram_session::Alloc_failed
+ * \throw Rm_session::Attach_failed
+ */
+ void *alloc(size_t cb, PPDMDEVINS pDevIns, unsigned iRegion)
+ {
+ Lock::Guard guard(_lock);
+
+ try {
+ Region *r = new (Genode::env()->heap())
+ Region(_ram, cb, pDevIns, iRegion);
+ _regions.insert(r);
+
+ return r->local_addr();
+
+ } catch (Ram_session::Alloc_failed) {
+ PERR("Vmm_memory::alloc(0x%zx): RAM allocation failed", cb);
+ throw;
+ } catch (Rm_session::Attach_failed) {
+ PERR("Vmm_memory::alloc(0x%zx): RM attach failed", cb);
+ throw;
+ }
+
+ return 0;
+ }
+
+ void *alloc_ram(size_t cb)
+ {
+ return alloc(cb, 0, 0);
+ }
+
+ size_t map_to_vm(PPDMDEVINS pDevIns, unsigned iRegion, RTGCPHYS GCPhys)
+ {
+ Lock::Guard guard(_lock);
+
+ Region *r = _lookup_unsynchronized(pDevIns, iRegion);
+
+ if (r) r->vm_phys = GCPhys;
+
+ return r ? r->size() : 0;
+ }
+
+ void add_handler(RTGCPHYS vm_phys, size_t size,
+ PFNPGMR3PHYSHANDLER pfnHandlerR3, void *pvUserR3)
+ {
+ Lock::Guard guard(_lock);
+
+ Region *r = _lookup_unsynchronized(vm_phys, size);
+
+ if (!r) return;
+
+ r->pfnHandlerR3 = pfnHandlerR3;
+ r->pvUserR3 = pvUserR3;
+ }
+
+ void * lookup(RTGCPHYS vm_phys, size_t size,
+ PFNPGMR3PHYSHANDLER *ppfnHandlerR3 = 0, void **ppvUserR3 = 0)
+ {
+ Lock::Guard guard(_lock);
+
+ Region *r = _lookup_unsynchronized(vm_phys, size);
+
+ if (!r) return 0;
+
+ if (ppfnHandlerR3) *ppfnHandlerR3 = r->pfnHandlerR3;
+ if (ppvUserR3) *ppvUserR3 = r->pvUserR3;
+
+ return reinterpret_cast(r->local_addr() +
+ (vm_phys - r->vm_phys));
+ }
+
+ bool unmap_from_vm(RTGCPHYS GCPhys);
+/*
+ {
+ size_t const size = 1;
+
+ Region *r = _lookup_unsynchronized(GCPhys, size);
+ if (!r) return false;
+
+ using Genode::addr_t;
+ addr_t const vmm_local = (addr_t)r->local_addr();
+
+ Assert(vmm_local);
+ Assert(!((r->size() - 1) & vmm_local));
+
+ using namespace Nova;
+ unsigned const order = Genode::log2(r->size() >> PAGE_SIZE_LOG2);
+
+ Rights rwx(true, true, true);
+ revoke(Mem_crd(vmm_local >> PAGE_SIZE_LOG2, order, rwx), false);
+
+ return true;
+ }
+*/
+};
+
+
+/**
+ * Return pointer to singleton instance
+ */
+Vmm_memory *vmm_memory();
+
+
+#endif /* _VMM_MEMORY_H_ */
diff --git a/ports/src/virtualbox/vmmdev.patch b/ports/src/virtualbox/vmmdev.patch
new file mode 100644
index 0000000000..80b2fb1239
--- /dev/null
+++ b/ports/src/virtualbox/vmmdev.patch
@@ -0,0 +1,28 @@
++++ src/VBox/Devices/VMMDev/VMMDev.cpp 2013-10-17 13:02:16.787071776 +0200
+@@ -1854,7 +1854,6 @@
+ }
+ break;
+ }
+-#endif /* VBOX_WITH_HGCM */
+
+ case VMMDevReq_HGCMCancel:
+ {
+@@ -1899,6 +1898,7 @@
+ }
+ break;
+ }
++#endif /* VBOX_WITH_HGCM */
+
+ case VMMDevReq_VideoAccelEnable:
+ {
+@@ -3341,8 +3341,10 @@
+ /* disabled statistics updating */
+ pThis->u32LastStatIntervalSize = 0;
+
++#ifdef VBOX_WITH_HGCM
+ /* Clear the "HGCM event enabled" flag so the event can be automatically reenabled. */
+ pThis->u32HGCMEnabled = 0;
++#endif
+
+ /*
+ * Clear the event variables.
diff --git a/ports/src/virtualbox/vmx_c++.patch b/ports/src/virtualbox/vmx_c++.patch
new file mode 100644
index 0000000000..7c95102850
--- /dev/null
+++ b/ports/src/virtualbox/vmx_c++.patch
@@ -0,0 +1,63 @@
++++ include/VBox/vmm/hwacc_vmx.h
+@@ -1338,10 +1338,10 @@
+ ".byte 0xF3, 0x0F, 0xC7, 0x34, 0x24 # VMXON [esp] \n\t"
+ "ja 2f \n\t"
+ "je 1f \n\t"
+- "movl $"STR(VERR_VMX_INVALID_VMXON_PTR)", %0 \n\t"
++ "movl $" STR(VERR_VMX_INVALID_VMXON_PTR)", %0 \n\t"
+ "jmp 2f \n\t"
+ "1: \n\t"
+- "movl $"STR(VERR_VMX_GENERIC)", %0 \n\t"
++ "movl $" STR(VERR_VMX_GENERIC)", %0 \n\t"
+ "2: \n\t"
+ "add $8, %%esp \n\t"
+ :"=rm"(rc)
+@@ -1418,7 +1418,7 @@
+ "push %2 \n\t"
+ ".byte 0x66, 0x0F, 0xC7, 0x34, 0x24 # VMCLEAR [esp] \n\t"
+ "jnc 1f \n\t"
+- "movl $"STR(VERR_VMX_INVALID_VMCS_PTR)", %0 \n\t"
++ "movl $" STR(VERR_VMX_INVALID_VMCS_PTR)", %0 \n\t"
+ "1: \n\t"
+ "add $8, %%esp \n\t"
+ :"=rm"(rc)
+@@ -1466,7 +1466,7 @@
+ "push %2 \n\t"
+ ".byte 0x0F, 0xC7, 0x34, 0x24 # VMPTRLD [esp] \n\t"
+ "jnc 1f \n\t"
+- "movl $"STR(VERR_VMX_INVALID_VMCS_PTR)", %0 \n\t"
++ "movl $" STR(VERR_VMX_INVALID_VMCS_PTR)", %0 \n\t"
+ "1: \n\t"
+ "add $8, %%esp \n\t"
+ :"=rm"(rc)
+@@ -1520,10 +1520,10 @@
+ ".byte 0x0F, 0x79, 0xC2 # VMWRITE eax, edx \n\t"
+ "ja 2f \n\t"
+ "je 1f \n\t"
+- "movl $"STR(VERR_VMX_INVALID_VMCS_PTR)", %0 \n\t"
++ "movl $" STR(VERR_VMX_INVALID_VMCS_PTR)", %0 \n\t"
+ "jmp 2f \n\t"
+ "1: \n\t"
+- "movl $"STR(VERR_VMX_INVALID_VMCS_FIELD)", %0 \n\t"
++ "movl $" STR(VERR_VMX_INVALID_VMCS_FIELD)", %0 \n\t"
+ "2: \n\t"
+ :"=rm"(rc)
+ :"0"(VINF_SUCCESS),
+@@ -1607,14 +1607,14 @@
+ int rc = VINF_SUCCESS;
+ # if RT_INLINE_ASM_GNU_STYLE
+ __asm__ __volatile__ (
+- "movl $"STR(VINF_SUCCESS)", %0 \n\t"
++ "movl $" STR(VINF_SUCCESS)", %0 \n\t"
+ ".byte 0x0F, 0x78, 0xc2 # VMREAD eax, edx \n\t"
+ "ja 2f \n\t"
+ "je 1f \n\t"
+- "movl $"STR(VERR_VMX_INVALID_VMCS_PTR)", %0 \n\t"
++ "movl $" STR(VERR_VMX_INVALID_VMCS_PTR)", %0 \n\t"
+ "jmp 2f \n\t"
+ "1: \n\t"
+- "movl $"STR(VERR_VMX_INVALID_VMCS_FIELD)", %0 \n\t"
++ "movl $" STR(VERR_VMX_INVALID_VMCS_FIELD)", %0 \n\t"
+ "2: \n\t"
+ :"=&r"(rc),
+ "=d"(*pData)