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)