diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-06 03:01:46 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-06 03:01:46 +0000 |
commit | f8fe689a81f906d1b91bb3220acde2a4ecb14c5b (patch) | |
tree | 26484e9d7e2c67806c2d1760196ff01aaa858e8c /src/VBox/ValidationKit/bootsectors | |
parent | Initial commit. (diff) | |
download | virtualbox-upstream.tar.xz virtualbox-upstream.zip |
Adding upstream version 6.0.4-dfsg.upstream/6.0.4-dfsgupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/VBox/ValidationKit/bootsectors')
342 files changed, 84474 insertions, 0 deletions
diff --git a/src/VBox/ValidationKit/bootsectors/Config.kmk b/src/VBox/ValidationKit/bootsectors/Config.kmk new file mode 100644 index 00000000..0b953bf2 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/Config.kmk @@ -0,0 +1,940 @@ +# $Id: Config.kmk $ +## @file +# kBuild Configuration file for VirtualBox Boot Sector Kit 3. +# + +# +# Copyright (C) 2010-2019 Oracle Corporation +# +# This file is part of VirtualBox Open Source Edition (OSE), as +# available from http://www.virtualbox.org. This file is free software; +# you can redistribute it and/or modify it under the terms of the GNU +# General Public License (GPL) as published by the Free Software +# Foundation, in version 2 as it comes in the "COPYING" file of the +# VirtualBox OSE distribution. VirtualBox OSE is distributed in the +# hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +# +# The contents of this file may alternatively be used under the terms +# of the Common Development and Distribution License Version 1.0 +# (CDDL) only, as it comes in the "COPYING.CDDL" file of the +# VirtualBox OSE distribution, in which case the provisions of the +# CDDL are applicable instead of those of the GPL. +# +# You may elect to license modified versions of this file under the +# terms and conditions of either the GPL or the CDDL or both. +# + +VBOX_BOOTSECTORS_CONFIG_KMK_INCLUDED = 1 + +# Include the parent configure file. +ifndef VBOX_VALIDATIONKIT_CONFIG_KMK_INCLUDED + include $(PATH_ROOT)/src/VBox/ValidationKit/Config.kmk +endif + +# Add our 32-bit and 64-bit C properties. +KBUILD_COMPILE_CATEGTORIES += C32 C64 +PROPS_TOOLS += C32TOOL C64TOOL +PROPS_SINGLE += C32TOOL C64TOOL C32OBJSUFF C64OBJSUFF +PROPS_ACCUMULATE_R += C32FLAGS C64FLAGS C32DEFS C64DEFS +PROPS_ACCUMULATE_L += C32INCS C64INCS + +if 0 # Adding as few as possible new properties. +KBUILD_COMPILE_CATEGTORIES += C16 +PROPS_TOOLS += C16TOOL +PROPS_SINGLE += C16TOOL C16OBJSUFF +PROPS_ACCUMULATE_R += C16FLAGS C16DEFS +PROPS_ACCUMULATE_L += C16INCS +endif + +# Add noarch to the architectures list (will be there by default in a new kBuild). +KBUILD_ARCHES += noarch + + +# The bootsector directory. +VBOX_PATH_BOOTSECTORS_SRC = $(VBOX_PATH_VALIDATIONKIT_SRC)/bootsectors + +# The bs3kit source directory. +VBOX_PATH_BS3KIT_SRC = $(VBOX_PATH_BOOTSECTORS_SRC)/bs3kit + + +# The 16-bit code & data segment classes. +if 1 +BS3KIT_CLASS_CODE16 = CODE +BS3KIT_SEGNM_DATA16 = +BS3KIT_CLASS_DATA16 = DATA +BS3KIT_GRPNM_DATA16 = DGROUP +BS3KIT_CLASS_BSS16 = BSS +else +BS3KIT_CLASS_CODE16 = BS3CLASS16CODE +BS3KIT_SEGNM_DATA16 = BS3DATA16 +BS3KIT_CLASS_DATA16 = FAR_DATA +BS3KIT_GRPNM_DATA16 = BS3DATA16_GROUP +BS3KIT_CLASS_BSS16 = ??? +endif + + +## +# Macro for generating near-call aliases for one 16-bit C function. +# @param 1 The target name. +# @param 2 The common function. +BS3KIT_FN_GEN_CMN_NEARSTUB = $(evalcall2 def_Bs3KitGenNearStubSource,$1,_$2_c16,_$2_f16) + +## +# Macro for generating near-call aliases for one 16-bit C mode function. +# @param 1 The target name. +# @param 2 The mode function. +BS3KIT_FN_GEN_MODE_NEARSTUB = $(foreach suff, \ + _rm \ + _pe16 \ + _pe16_v86 \ + _pe32_16 \ + _pev86 \ + _pp16 \ + _pp16_v86 \ + _pp32_16 \ + _ppv86 \ + _pae16 \ + _pae16_v86 \ + _pae32_16 \ + _paev86 \ + _lm16 \ + ,$(evalcall2 def_Bs3KitGenNearStubSource,$1,_$2$(suff),_$2$(suff)_far)) + +# @param 1 The target name. +# @param 2 The near function name. +# @param 3 The far function name. +define def_Bs3KitGenNearStubSource +$1_SOURCES += $$($1_0_OUTDIR)/stub$2.asm +$1_CLEAN += $$($1_0_OUTDIR)/stub$2.asm +$$$$($1_0_OUTDIR)/stub$2.asm: $$(VBOX_PATH_BOOTSECTORS_SRC)/Config.kmk | $$$$(dir $$$$@) + $(QUIET)$(APPEND) -tn $$@ \ + '%include "bs3kit.mac"' \ + 'BS3_BEGIN_TEXT16' \ + ' extern $3' \ + 'BS3_BEGIN_TEXT16_NEARSTUBS' \ + 'BS3_GLOBAL_NAME_EX $2, function, 6' \ + ' pop ax' \ + ' push cs' \ + ' push ax' \ + ' jmp $3 wrt CGROUP16' +endef + + +## +# Macro for generating far-call aliases for zero or more 16-bit C or assembly functions. +# @param 1 The target name. +# @param 2 The common function. +# @param 3 The parameter size in bytes. +BS3KIT_FN_GEN_CMN_FARSTUB = $(evalcall2 def_Bs3KitGenFarStubSource,$1,$2,_f16,_c16,$3) + +## +# Macro for generating far-call aliases for zero or more 16-bit C mode functions. +# @param 1 The target name. +# @param 2 The mode function. +# @param 3 The parameter size in bytes. +BS3KIT_FN_GEN_MODE_FARSTUB = $(foreach suff, \ + _rm \ + _pe16 \ + _pe16_v86 \ + _pe32_16 \ + _pev86 \ + _pp16 \ + _pp16_v86 \ + _pp32_16 \ + _ppv86 \ + _pae16 \ + _pae16_v86 \ + _pae32_16 \ + _paev86 \ + _lm16 \ + ,$(evalcall2 def_Bs3KitGenFarStubSource,$1,$2,$(suff)_far,$(suff),$3)) + +# @param 1 The target name. +# @param 2 The function name. +# @param 3 The far function suffix. +# @param 4 The near function suffix. +# @param 5 The parameter size in bytes. +define def_Bs3KitGenFarStubSource +$1_SOURCES += $$($1_0_OUTDIR)/stub_$2$3.asm +$1_CLEAN += $$($1_0_OUTDIR)/stub_$2$3.asm +$$$$($1_0_OUTDIR)/stub_$2$3.asm: $$(VBOX_PATH_BOOTSECTORS_SRC)/Config.kmk | $$$$(dir $$$$@) + $(QUIET)$(APPEND) -tn $$@ \ + '%include "bs3kit.mac"' \ + 'BS3_BEGIN_TEXT16' \ + ' extern _$2$4' \ + 'BS3_BEGIN_TEXT16_FARSTUBS' \ + 'BS3_PROC_BEGIN _$2$3' \ + ' CPU 8086' \ + ' inc bp' \ + ' push bp' \ + ' mov bp, sp' \ + '%assign offParam $5' \ + '%rep $5 / 2' \ + ' push word [bp + 2 + 4 + offParam - 2]' \ + '%assign offParam offParam - 2' \ + '%endrep' \ + ' call _$2$4' \ + ' add sp, $5' \ + ' pop bp' \ + ' dec bp' \ + ' retf' \ + 'BS3_PROC_END _$2$3' \ + '' +endef + + +# +# Tools Tools Tools +# Tools Tools Tools +# Tools Tools Tools +# + +if defined(VBOX_USE_KSUBMIT) && "$(KBUILD_HOST)" == "win" + VBOX_BS3KIT_KSUBMIT_OBJ_CONV := kmk_builtin_kSubmit -- +else + VBOX_BS3KIT_KSUBMIT_OBJ_CONV := +endif + +# Dummy CP "linker" tool. +TOOL_VBoxBsCpLd = Dummy copy linker. +TOOL_VBoxBsCpLd_LINK_MISCBIN_OUTPUT = +TOOL_VBoxBsCpLd_LINK_MISCBIN_DEPEND = +TOOL_VBoxBsCpLd_LINK_MISCBIN_DEPORD = +define TOOL_VBoxBsCpLd_LINK_MISCBIN_CMDS + $(CP) -- $(objs) $(othersrc) "$(out)" +endef + +# Dummy exit 1 "linker" tool. +TOOL_VBoxBsUnusedLd = Dummy unused linker. +TOOL_VBoxBsUnusedLd_LINK_MISCBIN_OUTPUT = +TOOL_VBoxBsUnusedLd_LINK_MISCBIN_DEPEND = +TOOL_VBoxBsUnusedLd_LINK_MISCBIN_DEPORD = +define TOOL_VBoxBsUnusedLd_LINK_MISCBIN_CMDS + echo "cannot use this template for linking" + exit 1 +endef + +# NASM tool with dependency workarounds (change dir to force consistent results; add -MP). +# Requires http://permalink.gmane.org/gmane.comp.lang.nasm.devel/3704 to work. +include $(KBUILD_PATH)/tools/NASM.kmk +TOOL_VBoxNasm = Our version of the NASM tool +ifndef TOOL_VBoxNasm_PATH + TOOL_VBoxNasm_PATH := $(firstword $(rsort $(wildcard $(KBUILD_DEVTOOLS_HST)/nasm/v*.*))) + if "$(TOOL_VBoxNasm_PATH)" == "" && "$(KBUILD_DEVTOOLS_HST_ALT)" != "" + TOOL_VBoxNasm_PATH := $(firstword $(rsort $(wildcard $(KBUILD_DEVTOOLS_HST_ALT)/nasm/v*.*))) + endif +endif +ifneq ($(TOOL_VBoxNasm_PATH),) + TOOL_VBoxNasm_AS ?= $(TOOL_VBoxNasm_PATH)/nasm$(HOSTSUFF_EXE) +else + TOOL_VBoxNasm_AS ?= nasm$(HOSTSUFF_EXE) +endif +TOOL_VBoxNasm_ASFLAGS ?= $(TOOL_NASM_ASFLAGS) +TOOL_VBoxNasm_COMPILE_AS_OUTPUT = $(outbase).lst +TOOL_VBoxNasm_COMPILE_AS_DEPEND = $(VBoxBs3ObjConverter_1_TARGET) +TOOL_VBoxNasm_COMPILE_AS_DEPORD = +define TOOL_VBoxNasm_COMPILE_AS_CMDS +ifdef TOOL_VBoxNasm_USE_KSUBMIT + $(QUIET)kmk_builtin_kSubmit -C $(PATH_OUT_BASE) -- $(TOOL_VBoxNasm_AS)\ + $(flags) $(addsuffix /,$(addprefix -i, $(incs))) $(addprefix -D, $(defs))\ + -l $(outbase).lst\ + -o $(obj)\ + -MD "$(dep)" -MP\ + $(abspath $(source)) +else + $(QUIET)$(REDIRECT) -C $(PATH_OUT_BASE) -- $(TOOL_VBoxNasm_AS)\ + $(flags) $(addsuffix /,$(addprefix -i, $(incs))) $(addprefix -D, $(defs))\ + -l $(outbase).lst\ + -o $(obj)\ + -MD "$(dep)" -MP\ + $(abspath $(source)) +endif + $(QUIET)$(VBOX_BS3KIT_KSUBMIT_OBJ_CONV) $(VBoxBs3ObjConverter_1_TARGET) "$(obj)" +endef + +# +# ELF 64-bit compiler tool with object conversion. +# +# Mac needs cross compiler: sudo port install x86_64-elf-gcc +# +TOOL_Bs3Gcc64Elf64 := AMD64/ELF64 gcc/g++ (cross) compiler. +ifeq ($(KBUILD_HOST),darwin) + TOOL_Bs3Gcc64Elf64_CC ?= x86_64-elf-gcc$(HOSTSUFF_EXE) -m64 + TOOL_Bs3Gcc64Elf64_CXX ?= x86_64-elf-g++$(HOSTSUFF_EXE) -m64 +else + TOOL_Bs3Gcc64Elf64_CC ?= gcc$(HOSTSUFF_EXE) -m64 + TOOL_Bs3Gcc64Elf64_CXX ?= g++$(HOSTSUFF_EXE) -m64 +endif +ifdef SLKRUNS + TOOL_Bs3Gcc64Elf64_CC += -fmessage-length=0 + TOOL_Bs3Gcc64Elf64_CXX += -fmessage-length=0 +endif +TOOL_Bs3Gcc64Elf64_COBJSUFF = .o64 +TOOL_Bs3Gcc64Elf64_CFLAGS = -fno-pie -x c $(VBOX_GCC_Wa_cma_nocompress_debug_sections) +TOOL_Bs3Gcc64Elf64_CFLAGS.debug = -g +TOOL_Bs3Gcc64Elf64_CFLAGS.profile = -O2 #-g -pg +TOOL_Bs3Gcc64Elf64_CFLAGS.release = -O2 +TOOL_Bs3Gcc64Elf64_CINCS = +TOOL_Bs3Gcc64Elf64_CDEFS = +TOOL_Bs3Gcc64Elf64_COMPILE_C_DEPEND = $(VBoxBs3ObjConverter_1_TARGET) +TOOL_Bs3Gcc64Elf64_COMPILE_C_DEPORD = +TOOL_Bs3Gcc64Elf64_COMPILE_C_OUTPUT = +TOOL_Bs3Gcc64Elf64_COMPILE_C_OUTPUT_MAYBE = $(obj).orignal +define TOOL_Bs3Gcc64Elf64_COMPILE_C_CMDS + $(QUIET)$(TOOL_Bs3Gcc64Elf64_CC) -c\ + $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\ + -Wp,-MD,$(dep) -Wp,-MT,$(obj) -Wp,-MP\ + -o $(obj)\ + $(abspath $(source)) + $(QUIET)$(VBOX_BS3KIT_KSUBMIT_OBJ_CONV) $(VBoxBs3ObjConverter_1_TARGET) "$(obj)" + $(QUIET)$(APPEND) -n "$(dep)" "" "$(source):" "" +endef + +TOOL_Bs3Gcc64Elf64_C64OBJSUFF = $(TOOL_Bs3Gcc64Elf64_COBJSUFF) +TOOL_Bs3Gcc64Elf64_C64FLAGS = $(TOOL_Bs3Gcc64Elf64_CFLAGS) +TOOL_Bs3Gcc64Elf64_C64FLAGS.debug = $(TOOL_Bs3Gcc64Elf64_CFLAGS.debug) +TOOL_Bs3Gcc64Elf64_C64FLAGS.profile = $(TOOL_Bs3Gcc64Elf64_CFLAGS.profile) +TOOL_Bs3Gcc64Elf64_C64FLAGS.release = $(TOOL_Bs3Gcc64Elf64_CFLAGS.release) +TOOL_Bs3Gcc64Elf64_C64INCS = $(TOOL_Bs3Gcc64Elf64_CINCS) +TOOL_Bs3Gcc64Elf64_C64DEFS = $(TOOL_Bs3Gcc64Elf64_CDEFS) +TOOL_Bs3Gcc64Elf64_COMPILE_C64_DEPEND = $(TOOL_Bs3Gcc64Elf64_COMPILE_C_DEPEND) +TOOL_Bs3Gcc64Elf64_COMPILE_C64_DEPORD = $(TOOL_Bs3Gcc64Elf64_COMPILE_C_DEPORD) +TOOL_Bs3Gcc64Elf64_COMPILE_C64_OUTPUT = $(TOOL_Bs3Gcc64Elf64_COMPILE_C_OUTPUT) +TOOL_Bs3Gcc64Elf64_COMPILE_C64_OUTPUT_MAYBE = $(TOOL_Bs3Gcc64Elf64_COMPILE_C_OUTPUT_MAYBE) +define TOOL_Bs3Gcc64Elf64_COMPILE_C64_CMDS +$(TOOL_Bs3Gcc64Elf64_COMPILE_C_CMDS) +endef + +TOOL_Bs3Gcc64Elf64_CXXOBJSUFF ?= .o +TOOL_Bs3Gcc64Elf64_CXXFLAGS ?= -fno-pie $(VBOX_GCC_Wa_cma_nocompress_debug_sections) +TOOL_Bs3Gcc64Elf64_CXXFLAGS.debug ?= -g0 # no debug info, thank you +TOOL_Bs3Gcc64Elf64_CXXFLAGS.profile ?= -O2 #-g -pg +TOOL_Bs3Gcc64Elf64_CXXFLAGS.release ?= -O2 +TOOL_Bs3Gcc64Elf64_CXXINCS ?= +TOOL_Bs3Gcc64Elf64_CXXDEFS ?= +TOOL_Bs3Gcc64Elf64_COMPILE_CXX_DEPEND = $(VBoxBs3ObjConverter_1_TARGET) +TOOL_Bs3Gcc64Elf64_COMPILE_CXX_DEPORD = +TOOL_Bs3Gcc64Elf64_COMPILE_CXX_OUTPUT = +TOOL_Bs3Gcc64Elf64_COMPILE_CXX_OUTPUT_MAYBE = $(obj).orignal +define TOOL_Bs3Gcc64Elf64_COMPILE_CXX_CMDS + $(QUIET)$(TOOL_Bs3Gcc64Elf64_CXX) -c\ + $(flags) $(addprefix -I, $(incs)) $(addprefix -D, $(defs))\ + -Wp,-MD,$(dep) -Wp,-MT,$(obj) -Wp,-MP\ + -o $(obj)\ + $(abspath $(source)) + $(QUIET)$(VBOX_BS3KIT_KSUBMIT_OBJ_CONV) $(VBoxBs3ObjConverter_1_TARGET) "$(obj)" + $(QUIET)$(APPEND) -n "$(dep)" "" "$(source):" "" +endef + +# +# Visual C++ tool variant that runs the object converter afterwards. +# +TOOL_Bs3Vcc64 := Visual C++ 64-bit +TOOL_Bs3Vcc64_CC = $(TOOL_$(VBOX_VCC_TOOL_STEM)AMD64_CC) +TOOL_Bs3Vcc64_CXX = $(TOOL_$(VBOX_VCC_TOOL_STEM)AMD64_CXX) +TOOL_Bs3Vcc64_COBJSUFF = .o64 +TOOL_Bs3Vcc64_CFLAGS = $(filter-out -TC,$(TOOL_$(VBOX_VCC_TOOL_STEM)AMD64_CFLAGS)) -TC +TOOL_Bs3Vcc64_CFLAGS.debug = +TOOL_Bs3Vcc64_CFLAGS.dbgopt = -O1 +TOOL_Bs3Vcc64_CFLAGS.profile = -O1 +TOOL_Bs3Vcc64_CFLAGS.release = -O1 +TOOL_Bs3Vcc64_CINCS = $(PATH_TOOL_$(VBOX_VCC_TOOL_STEM)AMD64_INC) +TOOL_Bs3Vcc64_CDEFS = +TOOL_Bs3Vcc64_COMPILE_C_DEPEND = $(TOOL_$(VBOX_VCC_TOOL_STEM)AMD64_COMPILE_C_DEPEND) $(VBoxBs3ObjConverter_1_TARGET) +TOOL_Bs3Vcc64_COMPILE_C_DEPORD = $(TOOL_$(VBOX_VCC_TOOL_STEM)AMD64_COMPILE_C_DEPORD) +TOOL_Bs3Vcc64_COMPILE_C_OUTPUT = $(TOOL_$(VBOX_VCC_TOOL_STEM)AMD64_COMPILE_C_OUTPUT) +TOOL_Bs3Vcc64_COMPILE_C_OUTPUT_MAYBE = $(TOOL_$(VBOX_VCC_TOOL_STEM)AMD64_COMPILE_C_OUTPUT_MAYBE) $(obj).orignal +define TOOL_Bs3Vcc64_COMPILE_C_CMDS +$(TOOL_$(VBOX_VCC_TOOL_STEM)AMD64_COMPILE_C_CMDS) + $(QUIET)$(VBOX_BS3KIT_KSUBMIT_OBJ_CONV) $(VBoxBs3ObjConverter_1_TARGET) "$(obj)" +endef + +TOOL_Bs3Vcc64_C64OBJSUFF = $(TOOL_Bs3Vcc64_COBJSUFF) +TOOL_Bs3Vcc64_C64FLAGS = $(TOOL_Bs3Vcc64_CFLAGS) +TOOL_Bs3Vcc64_C64FLAGS.debug = $(TOOL_Bs3Vcc64_CFLAGS.debug) +TOOL_Bs3Vcc64_C64FLAGS.dbgopt = $(TOOL_Bs3Vcc64_CFLAGS.dbgopt) +TOOL_Bs3Vcc64_C64FLAGS.profile = $(TOOL_Bs3Vcc64_CFLAGS.profile) +TOOL_Bs3Vcc64_C64FLAGS.release = $(TOOL_Bs3Vcc64_CFLAGS.release) +TOOL_Bs3Vcc64_C64INCS = $(TOOL_Bs3Vcc64_CINCS) +TOOL_Bs3Vcc64_C64DEFS = $(TOOL_Bs3Vcc64_CDEFS) +TOOL_Bs3Vcc64_COMPILE_C64_DEPEND = $(TOOL_Bs3Vcc64_COMPILE_C_DEPEND) +TOOL_Bs3Vcc64_COMPILE_C64_DEPORD = $(TOOL_Bs3Vcc64_COMPILE_C_DEPORD) +TOOL_Bs3Vcc64_COMPILE_C64_OUTPUT = $(TOOL_Bs3Vcc64_COMPILE_C_OUTPUT) +TOOL_Bs3Vcc64_COMPILE_C64_OUTPUT_MAYBE = $(TOOL_Bs3Vcc64_COMPILE_C_OUTPUT_MAYBE) +define TOOL_Bs3Vcc64_COMPILE_C64_CMDS +$(TOOL_Bs3Vcc64_COMPILE_C_CMDS) +endef + +TOOL_Bs3Vcc64_CXXOBJSUFF = $(TOOL_$(VBOX_VCC_TOOL_STEM)AMD64_CXXOBJSUFF) +TOOL_Bs3Vcc64_CXXFLAGS = $(TOOL_$(VBOX_VCC_TOOL_STEM)AMD64_CXXFLAGS) -TP +TOOL_Bs3Vcc64_CXXFLAGS.debug = +TOOL_Bs3Vcc64_CXXFLAGS.dbgopt = -O1 +TOOL_Bs3Vcc64_CXXFLAGS.profile = -O1 +TOOL_Bs3Vcc64_CXXFLAGS.release = -O1 +TOOL_Bs3Vcc64_CXXINCS = $(PATH_TOOL_$(VBOX_VCC_TOOL_STEM)AMD64_INC) +TOOL_Bs3Vcc64_CXXDEFS = +TOOL_Bs3Vcc64_COMPILE_CXX_DEPEND = $(TOOL_$(VBOX_VCC_TOOL_STEM)AMD64_COMPILE_CXX_DEPEND) $(VBoxBs3ObjConverter_1_TARGET) +TOOL_Bs3Vcc64_COMPILE_CXX_DEPORD = $(TOOL_$(VBOX_VCC_TOOL_STEM)AMD64_COMPILE_CXX_DEPORD) +TOOL_Bs3Vcc64_COMPILE_CXX_OUTPUT = $(TOOL_$(VBOX_VCC_TOOL_STEM)AMD64_COMPILE_CXX_OUTPUT) +TOOL_Bs3Vcc64_COMPILE_CXX_OUTPUT_MAYBE = $(TOOL_$(VBOX_VCC_TOOL_STEM)AMD64_COMPILE_CXX_OUTPUT_MAYBE) $(obj).orignal +define TOOL_Bs3Vcc64_COMPILE_CXX_CMDS +$(TOOL_$(VBOX_VCC_TOOL_STEM)AMD64_COMPILE_CXX_CMDS) + $(QUIET)$(VBOX_BS3KIT_KSUBMIT_OBJ_CONV) $(VBoxBs3ObjConverter_1_TARGET) "$(obj)" +endef + +# +# 32-bit OpenWatcom C/C++ tool variant that runs the object converter afterwards +# to rename intrinsic functions so they don't clash with the 16-bit compiler. +# +TOOL_Bs3Ow32 := OpenWatcom C/C++ 32-bit with object convertsion +TOOL_Bs3Ow32_CC = $(TOOL_OPENWATCOM_CC) +TOOL_Bs3Ow32_CXX = $(TOOL_OPENWATCOM_CXX) +TOOL_Bs3Ow32_COBJSUFF = .o32 +TOOL_Bs3Ow32_CFLAGS = $(TOOL_OPENWATCOM_CFLAGS) +# -adfs \ - This is too complicated and it doesn't support stubbing files (svn rename fun.h pain.h). Use kDepObj instead. +# -ad=$(call TOOL_OPENWATCOM_FIX_SLASHES,$(dep)) \ +# -adt=$(call TOOL_OPENWATCOM_FIX_SLASHES,$(obj)) \ +# -add=$(call TOOL_OPENWATCOM_FIX_SLASHES,$(abspath $(source))) \ +# -adhp=$(call TOOL_OPENWATCOM_FIX_SLASHES,$(dir $(abspath $(source)))) +TOOL_Bs3Ow32_CFLAGS.debug = $(TOOL_OPENWATCOM_CFLAGS.debug) +TOOL_Bs3Ow32_CFLAGS.dbgopt = $(TOOL_OPENWATCOM_CFLAGS.dbgopt) +TOOL_Bs3Ow32_CFLAGS.profile = $(TOOL_OPENWATCOM_CFLAGS.profile) +TOOL_Bs3Ow32_CFLAGS.release = $(TOOL_OPENWATCOM_CFLAGS.release) +TOOL_Bs3Ow32_CINCS = $(TOOL_OPENWATCOM_CINCS) +TOOL_Bs3Ow32_CDEFS = +TOOL_Bs3Ow32_COMPILE_C_DEPEND = $(TOOL_OPENWATCOM_COMPILE_C_DEPEND) $(VBoxBs3ObjConverter_1_TARGET) +TOOL_Bs3Ow32_COMPILE_C_DEPORD = $(TOOL_OPENWATCOM_COMPILE_C_DEPORD) +TOOL_Bs3Ow32_COMPILE_C_OUTPUT = $(TOOL_OPENWATCOM_COMPILE_C_OUTPUT) +TOOL_Bs3Ow32_COMPILE_C_OUTPUT_MAYBE = $(TOOL_OPENWATCOM_COMPILE_C_OUTPUT_MAYBE) $(obj).orignal +define TOOL_Bs3Ow32_COMPILE_C_CMDS +$(TOOL_OPENWATCOM_COMPILE_C_CMDS) + $(QUIET)$(VBOX_BS3KIT_KSUBMIT_OBJ_CONV) $(VBoxBs3ObjConverter_1_TARGET) "$(obj)" +endef + +TOOL_Bs3Ow32_C32OBJSUFF = $(TOOL_Bs3Ow32_COBJSUFF) +TOOL_Bs3Ow32_C32FLAGS = $(TOOL_Bs3Ow32_CFLAGS) +TOOL_Bs3Ow32_C32FLAGS.debug = $(TOOL_Bs3Ow32_CFLAGS.debug) +TOOL_Bs3Ow32_C32FLAGS.dbgopt = $(TOOL_Bs3Ow32_CFLAGS.dbgopt) +TOOL_Bs3Ow32_C32FLAGS.profile = $(TOOL_Bs3Ow32_CFLAGS.profile) +TOOL_Bs3Ow32_C32FLAGS.release = $(TOOL_Bs3Ow32_CFLAGS.release) +TOOL_Bs3Ow32_C32INCS = $(TOOL_Bs3Ow32_CINCS) +TOOL_Bs3Ow32_C32DEFS = +TOOL_Bs3Ow32_COMPILE_C32_DEPEND = $(TOOL_Bs3Ow32_COMPILE_C_DEPEND) +TOOL_Bs3Ow32_COMPILE_C32_DEPORD = $(TOOL_Bs3Ow32_COMPILE_C_DEPORD) +TOOL_Bs3Ow32_COMPILE_C32_OUTPUT = $(TOOL_Bs3Ow32_COMPILE_C_OUTPUT) +TOOL_Bs3Ow32_COMPILE_C32_OUTPUT_MAYBE = $(TOOL_Bs3Ow32_COMPILE_C_OUTPUT_MAYBE) +define TOOL_Bs3Ow32_COMPILE_C32_CMDS +$(TOOL_Bs3Ow32_COMPILE_C_CMDS) +endef + +TOOL_Bs3Ow32_CXXOBJSUFF = $(TOOL_OPENWATCOM_CXXOBJSUFF) +TOOL_Bs3Ow32_CXXFLAGS = $(TOOL_OPENWATCOM_CXXFLAGS) -ad=$(call TOOL_OPENWATCOM_FIX_SLASHES,$(dep)) -adfs +TOOL_Bs3Ow32_CXXFLAGS.debug = $(TOOL_OPENWATCOM_CXXFLAGS.debug) +TOOL_Bs3Ow32_CXXFLAGS.dbgopt = $(TOOL_OPENWATCOM_CXXFLAGS.dbgopt) +TOOL_Bs3Ow32_CXXFLAGS.profile = $(TOOL_OPENWATCOM_CXXFLAGS.profile) +TOOL_Bs3Ow32_CXXFLAGS.release = $(TOOL_OPENWATCOM_CXXFLAGS.release) +TOOL_Bs3Ow32_CXXINCS = $(TOOL_OPENWATCOM_CXXINCS) +TOOL_Bs3Ow32_CXXDEFS = +TOOL_Bs3Ow32_COMPILE_CXX_DEPEND = $(TOOL_OPENWATCOM_COMPILE_CXX_DEPEND) $(VBoxBs3ObjConverter_1_TARGET) +TOOL_Bs3Ow32_COMPILE_CXX_DEPORD = $(TOOL_OPENWATCOM_COMPILE_CXX_DEPORD) +TOOL_Bs3Ow32_COMPILE_CXX_OUTPUT = $(TOOL_OPENWATCOM_COMPILE_CXX_OUTPUT) +TOOL_Bs3Ow32_COMPILE_CXX_OUTPUT_MAYBE = $(TOOL_OPENWATCOM_COMPILE_CXX_OUTPUT_MAYBE) $(obj).orignal +define TOOL_Bs3Ow32_COMPILE_CXX_CMDS +$(TOOL_OPENWATCOM_COMPILE_CXX_CMDS) + $(QUIET)$(VBOX_BS3KIT_KSUBMIT_OBJ_CONV) $(VBoxBs3ObjConverter_1_TARGET) "$(obj)" +endef + + +# +# 16-bit OpenWatcom C/C++ tool variant that runs the object converter afterwards +# to rename intrinsic functions so they don't clash with the 16-bit compiler. +# +TOOL_Bs3Ow16 := OpenWatcom C/C++ 16-bit with object convertsion +TOOL_Bs3Ow16_CC = $(TOOL_OPENWATCOM-16_CC) +TOOL_Bs3Ow16_CXX = $(TOOL_OPENWATCOM-16_CXX) +TOOL_Bs3Ow16_COBJSUFF = .o16 +TOOL_Bs3Ow16_CFLAGS = $(TOOL_OPENWATCOM-16_CFLAGS) +TOOL_Bs3Ow16_CFLAGS.debug = $(TOOL_OPENWATCOM-16_CFLAGS.debug) +TOOL_Bs3Ow16_CFLAGS.dbgopt = $(TOOL_OPENWATCOM-16_CFLAGS.dbgopt) +TOOL_Bs3Ow16_CFLAGS.profile = $(TOOL_OPENWATCOM-16_CFLAGS.profile) +TOOL_Bs3Ow16_CFLAGS.release = $(TOOL_OPENWATCOM-16_CFLAGS.release) +TOOL_Bs3Ow16_CINCS = $(TOOL_OPENWATCOM-16_CINCS) +TOOL_Bs3Ow16_CDEFS = +TOOL_Bs3Ow16_COMPILE_C_DEPEND = $(TOOL_OPENWATCOM-16_COMPILE_C_DEPEND) $(VBoxBs3ObjConverter_1_TARGET) +TOOL_Bs3Ow16_COMPILE_C_DEPORD = $(TOOL_OPENWATCOM-16_COMPILE_C_DEPORD) +TOOL_Bs3Ow16_COMPILE_C_OUTPUT = $(TOOL_OPENWATCOM-16_COMPILE_C_OUTPUT) +TOOL_Bs3Ow16_COMPILE_C_OUTPUT_MAYBE = $(TOOL_OPENWATCOM-16_COMPILE_C_OUTPUT_MAYBE) +define TOOL_Bs3Ow16_COMPILE_C_CMDS +$(TOOL_OPENWATCOM-16_COMPILE_C_CMDS) + $(QUIET)$(VBOX_BS3KIT_KSUBMIT_OBJ_CONV) $(VBoxBs3ObjConverter_1_TARGET) "$(obj)" +endef + +TOOL_Bs3Ow16_C16OBJSUFF = $(TOOL_Bs3Ow16_C16OBJSUFF) +TOOL_Bs3Ow16_C16FLAGS = $(TOOL_Bs3Ow16_C16FLAGS) +TOOL_Bs3Ow16_C16FLAGS.debug = $(TOOL_Bs3Ow16_C16FLAGS.debug) +TOOL_Bs3Ow16_C16FLAGS.dbgopt = $(TOOL_Bs3Ow16_C16FLAGS.dbgopt) +TOOL_Bs3Ow16_C16FLAGS.profile = $(TOOL_Bs3Ow16_C16FLAGS.profile) +TOOL_Bs3Ow16_C16FLAGS.release = $(TOOL_Bs3Ow16_C16FLAGS.release) +TOOL_Bs3Ow16_C16INCS = $(TOOL_Bs3Ow16_C16INCS) +TOOL_Bs3Ow16_C16DEFS = $(TOOL_Bs3Ow16_C16DEFS) +TOOL_Bs3Ow16_COMPILE_C16_DEPEND = $(TOOL_Bs3Ow16_COMPILE_C16_DEPEND) +TOOL_Bs3Ow16_COMPILE_C16_DEPORD = $(TOOL_Bs3Ow16_COMPILE_C16_DEPORD) +TOOL_Bs3Ow16_COMPILE_C16_OUTPUT = $(TOOL_Bs3Ow16_COMPILE_C16_OUTPUT) +TOOL_Bs3Ow16_COMPILE_C16_OUTPUT_MAYBE = $(TOOL_Bs3Ow16_COMPILE_C16_OUTPUT_MAYBE) +define TOOL_Bs3Ow16_COMPILE_C16_CMDS +$(TOOL_Bs3Ow16_COMPILE_C_CMDS) +endef + +TOOL_Bs3Ow16_CXXOBJSUFF = $(TOOL_OPENWATCOM-16_CXXOBJSUFF) +TOOL_Bs3Ow16_CXXFLAGS = $(TOOL_OPENWATCOM-16_CXXFLAGS) +TOOL_Bs3Ow16_CXXFLAGS.debug = $(TOOL_OPENWATCOM-16_CXXFLAGS.debug) +TOOL_Bs3Ow16_CXXFLAGS.dbgopt = $(TOOL_OPENWATCOM-16_CXXFLAGS.dbgopt) +TOOL_Bs3Ow16_CXXFLAGS.profile = $(TOOL_OPENWATCOM-16_CXXFLAGS.profile) +TOOL_Bs3Ow16_CXXFLAGS.release = $(TOOL_OPENWATCOM-16_CXXFLAGS.release) +TOOL_Bs3Ow16_CXXINCS = $(TOOL_OPENWATCOM-16_CXXINCS) +TOOL_Bs3Ow16_CXXDEFS = +TOOL_Bs3Ow16_COMPILE_CXX_DEPEND = $(TOOL_OPENWATCOM-16_COMPILE_CXX_DEPEND) $(VBoxBs3ObjConverter_1_TARGET) +TOOL_Bs3Ow16_COMPILE_CXX_DEPORD = $(TOOL_OPENWATCOM-16_COMPILE_CXX_DEPORD) +TOOL_Bs3Ow16_COMPILE_CXX_OUTPUT = $(TOOL_OPENWATCOM-16_COMPILE_CXX_OUTPUT) +TOOL_Bs3Ow16_COMPILE_CXX_OUTPUT_MAYBE = $(TOOL_OPENWATCOM-16_COMPILE_CXX_OUTPUT_MAYBE) +define TOOL_Bs3Ow16_COMPILE_CXX_CMDS +$(TOOL_OPENWATCOM-16_COMPILE_CXX_CMDS) + $(QUIET)$(VBOX_BS3KIT_KSUBMIT_OBJ_CONV) $(VBoxBs3ObjConverter_1_TARGET) "$(obj)" +endef + +# Debug info format depends on what we use for 64-bit. +if 1 #1of ($(KBUILD_HOST), win) - wlink dwarf .sym files are useless for binary blobs + BS3_OW_DBG_OPT = -hc -d1+ + #BS3_OW_DBG_OPT = -hd -d1+ + BS3_OW_DBG_LDOPT = codeview +else + BS3_OW_DBG_OPT = -hd -d1+ + BS3_OW_DBG_LDOPT = dwarf +endif + +# +# Source handlers for .c16, .c32 and .c64 +# +define VBoxBs3KitImgSrcHandler_16bit_c +local type := C + $(kb-src-one 2) +endef + +C32TOOL = Bs3Ow32 +define VBoxBs3KitImgSrcHandler_32bit_c +local type := C32 + $(kb-src-one 2) +endef + +define VBoxBs3KitImgSrcHandler_64bit_c +local type := C64 + $(kb-src-one 2) +endef + + +# +# BS3Kit template for assembly and 16-bit code. +# +# Note! Using -d1 as -d1+ and -d2 causes suboptimal code to be generated (strlen +# reloading string pointer argument all the time). +# Update! -d1+ is required for line number information in code living in include +# files and any DWARF stuff at all. So, we'll ignore poor code quality. +# Note! Optimization options should come after debug stuff as -d2 for instance +# disables all optimziations. +# Note! We use BS3CLASS16CODE because of wdis code detection heuristics requires the class +# of a code segment to be exactly 'CODE', or ending with 'CODE' or 'TEXT' (more +# recent wdis have a -c=<clsnm> option, but not the one we currently use ). +# +# +# Compiler options explained: +# -nt=xxxx Sets the text segment name. +# -nc=xxxx Sets the text segment class name. +# -nd=xxxx Sets the data segment name. +# -ecc Sets the default calling convension to __cdecl +# Update: We don't use this in 16-bit code as it causes unfavorable reloading of DS before calling +# inlined functions (e.g. iprt/asm.h). Instead we use -ecw and __cdecl where needed. +# Update: With -zdp the DS reloading is gone. Code is slightly larger, but seems to cure stability +# issues in bs3CpuBasic2_RaiseXcpt1 (workers ending up with default calling convention). +# -ecw Sets the default calling convension to __watcall () +# -q Quiet, no logos or stuff. +# -0 Use 8086 instruction set (16-bit only). +# -3 Use 386 instruction set (16-bit only). +# -e<num> Stop after <num> errors. +# -wx Maxium warning level. +# -zl Don't emit default library information. +# -zdp DS pegged to BS3DATA16_GROUP/DGROUP. +# -zu Assume SS != DS. +# -mc Compact memory model, far data, small code. +# -ml Large memory model, far data, far code. +# -mf Flat memory model (32-bit). +# -d+ Enabled better /dVAR=XXX parsing, using space as delimiter instead of alpha-numerical/whatever. +# -d1 Debug info: Globals and line numbers. +# -s No stack overflow checks. +# -oa Relaxed aliasing constraints. +# -ob Branch prediction. +# -of Generate stack frames when needed. +# -oi Inline instrinsics functions. +# -ol Loop optimizations. +# -oh Expensive optimizations. (saves a byte or two) +# -or Reorder for best pipeline. +# -os Favor size over speed. +# +TEMPLATE_VBoxBS3KitImg = Template for building BS3Kit test images. +TEMPLATE_VBoxBS3KitImg_BLD_TRG = os-agnostic +TEMPLATE_VBoxBS3KitImg_BLD_TRG_ARCH = noarch +TEMPLATE_VBoxBS3KitImg_INST = $(INST_VALIDATIONKIT)bootsectors/ +TEMPLATE_VBoxBS3KitImg_BINSUFF = .img +TEMPLATE_VBoxBS3KitImg_MODE = 0644 +TEMPLATE_VBoxBS3KitImg_SRC_HANDLERS = \ + .c16:VBoxBs3KitImgSrcHandler_16bit_c \ + .c32:VBoxBs3KitImgSrcHandler_32bit_c \ + .c64:VBoxBs3KitImgSrcHandler_64bit_c +TEMPLATE_VBoxBS3KitImg_ASOBJSUFF = .o16 +TEMPLATE_VBoxBS3KitImg_ASTOOL = VBoxNasm +TEMPLATE_VBoxBS3KitImg_ASFLAGS = -f obj -g $(BS3KIT_NASM_allow_64_bit) -w+orphan-labels +TEMPLATE_VBoxBS3KitImg_ASDEFS = ASM_FORMAT_OMF RT_NOINC_SEGMENTS __NASM__ ARCH_BITS=16 RT_ARCH_X86 ASM_MODEL_FAR_CODE \ + BS3CLASS16CODE=$(BS3KIT_CLASS_CODE16) BS3KIT_CLASS_DATA16=$(BS3KIT_CLASS_DATA16) \ + BS3KIT_GRPNM_DATA16=$(BS3KIT_GRPNM_DATA16) BS3KIT_CLASS_BSS16=$(BS3KIT_CLASS_BSS16) +TEMPLATE_VBoxBS3KitImg_DEFS = IN_BS3KIT +TEMPLATE_VBoxBS3KitImg_DEFS.debug = BS3_STRICT + +TEMPLATE_VBoxBS3KitImg_ARTOOL = OPENWATCOM-16 + +TEMPLATE_VBoxBS3KitImg_CTOOL = Bs3Ow16 +TEMPLATE_VBoxBS3KitImg_CXXTOOL = Bs3Ow16 +TEMPLATE_VBoxBS3KitImg_CFLAGS = $(if $(BS3KIT_SEGNM_DATA16),-nd=$(BS3KIT_SEGNM_DATA16),) \ + -nt=BS3TEXT16 -nc=$(BS3KIT_CLASS_CODE16) -ecc -q -0 -e125 -wx -zl -zdp -zu -ml $(BS3_OW_DBG_OPT) -s -oa -ob -of -oi -ol -or -os -oh -d+ +TEMPLATE_VBoxBS3KitImg_CXXFLAGS = $(if $(BS3KIT_SEGNM_DATA16),-nd=$(BS3KIT_SEGNM_DATA16),) \ + -nt=BS3TEXT16 -nc=$(BS3KIT_CLASS_CODE16) -ecc -q -0 -e125 -wx -zl -zdp -zu -ml $(BS3_OW_DBG_OPT) -s -oa -ob -of -oi -ol -or -os -oh -d+ +TEMPLATE_VBoxBS3KitImg_CDEFS = ARCH_BITS=16 RT_ARCH_X86 + +TEMPLATE_VBoxBS3KitImg_TOOL = $(NO_SUCH_VARIABLE) +TEMPLATE_VBoxBS3KitImg_C16TOOL = $(TEMPLATE_VBoxBS3KitImg_CTOOL) +TEMPLATE_VBoxBS3KitImg_C16FLAGS = $(TEMPLATE_VBoxBS3KitImg_CFLAGS) +TEMPLATE_VBoxBS3KitImg_C16DEFS = $(TEMPLATE_VBoxBS3KitImg_CDEFS) +TEMPLATE_VBoxBS3KitImg_C32TOOL := Bs3Ow32 +TEMPLATE_VBoxBS3KitImg_C32FLAGS = $(TEMPLATE_VBoxBS3KitImg32_CFLAGS) +TEMPLATE_VBoxBS3KitImg_C32DEFS = ARCH_BITS=32 RT_ARCH_X86 +TEMPLATE_VBoxBS3KitImg_C64TOOL = $(TEMPLATE_VBoxBS3KitImg64_CTOOL) +TEMPLATE_VBoxBS3KitImg_C64FLAGS = $(TEMPLATE_VBoxBS3KitImg64_CFLAGS) +TEMPLATE_VBoxBS3KitImg_C64DEFS = ARCH_BITS=64 RT_ARCH_AMD64 + +TEMPLATE_VBoxBS3KitImg_INCS = $(VBOX_PATH_BS3KIT_SRC) . +TEMPLATE_VBoxBS3KitImg_LDTOOL = OPENWATCOM-WL + +# linker options: +# system dos: Link a 16-bit DOS binary. +# output raw ...: Produce a raw DOS binary for loading at flat address 10000h. +# The following is for ordering segments. +# option start=_start: The start symbol in bs3-first-xxx.asm. +# debug codeview/dwarf all: Full debug information either in codeview or dwarf. +# option symfile: Produce a separate symbol file with the debug info. +# option map: Produce a map file. +# option farcalls: Change intrasegment far calls into 'push cs; seg ds; call symbol' where possible. +# option statics: ? +# option verbose: Verbose map file? +# option disable 1014: Disable warning about 'stack segment not found'. +# option disable 1080: Disable warning about '%1 is a 32-bit object file'. +# +# Note! We're pushing DATA16 to 0x20000 because it's impossible to force wlink +# to give us a real-mode + GDT compatible alignment (0ffffff80h), i.e. +# real-mode address on the form 0fff8:0000. +TEMPLATE_VBoxBS3KitImg_LDFLAGS = system dos \ + debug $(BS3_OW_DBG_LDOPT) all \ + option quiet, map, statics, verbose, symfile, start=_start, farcalls \ + disable 1014, 1080 \ + \ + output raw offset=0x10000 \ + order \ + clname BS3FLAT segaddr=0x0000 \ + segment BS3FLAT segaddr=0x0000 \ + clname $(BS3KIT_CLASS_CODE16) segaddr=0x1000 \ + segment BS3TEXT16 \ + segment BS3TEXT16_NEARSTUBS \ + segment BS3TEXT16_FARSTUBS \ + segment BS3TEXT16_END \ + clname BS3SYSTEM16 segaddr=0x2000 \ + segment BS3SYSTEM16 \ +$(if-expr "$(BS3KIT_SEGNM_DATA16)" == "", \ + clname DATA \ + segment BS3DATA16 segaddr=0x2900 \ + segment BS3DATA16_DATA \ + segment DATA \ + segment _DATA \ + segment BS3DATA16CONST \ + segment CONST \ + segment BS3DATA16CONST2 \ + segment CONST2 \ + segment STRINGS \ + segment BS3DATA16_END \ + clname BSS \ + segment BSS \ + segment _BSS \ + segment BS3DATA16_END \ + clname FAR_DATA \ + segment FAR_DATA \ +, \ + clname FAR_DATA \ + segment BS3DATA16 segaddr=0x2900 \ + segment FAR_DATA \ + segment BS3DATA16CONST \ + segment BS3DATA16CONST2 \ + segment BS3DATA16_DATA \ + segment BS3DATA16_END \ +) \ + segment BS3DATA32 \ + segment BS3DATA32CONST \ + segment BS3DATA32CONST2 \ + segment BS3DATA32_DATA \ + segment BS3DATA32_BSS \ + segment BS3DATA32_END \ + \ + segment BS3DATA64 \ + segment BS3DATA64CONST \ + segment BS3DATA64_BSS \ + segment BS3DATA64_END \ + clname BS3CLASS16RMCODE \ + segment BS3RMCODE16_START \ + segment BS3RMCODE16 \ + segment BS3RMCODE16_END \ + clname BS3CLASS16X0CODE \ + segment BS3X0CODE16_START \ + segment BS3X0CODE16 \ + segment BS3X0CODE16_END \ + clname BS3CLASS16X1CODE \ + segment BS3X1CODE16_START \ + segment BS3X1CODE16 \ + segment BS3X1CODE16_END \ + clname BS3CLASS32CODE \ + segment BS3TEXT32_START \ + segment BS3TEXT32 \ + segment BS3TEXT32_END \ + clname BS3CLASSSEPARATE32AND64BITCODE \ + segment BS3SEPARATE32AND64BITCODE \ + segment BS3SEPARATE32AND64BITCODE_END \ + clname BS3CLASS64CODE \ + segment BS3TEXT64_START \ + segment BS3TEXT64 \ + segment BS3TEXT64_END + +TEMPLATE_VBoxBS3KitImg_LNK_DEPS = \ + $(bs3-bootsector_1_TARGET) \ + $(VBoxBs3Linker_1_TARGET) +TEMPLATE_VBoxBS3KitImg_POST_CMDS = $(if $(eq $(tool_do),LINK_LIBRARY)\ + ,,$(QUIET)$(MV_EXT) -f -- "$(out)" "$(out).tmp" \ + $$(NLTAB)$(QUIET)$(VBoxBs3Linker_1_TARGET) -o $(out) $(bs3-bootsector_1_TARGET) $(out).tmp \ + $$(NLTAB)$(QUIET)$(RM_EXT) -f -- "$(out).tmp") \ + $(eval .PRECIOUS: $(outbase).map) # ugly hack! + + +TEMPLATE_VBoxBS3KitImg_LIBS = \ + $(PATH_OBJ)/bs3kit-common-16/bs3kit-common-16.lib \ + $(PATH_OBJ)/bs3kit-common-32/bs3kit-common-32.lib \ + $(PATH_OBJ)/bs3kit-common-64/bs3kit-common-64.lib \ + \ + $(PATH_OBJ)/bs3kit-rm/bs3kit-rm.lib \ + $(PATH_OBJ)/bs3kit-pe16/bs3kit-pe16.lib \ + $(PATH_OBJ)/bs3kit-pe16_32/bs3kit-pe16_32.lib \ + $(PATH_OBJ)/bs3kit-pe16_v86/bs3kit-pe16_v86.lib \ + $(PATH_OBJ)/bs3kit-pe32/bs3kit-pe32.lib \ + $(PATH_OBJ)/bs3kit-pe32_16/bs3kit-pe32_16.lib \ + $(PATH_OBJ)/bs3kit-pev86/bs3kit-pev86.lib \ + $(PATH_OBJ)/bs3kit-pp16/bs3kit-pp16.lib \ + $(PATH_OBJ)/bs3kit-pp16_32/bs3kit-pp16_32.lib \ + $(PATH_OBJ)/bs3kit-pp16_v86/bs3kit-pp16_v86.lib \ + $(PATH_OBJ)/bs3kit-pp32/bs3kit-pp32.lib \ + $(PATH_OBJ)/bs3kit-pp32_16/bs3kit-pp32_16.lib \ + $(PATH_OBJ)/bs3kit-ppv86/bs3kit-ppv86.lib \ + $(PATH_OBJ)/bs3kit-pae16/bs3kit-pae16.lib \ + $(PATH_OBJ)/bs3kit-pae16_32/bs3kit-pae16_32.lib \ + $(PATH_OBJ)/bs3kit-pae16_v86/bs3kit-pae16_v86.lib \ + $(PATH_OBJ)/bs3kit-pae32/bs3kit-pae32.lib \ + $(PATH_OBJ)/bs3kit-pae32_16/bs3kit-pae32_16.lib \ + $(PATH_OBJ)/bs3kit-paev86/bs3kit-paev86.lib \ + $(PATH_OBJ)/bs3kit-lm16/bs3kit-lm16.lib \ + $(PATH_OBJ)/bs3kit-lm32/bs3kit-lm32.lib \ + $(PATH_OBJ)/bs3kit-lm64/bs3kit-lm64.lib + +# BS3Kit template for 32-bit code. +TEMPLATE_VBoxBS3KitImg32 = Template for building BS3Kit test images. +TEMPLATE_VBoxBS3KitImg32_BLD_TRG = os-agnostic +TEMPLATE_VBoxBS3KitImg32_BLD_TRG_ARCH = x86 +TEMPLATE_VBoxBS3KitImg32_INSTTYPE = none +TEMPLATE_VBoxBS3KitImg32_ASTOOL = VBoxNasm +TEMPLATE_VBoxBS3KitImg32_ASOBJSUFF = .o32 +TEMPLATE_VBoxBS3KitImg32_ASFLAGS = -f obj -g $(BS3KIT_NASM_allow_64_bit) -w+orphan-labels +TEMPLATE_VBoxBS3KitImg32_ASDEFS = ASM_FORMAT_OMF RT_NOINC_SEGMENTS __NASM__ \ + BS3CLASS16CODE=$(BS3KIT_CLASS_CODE16) BS3KIT_CLASS_DATA16=$(BS3KIT_CLASS_DATA16) \ + BS3KIT_GRPNM_DATA16=$(BS3KIT_GRPNM_DATA16) BS3KIT_CLASS_BSS16=$(BS3KIT_CLASS_BSS16) +TEMPLATE_VBoxBS3KitImg32_DEFS = ARCH_BITS=32 IN_BS3KIT +TEMPLATE_VBoxBS3KitImg32_DEFS.debug = BS3_STRICT +TEMPLATE_VBoxBS3KitImg32_ARTOOL = OPENWATCOM +TEMPLATE_VBoxBS3KitImg32_CTOOL = Bs3Ow32 +TEMPLATE_VBoxBS3KitImg32_CXXTOOL = Bs3Ow32 +TEMPLATE_VBoxBS3KitImg32_CFLAGS = \ + -nt=BS3TEXT32 -nd=BS3DATA32 -nc=BS3CLASS32CODE -ecc -q -e125 -wx -zl -mf $(BS3_OW_DBG_OPT) -s -oa -ob -of -oi -ol -or -os -d+ +TEMPLATE_VBoxBS3KitImg32_CXXFLAGS = \ + -nt=BS3TEXT32 -nd=BS3DATA32 -nc=BS3CLASS32CODE -ecc -q -e125 -wx -zl -mf $(BS3_OW_DBG_OPT) -s -oa -ob -of -oi -ol -or -os -d+ +TEMPLATE_VBoxBS3KitImg32_INCS = $(VBOX_PATH_BS3KIT_SRC) . +TEMPLATE_VBoxBS3KitImg32_LDTOOL = VBoxBsUnusedLd + +# BS3Kit template for 64-bit code. +TEMPLATE_VBoxBS3KitImg64 = Template for building BS3Kit test images. +TEMPLATE_VBoxBS3KitImg64_BLD_TRG = os-agnostic +TEMPLATE_VBoxBS3KitImg64_BLD_TRG_ARCH = amd64 +TEMPLATE_VBoxBS3KitImg64_INSTTYPE = none +TEMPLATE_VBoxBS3KitImg64_ASTOOL = VBoxNasm +TEMPLATE_VBoxBS3KitImg64_ASOBJSUFF = .o64 +TEMPLATE_VBoxBS3KitImg64_ASFLAGS = -f obj -g $(BS3KIT_NASM_allow_64_bit) -w+orphan-labels +TEMPLATE_VBoxBS3KitImg64_ASDEFS = ASM_FORMAT_OMF ASM_CALL64_MSC RT_NOINC_SEGMENTS __NASM__ \ + BS3CLASS16CODE=$(BS3KIT_CLASS_CODE16) BS3KIT_CLASS_DATA16=$(BS3KIT_CLASS_DATA16) \ + BS3KIT_GRPNM_DATA16=$(BS3KIT_GRPNM_DATA16) BS3KIT_CLASS_BSS16=$(BS3KIT_CLASS_BSS16) +TEMPLATE_VBoxBS3KitImg64_DEFS = IN_BS3KIT ARCH_BITS=64 +TEMPLATE_VBoxBS3KitImg64_DEFS.debug = BS3_STRICT +TEMPLATE_VBoxBS3KitImg64_ARTOOL = OPENWATCOM +TEMPLATE_VBoxBS3KitImg64_INCS = $(VBOX_PATH_BS3KIT_SRC) . +if1of ($(KBUILD_HOST), win) + ifndef TOOL_VCC100AMD64 # For win.x86 builds. + include $(KBUILD_PATH)/tools/$(VBOX_VCC_TOOL_STEM)AMD64.kmk + endif + TEMPLATE_VBoxBS3KitImg64_CTOOL := Bs3Vcc64 + TEMPLATE_VBoxBS3KitImg64_CXXTOOL := Bs3Vcc64 + TEMPLATE_VBoxBS3KitImg64_CFLAGS = -Z7 -O1 -Oi -GF -GS- -Gy- -Gs65536 + TEMPLATE_VBoxBS3KitImg64_CXXFLAGS = -Z7 -O1 -Oi -GF -GS- -Gy- -Gs65536 +else + TEMPLATE_VBoxBS3KitImg64_CTOOL := Bs3Gcc64Elf64 + TEMPLATE_VBoxBS3KitImg64_CXXTOOL := Bs3Gcc64Elf64 + # Note! -mx32 would be exactly what we needed here, however it causes internal compiler errors with 4.8.4 on gentoo. + TEMPLATE_VBoxBS3KitImg64_CFLAGS = -m64 -maccumulate-outgoing-args -g -Os -fno-omit-frame-pointer $(VBOX_GCC_fno-stack-protector) $(VBOX_GCC_WARN_PEDANTIC_C) \ + -msoft-float -fno-exceptions -mno-sse -mno-mmx -mno-sse2 -mno-3dnow $(VBOX_GCC_fno-stack-protector) + TEMPLATE_VBoxBS3KitImg64_CXXFLAGS = -m64 -maccumulate-outgoing-args -g -Os -fno-omit-frame-pointer $(VBOX_GCC_fno-stack-protector) $(VBOX_GCC_WARN_PEDANTIC_CXX) \ + -msoft-float -fno-exceptions -mno-sse -mno-mmx -mno-sse2 -mno-3dnow $(VBOX_GCC_fno-stack-protector) +endif +TEMPLATE_VBoxBS3KitImg64_LDTOOL = VBoxBsUnusedLd + +# BS3Kit template for the bootsector. +TEMPLATE_VBoxBS3KitBS = Template for building BS3Kit test images. +TEMPLATE_VBoxBS3KitBS_BLD_TRG = os-agnostic +TEMPLATE_VBoxBS3KitBS_BLD_TRG_ARCH = x86 +TEMPLATE_VBoxBS3KitBS_INST = $(INST_VALIDATIONKIT)bootsectors/ +TEMPLATE_VBoxBS3KitBS_INSTTYPE = none +TEMPLATE_VBoxBS3KitBS_BINSUFF = .img +TEMPLATE_VBoxBS3KitBS_MODE = 0644 +TEMPLATE_VBoxBS3KitBS_ASTOOL = YASM +TEMPLATE_VBoxBS3KitBS_ASFLAGS = -f bin --mapfile +TEMPLATE_VBoxBS3KitBS_ASDEFS = ASM_FORMAT_BIN RT_NOINC_SEGMENTS ARCH_BITS=16 __YASM__ \ + BS3CLASS16CODE=$(BS3KIT_CLASS_CODE16) BS3KIT_CLASS_DATA16=$(BS3KIT_CLASS_DATA16) \ + BS3KIT_GRPNM_DATA16=$(BS3KIT_GRPNM_DATA16) BS3KIT_CLASS_BSS16=$(BS3KIT_CLASS_BSS16) +TEMPLATE_VBoxBS3KitBS_INCS = $(VBOX_PATH_BS3KIT_SRC) . +TEMPLATE_VBoxBS3KitBS_LDTOOL = VBoxBsCpLd + + + +# +# Extends VBoxBS3KitImg +# User must starts SOURCES with: $(VBOX_PATH_BS3KIT_SRC)/bs3-first-dosexe.asm +## disable 1014, 1080, 1150 +# +TEMPLATE_VBoxBS3KitUtil = Utility using bs3kit code. +TEMPLATE_VBoxBS3KitUtil_EXTENDS = VBoxBS3KitImg +TEMPLATE_VBoxBS3KitUtil_BINSUFF = .exe +TEMPLATE_VBoxBS3KitUtil_DEFS = $(TEMPLATE_VBoxBS3KitImg_DEFS) BS3_IS_DOS_EXE +TEMPLATE_VBoxBS3KitUtil_CFLAGS = $(filter-out -zl,$(TEMPLATE_VBoxBS3KitImg_CFLAGS)) +TEMPLATE_VBoxBS3KitUtil_CXXFLAGS = $(filter-out -zl,$(TEMPLATE_VBoxBS3KitImg_CXXFLAGS)) +TEMPLATE_VBoxBS3KitUtil_LDFLAGS = system dos \ + debug $(BS3_OW_DBG_LDOPT) all \ + option quiet, map, statics, verbose, symfile \ + disable 1080 \ + order \ + clname $(BS3KIT_CLASS_CODE16) \ + segment BEGTEXT \ + segment BS3TEXT16 \ + segment _TEXT \ + segment BS3TEXT16_NEARSTUBS \ + segment BS3TEXT16_FARSTUBS \ + segment BS3TEXT16_END \ + clname BS3SYSTEM16 \ + segment BS3SYSTEM16 \ + \ + clname BEGDATA \ + segment _NULL \ + segment _AFTERNULL \ + clname DATA \ +$(if-expr "$(BS3KIT_SEGNM_DATA16)" == "", \ + segment BS3DATA16 \ + segment BS3DATA16CONST \ + segment CONST \ + segment BS3DATA16CONST2 \ + segment CONST2 \ +,\ + segment CONST \ + segment CONST2 \ +) \ + segment _DATA \ + segment XIB \ + segment XI \ + segment XIE \ + segment YIB \ + segment YI \ + segment YIE \ + segment STRINGS \ +$(if-expr "$(BS3KIT_SEGNM_DATA16)" == "", \ + segment BS3DATA16_DATA \ +,) \ + segment DATA \ + clname BSS \ + segment _BSS \ + segment BSS \ + segment BS3DATA16_END \ + clname STACK \ + segment STACK \ + \ + clname FAR_DATA \ +$(if-expr "$(BS3KIT_SEGNM_DATA16)" != "", \ + segment BS3DATA16 \ + segment BS3DATA16_DATA \ + segment BS3DATA16CONST \ + segment BS3DATA16CONST2 \ + segment FAR_DATA \ + segment BS3DATA16_END \ +,\ + segment FAR_DATA \ +)\ + segment BS3DATA32 \ + segment BS3DATA32CONST \ + segment BS3DATA32CONST2 \ + segment BS3DATA32_DATA \ + segment BS3DATA32_BSS \ + segment BS3DATA32_END \ + \ + segment BS3DATA64 \ + segment BS3DATA64CONST \ + segment BS3DATA64_BSS \ + segment BS3DATA64_END \ + clname BS3CLASS16RMCODE \ + segment BS3RMCODE16_START \ + segment BS3RMCODE16 \ + segment BS3RMCODE16_END \ + clname BS3CLASS16X0CODE \ + segment BS3X0CODE16_START \ + segment BS3X0CODE16 \ + segment BS3X0CODE16_END \ + clname BS3CLASS16X1CODE \ + segment BS3X1CODE16_START \ + segment BS3X1CODE16 \ + segment BS3X1CODE16_END \ + clname BS3CLASS32CODE \ + segment BS3TEXT32 \ + segment BS3TEXT32_END \ + clname BS3CLASSSEPARATE32AND64BITCODE \ + segment BS3SEPARATE32AND64BITCODE \ + segment BS3SEPARATE32AND64BITCODE_END \ + clname BS3CLASS64CODE \ + segment BS3TEXT64 \ + segment BS3TEXT64_END +# clname BS3FLAT segaddr=0x0000 \ +# segment BS3FLAT segaddr=0x0000 + +TEMPLATE_VBoxBS3KitUtil_LNK_DEPS = $(NO_SUCH_VARIABLE) +TEMPLATE_VBoxBS3KitUtil_POST_CMDS = $(NO_SUCH_VARIABLE) + diff --git a/src/VBox/ValidationKit/bootsectors/Makefile.kmk b/src/VBox/ValidationKit/bootsectors/Makefile.kmk new file mode 100644 index 00000000..126df93e --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/Makefile.kmk @@ -0,0 +1,364 @@ +# $Id: Makefile.kmk $ +## @file +# VirtualBox Validation Kit - Bootsector Tests for Test Drivers or standalone testing. +# + +# +# Copyright (C) 2006-2019 Oracle Corporation +# +# This file is part of VirtualBox Open Source Edition (OSE), as +# available from http://www.virtualbox.org. This file is free software; +# you can redistribute it and/or modify it under the terms of the GNU +# General Public License (GPL) as published by the Free Software +# Foundation, in version 2 as it comes in the "COPYING" file of the +# VirtualBox OSE distribution. VirtualBox OSE is distributed in the +# hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +# +# The contents of this file may alternatively be used under the terms +# of the Common Development and Distribution License Version 1.0 +# (CDDL) only, as it comes in the "COPYING.CDDL" file of the +# VirtualBox OSE distribution, in which case the provisions of the +# CDDL are applicable instead of those of the GPL. +# +# You may elect to license modified versions of this file under the +# terms and conditions of either the GPL or the CDDL or both. +# + +SUB_DEPTH = ../../../.. +include $(KBUILD_PATH)/subheader.kmk + + +# +# Make sure our Config.kmk gets included when kmk is running from a parent directory. +# +ifndef VBOX_BOOTSECTORS_CONFIG_KMK_INCLUDED + include $(PATH_SUB_CURRENT)/Config.kmk +endif + + +# +# Include sub-makefile. +# +# The VBOX_WITH_BS3KIT feature requires NASM 2.12 and either MSVC or gcc +# with ms_abi function attribute (gcc v4.4+, MSVC default). +# Some 32-bit gcc compilers come without 64-bit support (e.g. EL5). +# +if defined(VBOX_WITH_OPEN_WATCOM) + if1of ($(KBUILD_TARGET), win) + VBOX_WITH_BS3KIT = 1 + else if $(VBOX_GCC_VERSION_CC) >= 40400 # ms_abi was added in 4.4 + if1of ($(KBUILD_TARGET), linux) + ifneq ($(VBOX_GCC_m64),) + VBOX_WITH_BS3KIT = 1 + endif + endif + endif + ifdef VBOX_WITH_BS3KIT + include $(PATH_SUB_CURRENT)/bs3kit/Makefile.kmk + endif +endif + + +# +# Boot Sector "Linker" tool. +# +TOOL_VBoxBootSectorLd = Joins one or more BS2 object files into a floppy img. +TOOL_VBoxBootSectorLd_LINK_MISCBIN_OUTPUT = +TOOL_VBoxBootSectorLd_LINK_MISCBIN_DEPEND = +TOOL_VBoxBootSectorLd_LINK_MISCBIN_DEPORD = $(VBoxBs2Linker_1_TARGET) +define TOOL_VBoxBootSectorLd_LINK_MISCBIN_CMDS + $(VBoxBs2Linker_1_TARGET) -o $(out) $(objs) $(othersrc) +endef + +BLDPROGS += VBoxBs2Linker +VBoxBs2Linker_TEMPLATE = VBoxBldProg +VBoxBs2Linker_SOURCES = VBoxBs2Linker.cpp + + +# +# Makes a boot sector test image. +# +TEMPLATE_VBoxBsTestImg = kBuild tool config for building boot sector stuff. +TEMPLATE_VBoxBsTestImg_INST = $(INST_VALIDATIONKIT)bootsectors/ +TEMPLATE_VBoxBsTestImg_BINSUFF = .img +TEMPLATE_VBoxBsTestImg_MODE = 0644 +TEMPLATE_VBoxBsTestImg_ASTOOL = YASM +TEMPLATE_VBoxBsTestImg_ASFLAGS = -f bin -P $(VBOX_PATH_BOOTSECTORS_SRC)/bootsector2-first.mac $(VBOX_YASM_Wno-segreg-in-64bit) --mapfile +TEMPLATE_VBoxBsTestImg_ASDEFS = ASM_FORMAT_BIN +TEMPLATE_VBoxBsTestImg_INCS = \ + . \ + ../../VMM/testcase/Instructions +TEMPLATE_VBoxBsTestImg_LDTOOL = VBoxBootSectorLd + + +# +# The boot sector tests. +# +MISCBINS += bootsector-shutdown +bootsector-shutdown_TEMPLATE = VBoxBsTestImg +bootsector-shutdown_SOURCES = bootsector-shutdown.asm + +MISCBINS += bootsector-pae +bootsector-pae_TEMPLATE = VBoxBsTestImg +bootsector-pae_SOURCES = bootsector-pae.asm + +MISCBINS += bootsector-empty +bootsector-empty_TEMPLATE = VBoxBsTestImg +bootsector-empty_SOURCES = bootsector-empty.asm + +MISCBINS += bootsector2-test1 +bootsector2-test1_TEMPLATE = VBoxBsTestImg +bootsector2-test1_SOURCES = bootsector2-test1.asm + +MISCBINS += bootsector2-cpu-hidden-regs-1 +bootsector2-cpu-hidden-regs-1_TEMPLATE = VBoxBsTestImg +bootsector2-cpu-hidden-regs-1_SOURCES = bootsector2-cpu-hidden-regs-1.asm + +MISCBINS += bootsector2-cpu-instr-1 +bootsector2-cpu-instr-1_TEMPLATE = VBoxBsTestImg +bootsector2-cpu-instr-1_SOURCES = bootsector2-cpu-instr-1.asm + +MISCBINS += bootsector2-cpu-pf-1 +bootsector2-cpu-pf-1_TEMPLATE = VBoxBsTestImg +bootsector2-cpu-pf-1_SOURCES = bootsector2-cpu-pf-1.asm + +MISCBINS += bootsector2-cpu-xcpt-1 +bootsector2-cpu-xcpt-1_TEMPLATE = VBoxBsTestImg +bootsector2-cpu-xcpt-1_SOURCES = bootsector2-cpu-xcpt-1.asm + +MISCBINS += bootsector2-cpu-xcpt-2 +bootsector2-cpu-xcpt-2_TEMPLATE = VBoxBsTestImg +bootsector2-cpu-xcpt-2_SOURCES = bootsector2-cpu-xcpt-2.asm + +MISCBINS += bootsector2-cpu-a20-1 +bootsector2-cpu-a20-1_TEMPLATE = VBoxBsTestImg +bootsector2-cpu-a20-1_SOURCES = bootsector2-cpu-a20-1.asm + +MISCBINS += bootsector2-cpu-basic-1 +bootsector2-cpu-basic-1_TEMPLATE = VBoxBsTestImg +bootsector2-cpu-basic-1_SOURCES = bootsector2-cpu-basic-1.asm + +MISCBINS += bootsector2-cpu-ac-loop +bootsector2-cpu-ac-loop_TEMPLATE = VBoxBsTestImg +bootsector2-cpu-ac-loop_SOURCES = bootsector2-cpu-ac-loop.asm + +MISCBINS += bootsector2-cpu-db-loop +bootsector2-cpu-db-loop_TEMPLATE = VBoxBsTestImg +bootsector2-cpu-db-loop_SOURCES = bootsector2-cpu-db-loop.asm + +MISCBINS += bootsector2-boot-registers-1 +bootsector2-boot-registers-1_TEMPLATE = VBoxBsTestImg +bootsector2-boot-registers-1_SOURCES = bootsector2-boot-registers-1.asm + +MISCBINS += bootsector2-triple-fault-1 +bootsector2-triple-fault-1_TEMPLATE = VBoxBsTestImg +bootsector2-triple-fault-1_SOURCES = bootsector2-triple-fault-1.asm + + +ifeq ($(USERNAME),birdxx) + if1of ($(KBUILD_HOST).$(KBUILD_HOST_ARCH),win.amd64) +# +# Generated instruction tests (work in progress). +# + +VBOX_PATH_VBINSTST = $(PATH_ROOT)/src/VBox/VMM/testcase/Instructions +VBOX_VBINSTST_GEN = $(VBOX_PATH_VBINSTST)/InstructionTestGen.py +VBOX_BOOTSECTOR2_VBINSTST_AMD64_GEN = $(VBOX_BLD_PYTHON) $(VBOX_VBINSTST_GEN) \ + --split 3 --target bs2-r0-64 --output-base $(bootsectors_0_OUTDIR)/VBInsTst-64 --test-size tiny +VBOX_BOOTSECTOR2_VBINSTST_AMD64_FILES = $(shell $(VBOX_BOOTSECTOR2_VBINSTST_AMD64_GEN) --makefile-mode) + +#$$(bootsectors_0_OUTDIR)/VBInsTst.ts + $$(VBOX_BOOTSECTOR2_VBINSTST_AMD64_FILES): $(VBOX_VBINSTST_GEN) | $$(dir $$@) +# $(VBOX_BOOTSECTOR2_VBINSTST_AMD64_GEN) +# $(APPEND) -t $@ +# +#bootsectors_SOURCES += $(bootsectors_0_OUTDIR)/bootsector2-vbinstst-1.img +#bootsectors_CLEAN += $(VBOX_BOOTSECTOR2_VBINSTST_AMD64_FILES) +# +#$$(bootsectors_0_OUTDIR)/bootsector2-vbinstst-1.img: \ +# $(PATH_SUB_CURRENT)/bootsector2-vbinstst-64-1.asm \ +# $$(bootsectors_0_OUTDIR)/VBInsTst-64.asm +# $(TOOL_$(VBOX_ASTOOL)_AS) -f bin -D ASM_FORMAT_BIN -I $(dir $@) -I $(PATH_ROOT)/include -I $(VBOX_PATH_VBINSTST) -o $@ -L nasm -l $@.lst $< + +MISCBINS += bootsector2-vbinstst-kernel +bootsector2-vbinstst-kernel_TEMPLATE = VBoxBsTestImg +bootsector2-vbinstst-kernel_SOURCES = \ + bootsector2-vbinstst-kernel.asm + + +MISCBINS += bootsector2-vbinstst-64-1 +bootsector2-vbinstst-64-1_TEMPLATE = VBoxBsTestImg +bootsector2-vbinstst-64-1_DEFS = \ + BS2_BIG_IMAGE_LM64 \ + BS2_BIG_IMAGE_GEN_SOURCE_FILE=bs2-vbinstst-64-1.asm \ + BS2_BIG_IMAGE_GEN_TEST_NAME=\"bs2-vbinstst-64-1\" +bootsector2-vbinstst-64-1_INCS = $(bootsector2-vbinstst-64-1_0_OUTDIR)/ +bootsector2-vbinstst-64-1_SOURCES = \ + bootsector2-vbinstst-kernel.asm \ + bootsector2-vbinstst-big-template.asm +bootsector2-vbinstst-64-1_INTERMEDIATES = \ + $(bootsector2-vbinstst-64-1_0_OUTDIR)/bs2-vbinstst-64-1.asm +bootsector2-vbinstst-64-1_CLEAN = \ + $(bootsector2-vbinstst-64-1_0_OUTDIR)/bs2-vbinstst-64-1.asm + +$$(bootsector2-vbinstst-64-1_0_OUTDIR)/bs2-vbinstst-64-1.asm: $(VBOX_VBINSTST_GEN) | $$(dir $$@) + $(REDIRECT) -0 /dev/null -- $(VBOX_BLD_PYTHON) $(VBOX_VBINSTST_GEN) --target bs2-r0-64-big --output-base $(basename $@) --test-size medium + +MISCBINS += bootsector2-vbinstst-32-1 +bootsector2-vbinstst-32-1_TEMPLATE = VBoxBsTestImg +bootsector2-vbinstst-32-1_DEFS = \ + BS2_BIG_IMAGE_PP32 \ + BS2_BIG_IMAGE_GEN_SOURCE_FILE=bs2-vbinstst-32-1.asm \ + BS2_BIG_IMAGE_GEN_TEST_NAME=\"bs2-vbinstst-32-1\" +bootsector2-vbinstst-32-1_INCS = $(bootsector2-vbinstst-32-1_0_OUTDIR)/ +bootsector2-vbinstst-32-1_SOURCES = \ + bootsector2-vbinstst-kernel.asm \ + bootsector2-vbinstst-big-template.asm +bootsector2-vbinstst-32-1_INTERMEDIATES = \ + $(bootsector2-vbinstst-32-1_0_OUTDIR)/bs2-vbinstst-32-1.asm +bootsector2-vbinstst-32-1_CLEAN = \ + $(bootsector2-vbinstst-32-1_0_OUTDIR)/bs2-vbinstst-32-1.asm + +$$(bootsector2-vbinstst-32-1_0_OUTDIR)/bs2-vbinstst-32-1.asm: $(VBOX_VBINSTST_GEN) | $$(dir $$@) + $(REDIRECT) -0 /dev/null -- $(VBOX_BLD_PYTHON) $(VBOX_VBINSTST_GEN) --target bs2-r0-32-big --output-base $(basename $@) --test-size medium + + endif +endif # bird-only + + +ifdef VBOX_WITH_BS3KIT +# +# Bs3kit +# + +# CPU basics #2 (first being bootsector2-cpu-basic-1). +MISCBINS += bs3-cpu-basic-2 +bs3-cpu-basic-2_TEMPLATE = VBoxBS3KitImg +bs3-cpu-basic-2_INCS = . +bs3-cpu-basic-2_DEFS = BS3_CMN_INSTANTIATE_FILE1=bs3-cpu-basic-2-template.c +bs3-cpu-basic-2_DEFS += BS3_MODE_INSTANTIATE_FILE1=bs3-cpu-basic-2-template.c + ifeq ($(KBUILD_HOST),win) +bs3-cpu-basic-2_DEFS += HAVE_OMF_CONVERTER + endif +bs3-cpu-basic-2_SOURCES = \ + bs3kit/bs3-first-rm.asm \ + bs3-cpu-basic-2.c \ + bs3-cpu-basic-2-x0.c \ + bs3-cpu-basic-2-32.c32 \ + bs3-cpu-basic-2-pf.c32 \ + bs3-cpu-basic-2-asm.asm \ + bs3kit/bs3-cmn-instantiate-x0.c16 \ + bs3kit/bs3-cmn-instantiate.c32 \ + bs3kit/bs3-cmn-instantiate.c64 +bs3-cpu-basic-2-template.o:: \ + $$(bs3-cpu-basic-2_0_OUTDIR)/bs3kit/bs3-cmn-instantiate-x0.o16 \ + $$(bs3-cpu-basic-2_0_OUTDIR)/bs3kit/bs3-cmn-instantiate.o32 \ + $$(bs3-cpu-basic-2_0_OUTDIR)/bs3kit/bs3-cmn-instantiate.o64 \ + $$(bs3-cpu-basic-2_0_OUTDIR)/bs3-cpu-basic-2-asm.o16 + +# CPU weird stuff #1. +MISCBINS += bs3-cpu-weird-1 +bs3-cpu-weird-1_TEMPLATE = VBoxBS3KitImg +bs3-cpu-weird-1_INCS = . +bs3-cpu-weird-1_SOURCES = \ + bs3kit/bs3-first-rm.asm \ + bs3-cpu-weird-1.c \ + bs3-cpu-weird-1-x0.c \ + bs3-cpu-weird-1-asm.asm + +# FPU state corruption checker. +MISCBINS += bs3-fpustate-1 +bs3-fpustate-1_TEMPLATE = VBoxBS3KitImg +bs3-fpustate-1_INCS = . +bs3-fpustate-1_DEFS = BS3_CMN_INSTANTIATE_FILE1=bs3-fpustate-1-template.c +bs3-fpustate-1_DEFS += BS3_MODE_INSTANTIATE_FILE1=bs3-fpustate-1-template.c +bs3-fpustate-1_SOURCES = \ + bs3kit/bs3-first-rm.asm \ + bs3-fpustate-1.c \ + bs3kit/bs3-cmn-instantiate.c16 \ + bs3kit/bs3-cmn-instantiate.c32 \ + bs3kit/bs3-cmn-instantiate.c64 \ + bs3-fpustate-1-asm.asm +bs3-fpustate-1-template.o:: \ + $$(bs3-fpustate-1_0_OUTDIR)/bs3kit/bs3-cmn-instantiate.o16 \ + $$(bs3-fpustate-1_0_OUTDIR)/bs3kit/bs3-cmn-instantiate.o32 \ + $$(bs3-fpustate-1_0_OUTDIR)/bs3kit/bs3-cmn-instantiate.o64 \ + $$(bs3-fpustate-1_0_OUTDIR)/bs3-fpustate-1-asm.o16 + +# CPU instruction decoding experiments. +MISCBINS += bs3-cpu-decoding-1 +bs3-cpu-decoding-1_TEMPLATE = VBoxBS3KitImg +bs3-cpu-decoding-1_INCS = . +bs3-cpu-decoding-1_DEFS = BS3_CMN_INSTANTIATE_FILE1=bs3-cpu-decoding-1-template.c +bs3-cpu-decoding-1_DEFS += BS3_MODE_INSTANTIATE_FILE1=bs3-cpu-decoding-1-template.c +bs3-cpu-decoding-1_SOURCES = \ + bs3kit/bs3-first-init-all-pp32.asm \ + bs3-cpu-decoding-1.c32 \ + bs3-cpu-decoding-1-asm.asm +# bs3kit/bs3-cmn-instantiate.c16 \ +# bs3kit/bs3-cmn-instantiate.c32 \ +# bs3kit/bs3-cmn-instantiate.c64 +bs3-cpu-decoding-1-template.o:: \ + $$(bs3-cpu-decoding-1_0_OUTDIR)/bs3-cpu-decoding-1-asm.o16 +# $$(bs3-cpu-decoding-1_0_OUTDIR)/bs3kit/bs3-cmn-instantiate.o16 \ +# $$(bs3-cpu-decoding-1_0_OUTDIR)/bs3kit/bs3-cmn-instantiate.o32 \ +# $$(bs3-cpu-decoding-1_0_OUTDIR)/bs3kit/bs3-cmn-instantiate.o64 \ + + +# CPU instructions #2 (first being bootsector2-cpu-instr-1). +MISCBINS += bs3-cpu-instr-2 +bs3-cpu-instr-2_TEMPLATE = VBoxBS3KitImg +bs3-cpu-instr-2_INCS = . +bs3-cpu-instr-2_DEFS = BS3_CMN_INSTANTIATE_FILE1=bs3-cpu-instr-2-template.c +bs3-cpu-instr-2_DEFS += BS3_MODE_INSTANTIATE_FILE1=bs3-cpu-instr-2-template.c +bs3-cpu-instr-2_SOURCES = \ + bs3kit/bs3-first-rm.asm \ + bs3-cpu-instr-2.c \ + bs3-cpu-instr-2-asm.asm \ + bs3kit/bs3-cmn-instantiate-x0.c16 \ + bs3kit/bs3-cmn-instantiate.c32 \ + bs3kit/bs3-cmn-instantiate.c64 +bs3-cpu-instr-2-template.o:: \ + $$(bs3-cpu-instr-2_0_OUTDIR)/bs3kit/bs3-cmn-instantiate-x0.o16 \ + $$(bs3-cpu-instr-2_0_OUTDIR)/bs3kit/bs3-cmn-instantiate.o32 \ + $$(bs3-cpu-instr-2_0_OUTDIR)/bs3kit/bs3-cmn-instantiate.o64 \ + $$(bs3-cpu-instr-2_0_OUTDIR)/bs3-cpu-instr-2-asm.o16 + +# CPU generated instruction tests #1 +MISCBINS += bs3-cpu-generated-1 +bs3-cpu-generated-1_TEMPLATE = VBoxBS3KitImg +bs3-cpu-generated-1_INCS = . +bs3-cpu-generated-1_DEFS = BS3_CMN_INSTANTIATE_FILE1=bs3-cpu-generated-1-template.c +bs3-cpu-generated-1_SOURCES = \ + bs3kit/bs3-first-rm.asm \ + bs3-cpu-generated-1.c \ + bs3-cpu-generated-1-asm.asm \ + bs3kit/bs3-cmn-instantiate-x0.c16 \ + bs3kit/bs3-cmn-instantiate.c32 \ + bs3kit/bs3-cmn-instantiate.c64 \ + $(bs3-cpu-generated-1_0_OUTDIR)/bs3-cpu-generated-1-data.c16 +bs3-cpu-generated-1_CLEAN = $(bs3-cpu-generated-1_0_OUTDIR)/bs3-cpu-generated-1-data.c16 + +bs3-cpu-generated-1-template.o:: \ + $$(bs3-cpu-generated-1_0_OUTDIR)/bs3kit/bs3-cmn-instantiate-x0.o16 \ + $$(bs3-cpu-generated-1_0_OUTDIR)/bs3kit/bs3-cmn-instantiate.o32 \ + $$(bs3-cpu-generated-1_0_OUTDIR)/bs3kit/bs3-cmn-instantiate.o64 \ + $$(bs3-cpu-generated-1_0_OUTDIR)/bs3-cpu-generated-1-asm.o16 + +$$(bs3-cpu-generated-1_0_OUTDIR)/bs3-cpu-generated-1-data.c16: \ + $(PATH_SUB_CURRENT)/bs3-cpu-generated-1-data.py \ + $(PATH_SUB_CURRENT)/../../VMM/VMMAll/IEMAllInstructionsPython.py \ + $(PATH_SUB_CURRENT)/../../VMM/VMMAll/IEMAllInstructions*.cpp.h \ + | $$(dir $$@) + $(REDIRECT) -0 /dev/null -- $(VBOX_BLD_PYTHON) $< $@ + +endif # VBOX_WITH_BS3KIT + + +# +# pylint +# +VBOX_VALIDATIONKIT_PYTHON_SOURCES += $(wildcard $(PATH_SUB_CURRENT)/*.py) +$(evalcall def_vbox_validationkit_process_python_sources) + +include $(FILE_KBUILD_SUB_FOOTER) + diff --git a/src/VBox/ValidationKit/bootsectors/VBoxBs2Linker.cpp b/src/VBox/ValidationKit/bootsectors/VBoxBs2Linker.cpp new file mode 100644 index 00000000..911f5320 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/VBoxBs2Linker.cpp @@ -0,0 +1,219 @@ +/* $Id: VBoxBs2Linker.cpp $ */ +/** @file + * VirtualBox Validation Kit - Boot Sector 2 "linker". + */ + +/* + * Copyright (C) 2006-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <iprt/types.h> + + +int main(int argc, char **argv) +{ + const char *pszOutput = NULL; + const char **papszInputs = (const char **)calloc(argc, sizeof(const char *)); + unsigned cInputs = 0; + + /* + * Scan the arguments. + */ + for (int i = 1; i < argc; i++) + { + if (argv[i][0] == '-') + { + const char *pszOpt = &argv[i][1]; + if (*pszOpt == '-') + { + /* Convert long options to short ones. */ + pszOpt--; + if (!strcmp(pszOpt, "--output")) + pszOpt = "o"; + else if (!strcmp(pszOpt, "--version")) + pszOpt = "V"; + else if (!strcmp(pszOpt, "--help")) + pszOpt = "h"; + else + { + fprintf(stderr, "syntax errro: Unknown options '%s'\n", pszOpt); + free(papszInputs); + return 2; + } + } + + /* Process the list of short options. */ + while (*pszOpt) + { + switch (*pszOpt++) + { + case 'o': + { + const char *pszValue = pszOpt; + pszOpt = strchr(pszOpt, '\0'); + if (*pszValue == '=') + pszValue++; + else if (!*pszValue) + { + if (i + 1 >= argc) + { + fprintf(stderr, "syntax error: The --output option expects a filename.\n"); + free(papszInputs); + return 12; + } + pszValue = argv[++i]; + } + if (pszOutput) + { + fprintf(stderr, "Only one output file is allowed. You've specified '%s' and '%s'\n", + pszOutput, pszValue); + free(papszInputs); + return 2; + } + pszOutput = pszValue; + pszOpt = ""; + break; + } + + case 'V': + printf("%s\n", "$Revision: 127855 $"); + free(papszInputs); + return 0; + + case '?': + case 'h': + printf("usage: %s [options] -o <output> <input1> [input2 ... [inputN]]\n", argv[0]); + free(papszInputs); + return 0; + } + } + } + else + papszInputs[cInputs++] = argv[i]; + } + + if (!pszOutput) + { + fprintf(stderr, "syntax error: No output file was specified (-o or --output).\n"); + free(papszInputs); + return 2; + } + if (cInputs == 0) + { + fprintf(stderr, "syntax error: No input files was specified.\n"); + free(papszInputs); + return 2; + } + + + /* + * Do the job. + */ + /* Open the output file. */ +#if defined(RT_OS_OS2) || defined(RT_OS_WINDOWS) + FILE *pOutput = fopen(pszOutput, "wb"); +#else + FILE *pOutput = fopen(pszOutput, "w"); +#endif + if (!pOutput) + { + fprintf(stderr, "error: Failed to open output file '%s' for writing\n", pszOutput); + free(papszInputs); + return 1; + } + + /* Copy the input files to the output file, with sector padding applied. */ + int rcExit = 0; + size_t off = 0; + for (unsigned i = 0; i < cInputs && rcExit == 0; i++) + { +#if defined(RT_OS_OS2) || defined(RT_OS_WINDOWS) + FILE *pInput = fopen(papszInputs[i], "rb"); +#else + FILE *pInput = fopen(papszInputs[i], "r"); +#endif + if (pInput) + { + for (;;) + { + /* Read a block from the input file. */ + uint8_t abBuf[4096]; + size_t cbRead = fread(abBuf, sizeof(uint8_t), 4096, pInput); + if (!cbRead || ferror(pInput)) + break; + + /* Padd the end of the file if necessary. */ + if (cbRead != 4096 && !feof(pInput)) + { + fprintf(stderr, "error: fread returned %u bytes, but we're not at the end of the file yet...\n", + (unsigned)cbRead); + rcExit = 1; + break; + } + if ((cbRead & 0x1ff) != 0) + { + memset(&abBuf[cbRead], 0, 4096 - cbRead); + cbRead = (cbRead + 0x1ff) & ~0x1ffU; + } + + /* Write the block to the output file. */ + if (fwrite(abBuf, sizeof(uint8_t), cbRead, pOutput) == cbRead) + off += cbRead; + else + { + fprintf(stderr, "error: fwrite failed\n"); + rcExit = 1; + break; + } + } + + if (ferror(pInput)) + { + fprintf(stderr, "error: Error reading '%s'.\n", papszInputs[i]); + rcExit = 1; + } + fclose(pInput); + } + else + { + fprintf(stderr, "error: Failed to open '%s' for reading.\n", papszInputs[i]); + rcExit = 1; + } + } + + /* Finally, close the output file (can fail because of buffered data). */ + if (fclose(stderr) != 0) + { + fprintf(stderr, "error: Error closing '%s'.\n", pszOutput); + rcExit = 1; + } + + fclose(pOutput); + free(papszInputs); + return rcExit; +} + diff --git a/src/VBox/ValidationKit/bootsectors/bootsector-empty.asm b/src/VBox/ValidationKit/bootsectors/bootsector-empty.asm new file mode 100644 index 00000000..4000fd6d --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bootsector-empty.asm @@ -0,0 +1,60 @@ +; $Id: bootsector-empty.asm $ +;; @file +; Empty bootsector can be used as example +; + +; +; Copyright (C) 2012-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + +%include "iprt/asmdefs.mac" +%include "iprt/x86.mac" + + +;; The boot sector load address. +%define BS_ADDR 0x7c00 +%define PDP_ADDR 0x9000 +%define PD_ADDR 0xa000 + + +BITS 16 +start: + ; Start with a jump just to follow the convention. + jmp short the_code + nop +times 3ah db 0 + +the_code: + ; put the code here + + + +hlt_again: + hlt + cli + jmp hlt_again + + ; + ; The GDT. + ; +padding: +times 510 - (padding - start) db 0 + db 055h, 0aah + diff --git a/src/VBox/ValidationKit/bootsectors/bootsector-pae.asm b/src/VBox/ValidationKit/bootsectors/bootsector-pae.asm new file mode 100644 index 00000000..86ef93e2 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bootsector-pae.asm @@ -0,0 +1,165 @@ +; $Id: bootsector-pae.asm $ +;; @file +; Bootsector that switches the CPU info PAE mode. +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + +%include "iprt/asmdefs.mac" +%include "iprt/x86.mac" +%include "VBox/bios.mac" + + +;; The boot sector load address. +%define BS_ADDR 0x7c00 +%define PDP_ADDR 0x9000 +%define PD_ADDR 0xa000 + + +BITS 16 +start: + ; Start with a jump just to follow the convention. + jmp short the_code + nop +times 3ah db 0 + +the_code: + cli + xor edx, edx + mov ds, dx ; Use 0 based addresses + + ; + ; Create a paging hierarchy + ; + mov cx, 4 + xor esi, esi ; physical address + mov ebx, PDP_ADDR + mov edi, PD_ADDR +pdptr_loop: + ; The page directory pointer entry. + mov dword [ebx], edi + or word [bx], X86_PDPE_P + mov dword [ebx + 4], edx + + ; The page directory. +pd_loop: + mov dword [edi], esi + or word [di], X86_PDE4M_P | X86_PDE4M_RW | X86_PDE4M_PS + mov dword [edi + 4], 0 + add esi, 0x00200000 ; 2MB + add di, 8 + test di, 0fffh + jnz pd_loop + + add bx, 8 + loop pdptr_loop + + ; + ; Switch to protected mode. + ; + lgdt [(gdtr - start) + BS_ADDR] + lidt [(idtr_null - start) + BS_ADDR] + + mov eax, PDP_ADDR + mov cr3, eax + + mov eax, cr4 + or eax, X86_CR4_PAE | X86_CR4_PSE + mov cr4, eax + + mov eax, cr0 + or eax, X86_CR0_PE | X86_CR0_PG + mov cr0, eax + jmp far 0x0008:((code32_start - start) + BS_ADDR) ; 8=32-bit CS + +BITS 32 +code32_start: + mov ax, 0x10 + mov ds, ax + mov es, ax + mov fs, ax + mov gs, ax + mov ax, 0x18 + mov es, ax + mov esp, 0x80000 + + ; eye catchers + mov eax, 0xCafeBabe + mov ebx, eax + mov ecx, eax + mov edx, eax + mov edi, eax + mov esi, eax + mov ebp, eax + + ; + ; Boch shutdown request. + ; + mov bl, 64 + mov dx, VBOX_BIOS_SHUTDOWN_PORT + mov ax, VBOX_BIOS_OLD_SHUTDOWN_PORT +retry: + mov ecx, 8 + mov esi, (szShutdown - start) + BS_ADDR + rep outsb + xchg dx, ax ; alternate between the new (VBox) and old (Bochs) ports. + dec bl + jnz retry + ; Shutdown failed! +hlt_again: + hlt + cli + jmp hlt_again + + ; + ; The GDT. + ; +align 8, db 0 +gdt: + dw 0, 0, 0, 0 ; null selector + dw 0xffff, 0, 0x9b00, 0x00cf ; 32 bit flat code segment (0x08) + dw 0xffff, 0, 0x9300, 0x00cf ; 32 bit flat data segment (0x10) + dw 0xffff, 0, 0x9300, 0x00cf ; 32 bit flat stack segment (0x18) + +gdtr: + dw 8*4-1 ; limit 15:00 + dw (gdt - start) + BS_ADDR ; base 15:00 + db 0 ; base 23:16 + db 0 ; unused + +idtr_null: + dw 0 ; limit 15:00 + dw (gdt - start) + BS_ADDR ; base 15:00 + db 0 ; base 23:16 + db 0 ; unused + +szShutdown: + db 'Shutdown', 0 + + ; + ; Padd the remainder of the sector with zeros and + ; end it with the dos signature. + ; +padding: +times 510 - (padding - start) db 0 + db 055h, 0aah + diff --git a/src/VBox/ValidationKit/bootsectors/bootsector-shutdown.asm b/src/VBox/ValidationKit/bootsectors/bootsector-shutdown.asm new file mode 100644 index 00000000..75ec8291 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bootsector-shutdown.asm @@ -0,0 +1,80 @@ +; $Id: bootsector-shutdown.asm $ +;; @file +; Bootsector for grub chainloading that shutdowns the VM. +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + +%include "VBox/bios.mac" + + +BITS 16 +start: + ; Start with a jump just to follow the convention. + jmp short the_code + nop +times 3ah db 0 + +the_code: + cli + + ; + ; VBox/Bochs shutdown request - write "Shutdown" byte by byte to shutdown port. + ; + mov cx, 64 + mov dx, VBOX_BIOS_SHUTDOWN_PORT + mov bx, VBOX_BIOS_OLD_SHUTDOWN_PORT +retry: + mov al, 'S' + out dx, al + mov al, 'h' + out dx, al + mov al, 'u' + out dx, al + mov al, 't' + out dx, al + mov al, 'd' + out dx, al + mov al, 'o' + out dx, al + mov al, 'w' + out dx, al + mov al, 'n' + out dx, al + xchg dx, bx ; alternate between the new (VBox) and old (Bochs) ports. + loop retry + + ; + ; Shutdown failed! + ; + + ;; @todo print some message before halting. + hlt + + ; + ; Padd the remainder of the sector with zeros and + ; end it with the dos signature. + ; +padding: +times 510 - (padding - start) db 0 + db 055h, 0aah + diff --git a/src/VBox/ValidationKit/bootsectors/bootsector2-api.mac b/src/VBox/ValidationKit/bootsectors/bootsector2-api.mac new file mode 100644 index 00000000..116f7a96 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bootsector2-api.mac @@ -0,0 +1,152 @@ +; $Id: bootsector2-api.mac $ +;; @file +; Bootsector2 API definition for use by split images (kernel < 1MB < image). +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + +%ifndef ___bootsector2_api_mac +%define ___bootsector2_api_mac + +;******************************************************************************* +;* Header Files * +;******************************************************************************* +%include "iprt/asmdefs.mac" +%include "iprt/x86.mac" +%include "bootsector2-structures.mac" + +;; +; The load address for big images. +%define BS2_BIG_LOAD_ADDR 0x120000 + + +;; +; API Template for lazy birds. +; +%macro BS2_API_TEMPLATE 0, + + BS2_API_TEMPLATE_ACTION(Bs2DisableA20) + BS2_API_TEMPLATE_ACTION(Bs2DisableA20ViaKbd) + BS2_API_TEMPLATE_ACTION(Bs2DisableA20ViaPortA) + BS2_API_TEMPLATE_ACTION(Bs2DisableNX) + BS2_API_TEMPLATE_ACTION(Bs2EnableA20) + BS2_API_TEMPLATE_ACTION(Bs2EnableA20ViaKbd) + BS2_API_TEMPLATE_ACTION(Bs2EnableA20ViaPortA) + BS2_API_TEMPLATE_ACTION(Bs2EnableNX) + BS2_API_TEMPLATE_ACTION(Bs2IsNXSupported) + BS2_API_TEMPLATE_ACTION(Bs2KbdRead) + BS2_API_TEMPLATE_ACTION(Bs2KbdWait) + BS2_API_TEMPLATE_ACTION(Bs2KbdWrite) + BS2_API_TEMPLATE_ACTION(Bs2PanicIfVMMDevTestingIsMissing) + BS2_API_TEMPLATE_ACTION(Bs2SetupNX) + BS2_API_TEMPLATE_ACTION(CalcBenchmarkIterations) + BS2_API_TEMPLATE_ACTION(CalcTestPerSecond) + BS2_API_TEMPLATE_ACTION(GetElapsedNanoTS) + BS2_API_TEMPLATE_ACTION(GetNanoTS) + BS2_API_TEMPLATE_ACTION(PrintChr) + BS2_API_TEMPLATE_ACTION(PrintF) + BS2_API_TEMPLATE_ACTION(PrintStr) + BS2_API_TEMPLATE_ACTION(PrintStrColonSpaces) + BS2_API_TEMPLATE_ACTION(PrintStrSpacesColonSpace) + BS2_API_TEMPLATE_ACTION(PrintU32) + BS2_API_TEMPLATE_ACTION(ReportResult) + BS2_API_TEMPLATE_ACTION(Shutdown) + BS2_API_TEMPLATE_ACTION(StrFormatF) + BS2_API_TEMPLATE_ACTION(StrFormatV) + BS2_API_TEMPLATE_ACTION(StrLen) + BS2_API_TEMPLATE_ACTION(TestCheckTrap) + BS2_API_TEMPLATE_ACTION(TestDumpCurrentRegisters) + BS2_API_TEMPLATE_ACTION(TestDumpRegisters) + BS2_API_TEMPLATE_ACTION(TestFailed) + BS2_API_TEMPLATE_ACTION(TestFailedF) + BS2_API_TEMPLATE_ACTION(TestInit) + BS2_API_TEMPLATE_ACTION(TestRestoreRegisters) + BS2_API_TEMPLATE_ACTION(TestSaveRegisters) + BS2_API_TEMPLATE_ACTION(testSendStrCmd) + BS2_API_TEMPLATE_ACTION(TestSkipped) + BS2_API_TEMPLATE_ACTION(TestSub) + BS2_API_TEMPLATE_ACTION(testSubCleanup) + BS2_API_TEMPLATE_ACTION(TestSubDone) + BS2_API_TEMPLATE_ACTION(TestSubErrorCount) + BS2_API_TEMPLATE_ACTION(TestTerm) + BS2_API_TEMPLATE_ACTION(TestValueReg) + BS2_API_TEMPLATE_ACTION(TestValueU32) + BS2_API_TEMPLATE_ACTION(TestInstallTrapRecs) + +%endmacro + + +;; +; This defines the API pointers. +; +ABSOLUTE 0x500 +;; Start the structure with a magic number. +NAME(g_u32Bs2ApiMagic): resd 1 +;; And a version number. +NAME(g_u32Bs2ApiVersion): resd 1 + +; The real mode and v8086 mode entry points (far pointers). +%undef BS2_API_TEMPLATE_ACTION +%define BS2_API_TEMPLATE_ACTION(a_Name) NAME(g_pfn %+ a_Name %+ _r86): resd 1 +BS2_API_TEMPLATE + +; The 16-bit protected mode entry points (far pointers). +%undef BS2_API_TEMPLATE_ACTION +%define BS2_API_TEMPLATE_ACTION(a_Name) NAME(g_pfn %+ a_Name %+ _p16): resd 1 +BS2_API_TEMPLATE + +; The 32-bit protected mode entry points (flat pointers). +%undef BS2_API_TEMPLATE_ACTION +%define BS2_API_TEMPLATE_ACTION(a_Name) NAME(g_pfn %+ a_Name %+ _p32): resd 1 +BS2_API_TEMPLATE + +; The 64-bit protected (long) mode entry points. +%undef BS2_API_TEMPLATE_ACTION +%define BS2_API_TEMPLATE_ACTION(a_Name) NAME(g_pfn %+ a_Name %+ _p64): resq 1 +BS2_API_TEMPLATE + +;; End the structure with a magic so it's integrity can be verified. +NAME(g_u32Bs2ApiEndMagic) resd 1 + +;; +; The current API magic value (Douglas Carl Engelbart). +%define BS2_API_MAGIC 0x19250130 + +;; +; The current API version. +%define BS2_API_VERSION 0x00010000 + +BEGINCODE + + +;; @name Service trap vector interface. +; @{ +%define BS2_SYSCALL_TO_RING0 0 +%define BS2_SYSCALL_TO_RING1 1 +%define BS2_SYSCALL_TO_RING2 2 +%define BS2_SYSCALL_TO_RING3 3 + +;; The service vector. +%define BS2_TRAP_SYSCALL 20h +;; @} + +%endif diff --git a/src/VBox/ValidationKit/bootsectors/bootsector2-boot-registers-1.asm b/src/VBox/ValidationKit/bootsectors/bootsector2-boot-registers-1.asm new file mode 100644 index 00000000..ff697ddc --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bootsector2-boot-registers-1.asm @@ -0,0 +1,76 @@ +; $Id: bootsector2-boot-registers-1.asm $ +;; @file +; Bootsector that prints the register status at boot. +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + + +%include "iprt/asmdefs.mac" +%include "iprt/x86.mac" +%include "VBox/VMMDevTesting.mac" + +; +; Initialize in real mode, preserving the registers. +; +%define BS2_INIT_RM +%define BS2_INIT_SAVE_REGS +%include "bootsector2-common-init-code.mac" + +main: + mov ax, BS2_REG_SAVE_ADDR + call NAME(TestDumpRegisters_r86) + + xor ax, ax + mov al, [es:di] + push ax + mov al, [es:di + 1] + push ax + mov al, [es:di + 2] + push ax + mov al, [es:di + 3] + push ax + push ds + push .s_szPnpFmt1 + call NAME(PrintF_r86) + pop ax + push .s_szPnpFmt2 + call NAME(PrintF_r86) + pop ax + push .s_szPnpFmt3 + call NAME(PrintF_r86) + + call NAME(Bs2Panic) + +.s_szPnpFmt1: + db 'es:di -> %RX8 %RX8 %RX8 %RX8 ',0 +.s_szPnpFmt2: + db '%c%c%c%c', 0 +.s_szPnpFmt3: + db 13, 10, 0 + +; +; Pad the image so it loads cleanly. +; +BS2_PAD_IMAGE +the_end: + diff --git a/src/VBox/ValidationKit/bootsectors/bootsector2-common-end.mac b/src/VBox/ValidationKit/bootsectors/bootsector2-common-end.mac new file mode 100644 index 00000000..f842be59 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bootsector2-common-end.mac @@ -0,0 +1,42 @@ +; $Id: bootsector2-common-end.mac $ +;; @file +; Boot sector 2 - End of code. +; +; @note Don't forget to cinldue bootsector2-common-traprec-end.mac! +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + + +; +; Terminate the trap records if opened. +; +%ifdef BS2_WITH_TRAPRECS + BS2_TRAP_RECS_END +%endif + +; +; Pad the image so it loads cleanly. +; +BEGINEND +the_end: + diff --git a/src/VBox/ValidationKit/bootsectors/bootsector2-common-init-code.mac b/src/VBox/ValidationKit/bootsectors/bootsector2-common-init-code.mac new file mode 100644 index 00000000..aa76bf15 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bootsector2-common-init-code.mac @@ -0,0 +1,2303 @@ +; $Id: bootsector2-common-init-code.mac $ +;; @file +; Common bootsector code init. +; +; In addition to initialize the stack at %7bf0 it loads the first 512KB of the +; floppy image at %7c00. The control is handed over with interrupts disabled +; to a 'main' function defined by the includer. +; +; The following defines controls the mode we call main in: +; - BS2_INIT_RM (default) +; - BS2_INIT_PE32 +; - BS2_INIT_PP32 +; - BS2_INIT_PAE32 +; - BS2_INIT_LM64 +; +; The following defines controls code inclusion: +; - BS2_INC_RM +; - BS2_INC_PE +; - BS2_INC_PE16 +; - BS2_INC_PE32 +; - BS2_INC_PEV86 +; - BS2_INC_PP +; - BS2_INC_PP16 +; - BS2_INC_PP32 +; - BS2_INC_PPV86 +; - BS2_INC_PAE +; - BS2_INC_PAE16 +; - BS2_INC_PAE32 +; - BS2_INC_PAEV86 +; - BS2_INC_LM +; - BS2_INC_LM16 +; - BS2_INC_LM32 +; - BS2_INC_LM64 +; - BS2_INC_CMN_R86 +; - BS2_INC_CMN_V86 +; - BS2_INC_CMN_P16 +; - BS2_INC_CMN_P32 +; - BS2_INC_CMN_P64 +; - BS2_WITH_TRAPS +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + + +; map files should include symbols and everything. +[map all] + +;******************************************************************************* +;* Header Files * +;******************************************************************************* +%include "bootsector2-structures.mac" +%include "bootsector2-common-macros-1.mac" +%include "VBox/bios.mac" + + +;******************************************************************************* +;* Defined Constants And Macros * +;******************************************************************************* +;; @name Static Memory Allocation +; @{ +;; The boot sector load address. +%define BS2_ADDR 07c00h +;; The stack is located before the code (and will overflow into the interrupt +; table and other essential system data). +%define STACK_ADDR (BS2_ADDR - 256) + +%ifdef BS2_WITH_TRAPS +;; The address of the ring-0 stack in bs2Tss32BitDf. +%define BS2_DF_R0_STACK_ADDR 06800h +;; The address of the ring-0 stack in TSSxx. +%define BS2_R0_STACK_ADDR 06000h +;; The address of the ring-1 stack in TSSxx. +%define BS2_R1_STACK_ADDR 05000h +;; The address of the ring-2 stack in TSSxx. +%define BS2_R2_STACK_ADDR 04800h +%endif ; BS2_WITH_TRAPS + +;; +; Where we save the boot registers during init. +%define BS2_REG_SAVE_ADDR 06000h + +;; The start of the memory area used for paging, stacks and so forth. +%define BS2_PXX_BASE 080000h + +;; The page map level 4 address (all entries point to BS2_LM_PDP_ADDR). +%define BS2_LM_PML4_ADDR 080000h +;; The long mode page directory pointer table address. +%define BS2_LM_PDP_ADDR 081000h +;; The PAE page directory pointer table address. +%define BS2_PAE_PDP_ADDR 082000h +;; The address of the 4 PAE page directories. Also used by long mode. +%define BS2_PAE_PD_ADDR 083000h +;; The address of the 32-bit page directory. +%define BS2_32B_PD_ADDR 087000h +;; User page table #0. +%define BS2_USER_PX_0_ADDR 088000h +;; User page table #1. +%define BS2_USER_PX_1_ADDR 089000h +;; User page table #2. +%define BS2_USER_PX_2_ADDR 08a000h +;; User page table #3. +%define BS2_USER_PX_3_ADDR 08b000h +;; User page table #4. +%define BS2_USER_PX_4_ADDR 08c000h +;; User page table #5. +%define BS2_USER_PX_5_ADDR 08d000h +;; User page table #6. +%define BS2_USER_PX_6_ADDR 08e000h +;; User page table #7. +%define BS2_USER_PX_7_ADDR 08f000h +;; The selector to use when accessing the PDP and PD from real mode. +%define BS2_PXX_SEL 08000h +;; Converts a BS2_P*_ADDR into a BS2_PXX_SEL selector offset. +%define BS2_PXX_OFF(Addr) ( (Addr) - (BS2_PXX_SEL * 16) ) + +;; The base address in the default address spaces of the range where we are +; free to muck about as much as we like. (This is a virtual address.) +%define BS2_MUCK_ABOUT_BASE 000400000h + +; We have some free space here 090000h...09a000h (stacks moved) + +;; The address of the LDT. +%define BS2_LDT_BASE 09b000h +;; The size of the LDT in bytes. +%define BS2_LDT_SIZE 001fffh + +;; The start of the memory area used for paging, stacks and so forth. +%define BS2_PXX_LAST 09ffffh +;; @} + + +;; +; @name Group of 32-bit, 16-bit and 64-bit selectors for one ring. +; @{ +%define BS2_SEL_GRP_CS32 00h +%define BS2_SEL_GRP_DS32 08h +%define BS2_SEL_GRP_SS32 10h +%define BS2_SEL_GRP_CS16 18h +%define BS2_SEL_GRP_DS16 20h +%define BS2_SEL_GRP_SS16 28h +%define BS2_SEL_GRP_CS64 30h +%define BS2_SEL_GRP_DS64 38h +%define BS2_SEL_GRP_SS64 38h +%define BS2_SEL_GRP_SIZE 40h +;; @} + + +;; Move to program. +%ifndef BS2_WITHOUT_RAW_MODE + %define BS2_WITH_RAW_MODE +%endif + +; Implicit code inclusion based on the init mode. +%ifdef BS2_INIT_PE32 + %define BS2_INC_PE32 +%elifdef BS2_INIT_PP32 + %define BS2_INC_PP32 +%elifdef BS2_INIT_PAE32 + %define BS2_INC_PAE32 +%elifdef BS2_INIT_LM64 + %define BS2_INC_LM64 +%else + %define BS2_INIT_RM ; the default + %define BS2_INC_RM +%endif + +; Aliases. +%ifdef BS2_INC_PE + %define BS2_INC_PE16 + %define BS2_INC_PE32 + %define BS2_INC_PEV86 +%endif +%ifdef BS2_INC_PP + %define BS2_INC_PP16 + %define BS2_INC_PP32 + %define BS2_INC_PPV86 +%endif +%ifdef BS2_INC_PAE + %define BS2_INC_PAE16 + %define BS2_INC_PAE32 + %define BS2_INC_PAEV86 +%endif +%ifdef BS2_INC_LM + %define BS2_INC_LM16 + %define BS2_INC_LM32 + %define BS2_INC_LM64 +%endif + +; Common code. +%ifdef BS2_INC_RM + %define BS2_INC_CMN_R86 +%endif +%ifdef BS2_INC_PE16 + %define BS2_INC_CMN_P16 + %define BS2_INC_CMN_PE + %define BS2_INC_CMN_PM +%endif +%ifdef BS2_INC_PE32 + %define BS2_INC_CMN_P32 + %define BS2_INC_CMN_PE + %define BS2_INC_CMN_PM +%endif +%ifdef BS2_INC_PEV86 + %define BS2_INC_CMN_R86 + %define BS2_INC_CMN_V86 + %define BS2_INC_CMN_PE + %define BS2_INC_CMN_PM +%endif +%ifdef BS2_INC_PP16 + %define BS2_INC_CMN_P16 + %define BS2_INC_CMN_PP + %define BS2_INC_CMN_PM +%endif +%ifdef BS2_INC_PP32 + %define BS2_INC_CMN_P32 + %define BS2_INC_CMN_PP + %define BS2_INC_CMN_PM +%endif +%ifdef BS2_INC_PPV86 + %define BS2_INC_CMN_R86 + %define BS2_INC_CMN_V86 + %define BS2_INC_CMN_PP + %define BS2_INC_CMN_PM +%endif +%ifdef BS2_INC_PAE16 + %define BS2_INC_CMN_P16 + %define BS2_INC_CMN_PAE + %define BS2_INC_CMN_PM + %define BS2_INC_CMN_PAE_LM +%endif +%ifdef BS2_INC_PAE32 + %define BS2_INC_CMN_P32 + %define BS2_INC_CMN_PAE + %define BS2_INC_CMN_PM + %define BS2_INC_CMN_PAE_LM +%endif +%ifdef BS2_INC_PAEV86 + %define BS2_INC_CMN_R86 + %define BS2_INC_CMN_V86 + %define BS2_INC_CMN_PAE + %define BS2_INC_CMN_PM + %define BS2_INC_CMN_PAE_LM +%endif +%ifdef BS2_INC_LM16 + %define BS2_INC_CMN_P16 + %define BS2_INC_CMN_LM + %define BS2_INC_CMN_PAE_LM +%endif +%ifdef BS2_INC_LM32 + %define BS2_INC_CMN_P32 + %define BS2_INC_CMN_LM + %define BS2_INC_CMN_PAE_LM +%endif +%ifdef BS2_INC_LM64 + %define BS2_INC_CMN_LM64 + %define BS2_INC_CMN_LM + %define BS2_INC_CMN_PAE_LM +%endif + + +; +; Misc defines. +; +;; The offset of the TSS32.CR3 field. +%define BS2_TSS32_CR3_OFF 01ch + + +;******************************************************************************* +;* Structures and Typedefs * +;******************************************************************************* + + +; +; Start with a jump just to follow the convention. +; Also declare all segments/sections to establish them and their order. +; + ORG BS2_ADDR + +section .text valign=16 align=16 progbits +section .data vfollows=.text follows=.text valign=16 align=16 progbits +section .texthigh vfollows=.data follows=.data valign=16 align=16 progbits +section .traprecs vfollows=.texthigh follows=.texthigh valign=8 align=8 progbits +section .end vfollows=.traprecs follows=.traprecs valign=512 align=512 progbits + +%define BEGINCODELOW section .text ;;< For 16-bit code. +%define BEGINCODEHIGH section .texthigh ;;< For 32-bit and 64-bit code. +%define BEGINEND section .end ;;< For aligning image to 512 bytes. + +BEGINCODELOW +BITS 16 +start: + jmp short bs2InitCode + nop + nop ; alignment + +; +; Abuse the bios parameter block area for data storage. +; +gdtr: + dw bs2GdtEnd - bs2Gdt - 1 ; limit 15:00 + dw bs2Gdt ; base 15:00 + db 0 ; base 23:16 + db 0 ; unused + +idtr_null: + dw 0 ; limit 15:00 + dw bs2Gdt ; base 15:00 + db 0 ; base 23:16 + db 0 ; unused + +%ifdef BS2_WITH_TRAPS + %ifdef BS2_INC_CMN_PM +idtr_32bit: + dw bs2Idt32bitEnd - bs2Idt32bit -1 ; limit 15:00 + dw bs2Idt32bit ; base 15:00 + db 0 ; base 23:16 + db 0 ; unused + %endif + + %ifdef BS2_INC_CMN_LM +idtr_64bit: + dw bs2Idt64bitEnd - bs2Idt64bit -1 ; limit 15:00 + dw bs2Idt64bit ; base 15:00 + db 0 ; base 23:16 + db 0 ; unused + %endif + +%elifdef BS2_WITH_RAW_MODE +idtr_dummy_32bit: + dw bs2DummyIdt32bitEnd - bs2DummyIdt32bit -1 ; limit 15:00 + dw bs2DummyIdt32bit ; base 15:00 + db 0 ; base 23:16 + db 0 ; unused +%endif + +idtr_real_mode: + dw 01ffh ; limit 15:00 + dw 0 ; base 15:00 + db 0 ; base 23:16 + db 0 ; unused + +g_achHex: + db '0123456789abcdef', 0 + +g_bBootDrv: + db 80h ; Not in the official BPB location, but whatever. +g_fCpuIntel: + db 0 +g_fCpuAmd: + db 0 + +bs2BpbPadding: + times 3dh - (bs2BpbPadding - start) db 0 + + +; +; Where to real init code starts. +; +bs2InitCode: + cli + +%ifdef BS2_INIT_SAVE_REGS + ; save the registers if we've been asked to do so. + mov [cs:BS2_REG_SAVE_ADDR + BS2REGS.rax], eax + mov [cs:BS2_REG_SAVE_ADDR + BS2REGS.rsp], esp + mov [cs:BS2_REG_SAVE_ADDR + BS2REGS.rbp], ebp + mov ax, ss + mov [cs:BS2_REG_SAVE_ADDR + BS2REGS.ss], ax + mov ax, ds + mov [cs:BS2_REG_SAVE_ADDR + BS2REGS.ds], ax + mov ax, es + mov [cs:BS2_REG_SAVE_ADDR + BS2REGS.es], ax + mov ax, fs + mov [cs:BS2_REG_SAVE_ADDR + BS2REGS.fs], ax + mov ax, gs +%endif + + ; set up the segment reisters and stack. + xor eax, eax + mov ds, ax + mov es, ax + mov fs, ax + mov gs, ax + mov ss, ax + mov esp, STACK_ADDR + mov [esp], eax ; clear the first 16 bytes + mov [esp + 04h], eax + mov [esp + 08h], eax ; fake rbp. + mov [esp + 0ch], eax ; fake ebp and bp + mov ebp, esp + +%ifdef BS2_INIT_SAVE_REGS + ; Save more registers now that ds is known and the stack is usable. + pushfd + pop eax + mov [BS2_REG_SAVE_ADDR + BS2REGS.rflags], eax + mov [BS2_REG_SAVE_ADDR + BS2REGS.rbx], ebx + mov [BS2_REG_SAVE_ADDR + BS2REGS.rcx], ecx + mov [BS2_REG_SAVE_ADDR + BS2REGS.rdx], edx + mov [BS2_REG_SAVE_ADDR + BS2REGS.rsi], esi + mov [BS2_REG_SAVE_ADDR + BS2REGS.rdi], edi +%endif + + ; Make sure caching is enabled and alignment is off. + mov eax, cr0 +%ifdef BS2_INIT_SAVE_REGS + mov [BS2_REG_SAVE_ADDR + BS2REGS.cr0], eax +%endif + and eax, ~(X86_CR0_NW | X86_CR0_CD | X86_CR0_AM) + mov cr0, eax + + ; Load all the code. + call bs2InitLoadImage + mov [g_bBootDrv], dl + + ; Initialize the data structures for the included modes requiring this. +%ifdef BS2_INC_CMN_PP + call bs2InitPagedProtMode +%endif +%ifdef BS2_INC_CMN_PAE + call bs2InitPaeProtMode +%endif +%ifdef BS2_INC_CMN_LM + call bs2InitLongMode +%endif + + ; Entered the desired mode. +%ifdef BS2_INIT_PE32 + call Bs2EnterMode_rm_pe32 +BITS 32 +%endif +%ifdef BS2_INIT_PP32 + call Bs2EnterMode_rm_pp32 +BITS 32 +%endif +%ifdef BS2_INIT_PAE32 + call Bs2EnterMode_rm_pae32 +BITS 32 +%endif +%ifdef BS2_INIT_LM64 + call Bs2EnterMode_rm_lm64 +BITS 64 +%endif +%ifdef BS2_INIT_RM + call SetCpuModeGlobals_rm +%endif + +%ifdef BS2_WITH_RAW_MODE + ; + ; Mask interrupts and then set IF. + ; + mov al, 0ffh + out 021h, al + out 0a1h, al + sti +%endif + + jmp bs2DoneInit + + +;; +; Loads the image off the floppy. +; +; This uses the the_end label to figure out the length. For this to work +; cleanly the label must be aligned on a sector boundrary. Use BS2_PAD_IMAGE +; to make sure this is the case. +; +; Clobbers everything except ebp and esp. Panics on failure. +; +; @param dl The boot drive number (from BIOS). +; @uses ax, cx, bx, esi, di +; +BEGINCODELOW +BITS 16 +BEGINPROC bs2InitLoadImage + push bp + mov bp, sp + push es +%define bSavedDiskNo byte [bp - 04h] + push dx +%define bMaxSector byte [bp - 06h] + push 0 +%define bMaxHead byte [bp - 08h] + push 0 +%define bMaxCylinder byte [bp - 0ah] + push 0 + + ; + ; Try figure the geometry. + ; + mov ah, 08h + int 13h + jc .failure + mov bMaxSector, cl + mov bMaxHead, dh + mov bMaxCylinder, ch + mov dl, bSavedDiskNo + + ; + ; Reload all the sectors one at a time (avoids problems). + ; + lea esi, [dword the_end] + sub esi, start + shr esi, 9 ; si = number of sectors to load. + mov di, BS2_ADDR / 16 ; The current load segment. + mov cx, 0001h ; ch/cylinder=0 (0-based); cl/sector=1 (1-based) + xor dh, dh ; dh/head=0 +.the_load_loop: + xor bx, bx + mov es, di ; es:bx -> buffer + mov ax, 0201h ; al=1 sector; ah=read function + int 13h + jc .failure + + ; advance to the next sector/head/cylinder. + inc cl + cmp cl, bMaxSector + jbe .adv_addr + + mov cl, 1 + inc dh + cmp dh, bMaxHead + jbe .adv_addr + + mov dh, 0 + inc ch + +.adv_addr: + add di, 512 / 16 + dec si + jnz .the_load_loop + + add sp, 3*2 + pop dx + pop es + leave + ret + + ; + ; Something went wrong, display a message. + ; +.failure: + pusha + + ; print message + mov si, .s_szErrMsg + mov ah, 0eh + xor bx, bx +.failure_next_char: + lodsb + int 10h + cmp si, .s_szErrMsgEnd + jb .failure_next_char + + ; format the error number. + movzx bx, byte [bp - 2 - 1] ; read the ah of the pusha frame + shr bl, 4 + mov al, [bx + g_achHex] + int 10h + + movzx bx, byte [bp - 2 - 1] ; read the ah of the pusha frame + and bl, 0fh + mov al, [bx + g_achHex] + int 10h + + ; panic + popa + call Bs2Panic +.s_szErrMsg: + db 13, 10, 'read error: ' +.s_szErrMsgEnd: +ENDPROC bs2InitLoadImage + +;; Pads the image so bs2InitLoadImage can load it without trouble. +%macro BS2_PAD_IMAGE 0 +bs2PadImageLabel: +; times ( (512*18*2) - ( (bs2PadImageLabel - start) % (512*18*2) ) ) db 0 ; track aligned size. + times ( 512 - ( (bs2PadImageLabel - start) % 512 ) ) db 0 ; sector aligned size. +; times ( 10000h - BS2_ADDR - (bs2PadImageLabel - start) ) db 0 ; full segment 0 size. +%endmacro + + +;; +; Shutdown routine that will work in real and protected mode, providing +; that SS is valid that we can load it into DS. +; +; Does not return. +; +BEGINCODELOW +BITS 16 +BEGINPROC Bs2Shutdown + cli + mov bl, 64 + mov ax, ss + mov ds, ax + mov dx, VBOX_BIOS_SHUTDOWN_PORT + mov ax, VBOX_BIOS_OLD_SHUTDOWN_PORT +.retry: + mov ecx, 8 + mov esi, .s_szShutdown + rep outsb + xchg dx, ax ; alternate between the new (VBox) and old (Bochs) ports. + dec bl + jnz .retry + ; Shutdown failed! + jmp Bs2Panic +.s_szShutdown: + db 'Shutdown', 0 +ENDPROC Bs2Shutdown + + +;; +; Panic routine for real mode. +; +; Does not return. +; +BEGINCODELOW +BITS 16 +BEGINPROC Bs2Panic + cli +.hlt_again: + hlt + jmp .hlt_again +ENDPROC Bs2Panic + + +; +; Padd the remainder of the sector with zeros and +; end it with the dos signature. +; +bs2Padding: + times 510 - (bs2Padding - start) db 0 + db 055h, 0aah + + +; +; The GDT (X86DESCGENERIC). +; +align 8, db 0 +bs2Gdt: + dw 00000h, 00000h, 00000h, 00000h ; null selector +%define BS2_SEL_R0_BASE 08h +%define BS2_SEL_CS32 08h + dw 0ffffh, 00000h, 09b00h, 000cfh ; 32-bit flat code segment. +%define BS2_SEL_DS32 10h + dw 0ffffh, 00000h, 09300h, 000cfh ; 32-bit flat data segment. +%define BS2_SEL_SS32 18h + dw 0ffffh, 00000h, 09300h, 000cfh ; 32-bit flat stack segment. +%define BS2_SEL_CS16 20h + dw 0ffffh, 00000h, 09b00h, 00000h ; 16-bit code segment with base 0. +%define BS2_SEL_DS16 28h + dw 0ffffh, 00000h, 09300h, 00000h ; 16-bit data segment with base 0. +%define BS2_SEL_SS16 30h + dw 0ffffh, 00000h, 09300h, 00000h ; 16-bit stack segment with base 0. +%define BS2_SEL_CS64 38h + dw 0ffffh, 00000h, 09a00h, 000afh ; 64-bit code segment. +%define BS2_SEL_DS64 40h +%define BS2_SEL_SS64 40h + dw 0ffffh, 00000h, 09300h, 000afh ; 64-bit stack and data segment. + dw 00000h, 00000h, 00000h, 00000h ; Unused +%define BS2_SEL_MMIO16 50h +%define BS2_SEL_MMIO16_BASE 0100000h + dw 0ffffh, 00000h, 09310h, 00000h ; 16-bit VMMDev MMIO segment with base 0100000h. + dw 00000h, 00000h, 00000h, 00000h ; Unused +%define BS2_SEL_LDT 60h ; LDT usage requires manual LLDT and setting up. + dw BS2_LDT_SIZE, BS2_LDT_BASE & 0xffff, 08200h | ((BS2_LDT_BASE >> 16) & 0xff), 00000h + dw 00000h, 00000h, 00000h, 00000h ; zero for 64-bit mode. +%define BS2_SEL_CS16_EO 70h + dw 0fffeh, 00000h, 09800h, 00000h ; 16-bit code segment with base 0, not accessed, execute only, short limit. + dw 00000h, 00000h, 00000h, 00000h ; unused. +%ifdef BS2_WITH_TRAPS + %ifdef BS2_INC_CMN_PM + %define BS2_SEL_TSS32 80h + dw (bs2Tss32BitEnd - bs2Tss32Bit) - 1 ; 32-bit TSS. + dw bs2Tss32Bit + db 0 + db X86_SEL_TYPE_SYS_386_TSS_AVAIL | 0x80 + dw 0 + %define BS2_SEL_TSS32_DF 88h + dw (bs2Tss32BitDfEnd - bs2Tss32BitDf) - 1; 32-bit TSS, double fault. + dw bs2Tss32BitDf + db 0 + db X86_SEL_TYPE_SYS_386_TSS_AVAIL | 0x80 + dw 0 + %else + dw 00000h, 00000h, 00000h, 00000h + dw 00000h, 00000h, 00000h, 00000h + %endif + %ifdef BS2_INC_CMN_LM + %define BS2_SEL_TSS64 90h + dw (bs2Tss64BitEnd - bs2Tss64Bit) - 1 ; 32-bit TSS. + dw bs2Tss64Bit + db 0 + db AMD64_SEL_TYPE_SYS_TSS_AVAIL | 0x80 + dw 0 + dw 00000h, 00000h, 00000h, 00000h ; 2nd half of the 64-bit selector (not necessary). + %else + dw 00000h, 00000h, 00000h, 00000h + dw 00000h, 00000h, 00000h, 00000h + %endif +%endif + ; Ring-1 selectors. +%define BS2_SEL_R1_BASE 0a0h +%define BS2_SEL_R1_CS32 0a0h + dw 0ffffh, 00000h, 0bb00h, 000cfh ; Ring-1 32-bit flat code segment. +%define BS2_SEL_R1_DS32 0a8h + dw 0ffffh, 00000h, 0b300h, 000cfh ; Ring-1 32-bit flat data segment. +%define BS2_SEL_R1_SS32 0b0h + dw 0ffffh, 00000h, 0b300h, 000cfh ; Ring-1 32-bit flat stack segment. +%define BS2_SEL_R1_CS16 0b8h + dw 0ffffh, 00000h, 0bb00h, 00000h ; Ring-1 16-bit code segment with base 0. +%define BS2_SEL_R1_DS16 0c0h + dw 0ffffh, 00000h, 0b300h, 00000h ; Ring-1 16-bit data segment with base 0. +%define BS2_SEL_R1_SS16 0c8h + dw 0ffffh, 00000h, 0b300h, 00000h ; Ring-1 16-bit stack segment with base 0. +%define BS2_SEL_R1_CS64 0d0h + dw 0ffffh, 00000h, 0ba00h, 000afh ; Ring-1 64-bit code segment. +%define BS2_SEL_R1_DS64 0d8h +%define BS2_SEL_R1_SS64 0d8h + dw 0ffffh, 00000h, 0b300h, 000afh ; Ring-1 64-bit stack and data segment. + + ; Ring-2 selectors. +%define BS2_SEL_R2_BASE 0e0h +%define BS2_SEL_R2_CS32 0e0h + dw 0ffffh, 00000h, 0db00h, 000cfh ; Ring-2 32-bit flat code segment. +%define BS2_SEL_R2_DS32 0e8h + dw 0ffffh, 00000h, 0d300h, 000cfh ; Ring-2 32-bit flat data segment. +%define BS2_SEL_R2_SS32 0f0h + dw 0ffffh, 00000h, 0d300h, 000cfh ; Ring-2 32-bit flat stack segment. +%define BS2_SEL_R2_CS16 0f8h + dw 0ffffh, 00000h, 0db00h, 00000h ; Ring-2 16-bit code segment with base 0. +%define BS2_SEL_R2_DS16 0f0h + dw 0ffffh, 00000h, 0d300h, 00000h ; Ring-2 16-bit data segment with base 0. +%define BS2_SEL_R2_SS16 108h + dw 0ffffh, 00000h, 0d300h, 00000h ; Ring-2 16-bit stack segment with base 0. +%define BS2_SEL_R2_CS64 110h + dw 0ffffh, 00000h, 0da00h, 000afh ; Ring-2 64-bit code segment. +%define BS2_SEL_R2_DS64 118h +%define BS2_SEL_R2_SS64 118h + dw 0ffffh, 00000h, 0d300h, 000afh ; Ring-2 64-bit stack and data segment. + + ; Ring-3 selectors. +%define BS2_SEL_R3_BASE 120h +%define BS2_SEL_R3_CS32 120h + dw 0ffffh, 00000h, 0fb00h, 000cfh ; Ring-3 32-bit flat code segment. +%define BS2_SEL_R3_DS32 128h + dw 0ffffh, 00000h, 0f300h, 000cfh ; Ring-3 32-bit flat data segment. +%define BS2_SEL_R3_SS32 130h + dw 0ffffh, 00000h, 0f300h, 000cfh ; Ring-3 32-bit flat stack segment. +%define BS2_SEL_R3_CS16 138h + dw 0ffffh, 00000h, 0fb00h, 00000h ; Ring-3 16-bit code segment with base 0. +%define BS2_SEL_R3_DS16 140h + dw 0ffffh, 00000h, 0f300h, 00000h ; Ring-3 16-bit data segment with base 0. +%define BS2_SEL_R3_SS16 148h + dw 0ffffh, 00000h, 0f300h, 00000h ; Ring-3 16-bit stack segment with base 0. +%define BS2_SEL_R3_CS64 150h + dw 0ffffh, 00000h, 0fa00h, 000afh ; Ring-1 64-bit code segment. +%define BS2_SEL_R3_DS64 158h +%define BS2_SEL_R3_SS64 158h + dw 0ffffh, 00000h, 0f300h, 000afh ; Ring-1 64-bit stack and data segment. + + ; Here follows a bunch of spare GDT entries for (ab)use in testing. +%define BS2_SEL_SPARE0 160h +bs2GdtSpare0: + dq 0 +%define BS2_SEL_SPARE1 (BS2_SEL_SPARE0 + 08h) +bs2GdtSpare1: + dq 0 +%define BS2_SEL_SPARE2 (BS2_SEL_SPARE0 + 10h) +bs2GdtSpare2: + dq 0 +%define BS2_SEL_SPARE3 (BS2_SEL_SPARE0 + 18h) +bs2GdtSpare3: + dq 0 +bs2GdtEnd: + + +%ifndef BS2_WITH_TRAPS + %ifdef BS2_WITH_RAW_MODE +; +; Dummy 32-bit IDT for making CSAM happy. +; +align 16, db 0 +bs2DummyIdt32bit: + dw 0, 0, 0, 0 + dw 0, 0, 0, 0 + dw 0, 0, 0, 0 + dw 0, 0, 0, 0 +bs2DummyIdt32bitEnd + %endif +%endif + + +; +; Mode initialization routines. +; + +%ifdef BS2_INC_CMN_PP +;; +; Initializes the paged protected mode structures during init. +; +; @uses ebx, esi +; +BEGINCODELOW +BITS 16 +BEGINPROC bs2InitPagedProtMode + push ds + + ; + ; Create a paging hierarchy + ; + mov bx, BS2_PXX_SEL + mov ds, bx + mov ebx, BS2_PXX_OFF(BS2_32B_PD_ADDR) + xor esi, esi ; physical address + + ; The page directory. +.pd_loop: + mov dword [bx], esi + or word [bx], X86_PDE4M_P | X86_PDE4M_RW | X86_PDE4M_PS | X86_PDE4M_US + add esi, _4M + add bx, 4 + test bx, 0fffh + jnz .pd_loop + +%ifdef BS2_WITH_RAW_MODE + ; + ; Make sure there is some free space for the hypervisor near the top + ; of the address space (last 4MB is mapped). + ; + and byte [bx - 08h], 0feh + and byte [bx - 0ch], 0feh + and byte [bx - 10h], 0feh + and byte [bx - 14h], 0feh +%endif + + pop ds + ret +ENDPROC bs2InitPagedProtMode +%endif ; BS2_INC_CMN_PP + + +%ifdef BS2_INC_CMN_PAE_LM +;; +; Initializes the PAE page directories. +; +; Assumes ds is set to BS2_PXX_SEL already and that edx is zero. +; +; @uses ebx, esi +; @internal +; +BEGINPROC bs2InitPaePageDirs + mov esi, X86_PDE4M_P | X86_PDE4M_RW | X86_PDE4M_PS | X86_PDE4M_US + mov ebx, BS2_PXX_OFF(BS2_PAE_PD_ADDR) +.pd_loop: + mov [bx], esi + mov [bx + 4], edx + add esi, _2M + add bx, 8 + test bx, 0fffh + jnz .pd_loop + cmp bx, BS2_PXX_OFF(BS2_PAE_PD_ADDR + 4*_4K) + jne .pd_loop + +%ifdef BS2_WITH_RAW_MODE + ; + ; Make sure there is some free space for the hypervisor near the top + ; of the address space (last 4MB is mapped). + ; + and byte [bx - 10h], 0feh + and byte [bx - 18h], 0feh + and byte [bx - 20h], 0feh + and byte [bx - 28h], 0feh +%endif + + ret +ENDPROC bs2InitPaePageDirs +%endif ; BS2_INC_CMN_PAE_LM + + +%ifdef BS2_INC_CMN_PAE +;; +; Initializes the PAE protected mode structures during init. +; +; @uses edx, ebx, esi. +; +BEGINCODELOW +BITS 16 +BEGINPROC bs2InitPaeProtMode + push ds + + mov dx, BS2_PXX_SEL + mov ds, dx + xor edx, edx + + ; + ; Join paths with long mode. + ; + call bs2InitPaePageDirs + + ; + ; Create the page directory pointer table. + ; + mov ebx, BS2_PXX_OFF(BS2_PAE_PDP_ADDR) + mov dword [bx], (BS2_PAE_PD_ADDR ) | X86_PDPE_P + mov dword [bx + 04h], edx + mov dword [bx + 08h], (BS2_PAE_PD_ADDR + 1000h) | X86_PDPE_P + mov dword [bx + 0ch], edx + mov dword [bx + 10h], (BS2_PAE_PD_ADDR + 2000h) | X86_PDPE_P + mov dword [bx + 14h], edx + mov dword [bx + 18h], (BS2_PAE_PD_ADDR + 3000h) | X86_PDPE_P + mov dword [bx + 1ch], edx + + pop ds + ret +ENDPROC bs2InitPaeProtMode +%endif ; BS2_INC_CMN_PAE + + +%ifdef BS2_INC_CMN_LM +;; +; Initializes the long mode structures during init. +; +; @uses edx, ebx, esi +; +BEGINCODELOW +BITS 16 +BEGINPROC bs2InitLongMode + push ds + + mov dx, BS2_PXX_SEL + mov ds, dx + xor edx, edx + + ; + ; Join paths with the PAE code. + ; + call bs2InitPaePageDirs + + ; + ; Create the long mode page directory pointer table. + ; + mov ebx, BS2_PXX_OFF(BS2_LM_PDP_ADDR) +.pdptr_loop: + mov dword [bx], (BS2_PAE_PD_ADDR ) | X86_PDPE_P | X86_PDPE_RW | X86_PDPE_US + mov dword [bx + 04h], edx + mov dword [bx + 08h], (BS2_PAE_PD_ADDR + 1000h) | X86_PDPE_P | X86_PDPE_RW | X86_PDPE_US + mov dword [bx + 0ch], edx + mov dword [bx + 10h], (BS2_PAE_PD_ADDR + 2000h) | X86_PDPE_P | X86_PDPE_RW | X86_PDPE_US + mov dword [bx + 14h], edx + mov dword [bx + 18h], (BS2_PAE_PD_ADDR + 3000h) | X86_PDPE_P | X86_PDPE_RW | X86_PDPE_US + mov dword [bx + 1ch], edx + add bx, 20h + test bx, 0fffh + jnz .pdptr_loop + + ; + ; Set up the page map level 4 table, all entries mapping the same PDPTR. + ; + mov ebx, BS2_PXX_OFF(BS2_LM_PML4_ADDR) +.pml4_loop: + mov dword [bx], BS2_LM_PDP_ADDR | X86_PML4E_P | X86_PML4E_RW | X86_PML4E_US + mov dword [bx + 4], edx + add bx, 8 + test bx, 0fffh + jnz .pml4_loop + + pop ds + ret +ENDPROC bs2InitLongMode +%endif ; BS2_INC_CMN_LM + + + +; +; Routines for entering the different modes. +; + +%ifdef BS2_INC_RM +;; +; Dummy. +BEGINCODELOW +BITS 16 +BEGINPROC Bs2EnterMode_rm_rm + ret +ENDPROC Bs2EnterMode_rm_rm +%endif ; BS2_INC_RM + + +%ifdef BS2_INC_PE16 +;; +; Enters unpaged protected mode from real mode (cs = 0). +; +; @returns cs,ds,ss,es,gs,fs loaded with 16-bit selectors. +; ebp and esp converted to 32/16-bit. +; All other registers are preserved. +; @uses nothing +; +BEGINCODELOW +BITS 16 +BEGINPROC Bs2EnterMode_rm_pe16 + push eax + pushfd + cli +%ifndef BS2_NOINC_COMMON + push word SetCpuModeGlobals_pe16 +%endif + + ; + ; Switch to protected mode. + ; + xor ax, ax + mov ds, ax + lgdt [gdtr] +%ifdef BS2_WITH_TRAPS + lidt [idtr_32bit] +%elifdef BS2_WITH_RAW_MODE + lidt [idtr_dummy_32bit] +%else + lidt [idtr_null] +%endif + + mov eax, cr0 + or eax, X86_CR0_PE + and eax, 0ffffffffh - X86_CR0_PG + mov cr0, eax + jmp far BS2_SEL_CS16:bs2ProtModeCode16Start_p16 +ENDPROC Bs2EnterMode_rm_pe16 +%endif ; BS2_INC_PE16 + + +%ifdef BS2_INC_PE32 +;; +; Enters unpaged protected mode from real mode (cs = 0). +; +; @returns cs,ds,ss,es,gs,fs loaded with 32-bit selectors. +; ebp and esp converted to 32-bit. +; All other registers are preserved. +; @uses nothing +; +BEGINCODELOW +BITS 16 +BEGINPROC Bs2EnterMode_rm_pe32 + push word 0 + push eax + pushfd + cli +%ifndef BS2_NOINC_COMMON + push dword SetCpuModeGlobals_pe32 +%endif + + ; Do the mode switch. + xor ax, ax + mov ds, ax + lgdt [gdtr] +%ifdef BS2_WITH_TRAPS + lidt [idtr_32bit] +%elifdef BS2_WITH_RAW_MODE + lidt [idtr_dummy_32bit] +%else + lidt [idtr_null] +%endif + + mov eax, cr0 + or eax, X86_CR0_PE + and eax, 0ffffffffh - X86_CR0_PG + mov cr0, eax + jmp far BS2_SEL_CS32:bs2ProtModeCode32Start_p32 +ENDPROC Bs2EnterMode_rm_pe32 +%endif ; BS2_INC_PE32 + + +;; @todo BS2_INC_PEV86 + + +%ifdef BS2_INC_PP16 +;; +; Enters paged protected mode from real mode (cs = 0). +; +; @returns cs,ds,ss,es,gs,fs loaded with 16-bit selectors. +; ebp and esp converted to 16/32-bit. +; All other registers are preserved. +; @uses nothing +; +BEGINCODELOW +BITS 16 +BEGINPROC Bs2EnterMode_rm_pp16 + push eax + pushfd + cli +%ifndef BS2_NOINC_COMMON + push word SetCpuModeGlobals_pp16 +%endif + + ; Do the mode switch. + xor ax, ax + mov ds, ax + lgdt [gdtr] +%ifdef BS2_WITH_TRAPS + lidt [idtr_32bit] +%elifdef BS2_WITH_RAW_MODE + lidt [idtr_dummy_32bit] +%else + lidt [idtr_null] +%endif + + mov eax, BS2_32B_PD_ADDR + mov cr3, eax +%ifdef BS2_WITH_TRAPS + mov [bs2Tss32BitDf + BS2_TSS32_CR3_OFF], eax +%endif + + mov eax, cr4 + or eax, X86_CR4_PSE + and eax, ~X86_CR4_PAE + mov cr4, eax + + mov eax, cr0 + or eax, X86_CR0_PE | X86_CR0_PG | X86_CR0_WP + mov cr0, eax + jmp far BS2_SEL_CS16:bs2ProtModeCode16Start_p16 +ENDPROC Bs2EnterMode_rm_pp16 +%endif ; BS2_INC_PP16 + + +%ifdef BS2_INC_PP32 +;; +; Enters paged protected mode from real mode (cs = 0). +; +; @returns cs,ds,ss,es,gs,fs loaded with 32-bit selectors. +; ebp and esp converted to 32-bit. +; All other registers are preserved. +; @uses nothing +; +BEGINCODELOW +BITS 16 +BEGINPROC Bs2EnterMode_rm_pp32 + push word 0 + push eax + pushfd + cli +%ifndef BS2_NOINC_COMMON + push dword SetCpuModeGlobals_pp32 +%endif + + ; Do the mode switch. + xor ax, ax + mov ds, ax + lgdt [gdtr] +%ifdef BS2_WITH_TRAPS + lidt [idtr_32bit] +%elifdef BS2_WITH_RAW_MODE + lidt [idtr_dummy_32bit] +%else + lidt [idtr_null] +%endif + + mov eax, BS2_32B_PD_ADDR + mov cr3, eax +%ifdef BS2_WITH_TRAPS + mov [bs2Tss32BitDf + BS2_TSS32_CR3_OFF], eax +%endif + + mov eax, cr4 + or eax, X86_CR4_PSE + and eax, ~X86_CR4_PAE + mov cr4, eax + + mov eax, cr0 + or eax, X86_CR0_PE | X86_CR0_PG | X86_CR0_WP + mov cr0, eax + jmp far BS2_SEL_CS32:bs2ProtModeCode32Start_p32 +ENDPROC Bs2EnterMode_rm_pp32 +%endif ; BS2_INC_PP16 + + +;; @todo BS2_INC_PPV86 + + +%ifdef BS2_INC_PAE16 +;; +; Enters PAE protected mode from real mode (cs = 0). +; +; @returns cs,ds,ss,es,gs,fs loaded with 16-bit selectors. +; ebp and esp converted to 16/32-bit. +; All other registers are preserved. +; @uses nothing +; +BEGINCODELOW +BITS 16 +BEGINPROC Bs2EnterMode_rm_pae16 + push eax + pushfd + cli +%ifndef BS2_NOINC_COMMON + push word SetCpuModeGlobals_pae16 +%endif + + ; Do the mode switch. + xor ax, ax + mov ds, ax + lgdt [gdtr] +%ifdef BS2_WITH_TRAPS + lidt [idtr_32bit] +%elifdef BS2_WITH_RAW_MODE + lidt [idtr_dummy_32bit] +%else + lidt [idtr_null] +%endif + + mov eax, BS2_PAE_PDP_ADDR + mov cr3, eax +%ifdef BS2_WITH_TRAPS + mov [bs2Tss32BitDf + BS2_TSS32_CR3_OFF], eax +%endif + + mov eax, cr4 + or eax, X86_CR4_PAE | X86_CR4_PSE + mov cr4, eax + + mov eax, cr0 + or eax, X86_CR0_PE | X86_CR0_PG | X86_CR0_WP + mov cr0, eax + jmp far BS2_SEL_CS16:bs2ProtModeCode16Start_p16 +ENDPROC Bs2EnterMode_rm_pae16 +%endif ; BS2_INC_PAE16 + + +%ifdef BS2_INC_PAE32 +;; +; Enters PAE protected mode from real mode (cs = 0). +; +; @returns cs,ds,ss,es,gs,fs loaded with 32-bit selectors. +; ebp and esp converted to 32-bit. +; All other registers are preserved. +; @uses nothing +; +BEGINCODELOW +BITS 16 +BEGINPROC Bs2EnterMode_rm_pae32 + push word 0 + push eax + pushfd + cli +%ifndef BS2_NOINC_COMMON + push dword SetCpuModeGlobals_pae32 +%endif + + ; Do the mode switch. + xor ax, ax + mov ds, ax + lgdt [gdtr] +%ifdef BS2_WITH_TRAPS + lidt [idtr_32bit] +%elifdef BS2_WITH_RAW_MODE + lidt [idtr_dummy_32bit] +%else + lidt [idtr_null] +%endif + + mov eax, BS2_PAE_PDP_ADDR + mov cr3, eax +%ifdef BS2_WITH_TRAPS + mov [bs2Tss32BitDf + BS2_TSS32_CR3_OFF], eax +%endif + + mov eax, cr4 + or eax, X86_CR4_PAE | X86_CR4_PSE + mov cr4, eax + + mov eax, cr0 + or eax, X86_CR0_PE | X86_CR0_PG | X86_CR0_WP + mov cr0, eax + jmp far BS2_SEL_CS32:bs2ProtModeCode32Start_p32 +ENDPROC Bs2EnterMode_rm_pae32 +%endif ; BS2_INC_PAE32 + + +;; @todo BS2_INC_PAEV86 + + +%ifdef BS2_INC_LM16 +;; +; Enters long mode from real mode (cs = 0). +; +; @returns cs,ds,ss,es,gs,fs loaded with 16-bit selectors. +; rbp and rsp converted to 16/32/64-bit. +; All other registers are preserved. +; @uses nothing +; +BEGINCODELOW +BITS 16 +BEGINPROC Bs2EnterMode_rm_lm16 + call Bs2EnterMode_rm_lm64 +BITS 64 + call Bs2Thunk_lm64_lm16 +BITS 16 + ret +ENDPROC Bs2EnterMode_rm_lm16 +%endif ; BS2_INC_LM16 + + +%ifdef BS2_INC_LM32 +;; +; Enters long mode from real mode (cs = 0). +; +; @returns cs,ds,ss,es,gs,fs loaded with 32-bit selectors. +; rbp and rsp converted to 16/32/64-bit. +; All other registers are preserved. +; @uses nothing +; +BEGINCODELOW +BITS 16 +BEGINPROC Bs2EnterMode_rm_lm32 + ; Change the return address into a 32-bit one. + push word 0 ; Reserved 2 extra bytes for 32-bit return address. + push eax ; Save eax. + movzx eax, word [esp + 6h] ; Read narrow return address. + mov [esp + 4h], eax ; Store wide return address. + pop eax ; Restore eax. + + ; Do the mode switch and thunking. + call Bs2EnterMode_rm_lm64 +BITS 64 + call Bs2Thunk_lm64_lm32 +BITS 32 + ret +ENDPROC Bs2EnterMode_rm_lm32 +%endif ; BS2_INC_LM32 + + +%ifdef BS2_INC_LM64 +;; +; Enters long mode from real mode (cs = 0). +; +; @returns cs,ds,ss,es,gs,fs loaded with 64-bit selectors. +; rbp and rsp converted to 64-bit. +; All other registers are preserved. +; @uses nothing +; +BEGINCODELOW +BITS 16 +BEGINPROC Bs2EnterMode_rm_lm64 + push word 0 ; reserve bytes for 64-bit return address. + push dword 0 + push dword 0 ; rax + push eax + push dword 0 ; rcx + push ecx + push dword 0 ; rdx + push edx + push dword 0 ; rflags + pushfd + cli + + ; Fix the return address. + mov ax, [esp + 20h + 6h] + mov word [esp + 20h + 6h], 0 + mov [esp + 20h], ax + + ; + ; Switch to long mode. + ; + xor ax, ax + mov ds, ax + lgdt [gdtr] +%ifdef BS2_WITH_TRAPS + lidt [idtr_64bit] +%else + lidt [idtr_null] +%endif + + mov eax, BS2_LM_PML4_ADDR + mov cr3, eax + + mov eax, cr4 + or eax, X86_CR4_PAE | X86_CR4_PSE + mov cr4, eax + + mov ecx, MSR_K6_EFER + rdmsr + or eax, MSR_K6_EFER_LME + wrmsr + + mov eax, cr0 + or eax, X86_CR0_PE | X86_CR0_PG | X86_CR0_WP + mov cr0, eax + jmp far BS2_SEL_CS64:.code64_start + +BITS 64 +.code64_start: + mov eax, BS2_SEL_DS64 + mov ds, ax + mov es, ax + mov fs, ax + mov gs, ax + mov ax, BS2_SEL_SS64 + mov ss, ax +%ifdef BS2_WITH_TRAPS + btr dword [bs2Gdt + BS2_SEL_TSS64 + 32/8], 1+8 ; busy -> avail + %ifndef BS2_WITH_MANUAL_LTR + mov ax, BS2_SEL_TSS64 + ltr ax + %endif +%endif + + and ebp, 0ffffh + and esp, 0ffffh + and edi, 0ffffffffh + and esi, 0ffffffffh + and ebx, 0ffffffffh + +%ifndef BS2_NOINC_COMMON + call SetCpuModeGlobals_lm64 +%endif + + popf + pop rdx + pop rcx + pop rax + ret +ENDPROC Bs2EnterMode_rm_lm64 +%endif ; BS2_INC_PAE32 + + + +%ifdef BS2_INC_CMN_P16 +;; +; Code shared by the three 16-bit protected mode switchers. +; +; @internal +; +BEGINCODELOW +BITS 16 +BEGINPROC bs2ProtModeCode16Start_p16 + ; Initialize the registers. + mov ax, BS2_SEL_DS16 + mov ds, ax + mov es, ax + mov fs, ax + mov gs, ax + mov ax, BS2_SEL_SS16 + mov ss, ax + and esp, 0ffffh + and ebp, 0ffffh +%ifdef BS2_WITH_TRAPS + btr word [bs2Gdt + BS2_SEL_TSS32 + 32/8], 1+8 ; busy -> avail + btr word [bs2Gdt + BS2_SEL_TSS32_DF + 32/8], 1+8 ; busy -> avail + %ifndef BS2_WITH_MANUAL_LTR + mov ax, BS2_SEL_TSS32 + ltr ax + %endif +%endif + +%ifndef BS2_NOINC_COMMON + ; Set up mode specific global variables. + pop ax + call ax +%endif + + popfd + pop eax + ret +ENDPROC bs2ProtModeCode16Start_p16 +%endif ; BS2_INC_CMN_P16 + + +%ifdef BS2_INC_CMN_P32 +;; +; Code shared by the three 32-bit protected mode switchers. +; +; @internal +; +BEGINCODELOW +BITS 32 +BEGINPROC bs2ProtModeCode32Start_p32 + ; Initialize the registers. + mov ax, BS2_SEL_DS32 + mov ds, ax + mov es, ax + mov fs, ax + mov gs, ax + mov ax, BS2_SEL_SS32 + mov ss, ax + and esp, 0ffffh + and ebp, 0ffffh +%ifdef BS2_WITH_TRAPS + btr dword [bs2Gdt + BS2_SEL_TSS32 + 32/8], 1+8 ; busy -> avail + btr dword [bs2Gdt + BS2_SEL_TSS32_DF + 32/8], 1+8 ; busy -> avail + %ifndef BS2_WITH_MANUAL_LTR + mov ax, BS2_SEL_TSS32 + ltr ax + %endif +%endif + +%ifndef BS2_NOINC_COMMON + ; Set up mode specific global variables. + pop eax + call eax +%endif + + ; Make the return address 32-bit and then return. + movzx eax, word [esp + 0ah] + mov [esp + 8h], eax + popfd + pop eax + ret +ENDPROC bs2ProtModeCode32Start_p32 +%endif ; BS2_INC_CMN_P32 + + + +; +; Routines for exitting the different modes. +; + + +%ifdef BS2_INC_RM +;; +; Dummy. +BEGINCODELOW +BITS 16 +BEGINPROC Bs2ExitMode_rm + ret +ENDPROC Bs2ExitMode_rm +%endif ; BS2_INC_RM + + +%ifdef BS2_INC_PE16 +;; +; See bs2ExitMode_p16. +BEGINCODELOW +BITS 16 +BEGINPROC Bs2ExitMode_pe16 + push bs2ExitModeCleanupNop_rm + jmp bs2ExitMode_p16 +ENDPROC Bs2ExitMode_pe16 +%endif ; BS2_INC_PE16 + + +%ifdef BS2_INC_PE32 +;; +; See bs2ExitMode_p32. +BEGINCODEHIGH +BITS 32 +BEGINPROC Bs2ExitMode_pe32 + push bs2ExitModeCleanupNop_rm + jmp bs2ExitMode_p32 +ENDPROC Bs2ExitMode_pe32 +%endif ; BS2_INC_PE32 + + +%ifdef BS2_INC_PEV86 +;; +; See Bs2ExitMode_v86. +BEGINCODELOW +BITS 16 +BEGINPROC Bs2ExitMode_pev86 + push bs2ExitModeCleanupNop_rm + jmp Bs2ExitMode_pv86 +ENDPROC Bs2ExitMode_pev86 +%endif ; BS2_INC_PEV86 + + +%ifdef BS2_INC_PP16 +;; +; See bs2ExitMode_p16. +BEGINCODELOW +BITS 16 +BEGINPROC Bs2ExitMode_pp16 + push bs2ExitModeCleanupNop_rm + jmp bs2ExitMode_p16 +ENDPROC Bs2ExitMode_pp16 +%endif ; BS2_INC_PP16 + + +%ifdef BS2_INC_PP32 +;; +; See bs2ExitMode_p32. +BEGINCODEHIGH +BITS 32 +BEGINPROC Bs2ExitMode_pp32 + push bs2ExitModeCleanupNop_rm + jmp bs2ExitMode_p32 +ENDPROC Bs2ExitMode_pp32 +%endif ; BS2_INC_PP32 + + +%ifdef BS2_INC_PPV86 +;; +; See Bs2ExitMode_v86. +BEGINCODELOW +BITS 16 +BEGINPROC Bs2ExitMode_ppv86 + push bs2ExitModeCleanupNop_rm + jmp Bs2ExitMode_pv86 +ENDPROC Bs2ExitMode_ppv86 +%endif ; BS2_INC_PPV86 + + + +%ifdef BS2_INC_PAE16 +;; +; See bs2ExitMode_p16. +BEGINCODELOW +BITS 16 +BEGINPROC Bs2ExitMode_pae16 + push bs2ExitModeCleanupPae_rm + jmp bs2ExitMode_p16 +ENDPROC Bs2ExitMode_pae16 +%endif ; BS2_INC_pae16 + + +%ifdef BS2_INC_PAE32 +;; +; See bs2ExitMode_p32. +BEGINCODEHIGH +BITS 32 +BEGINPROC Bs2ExitMode_pae32 + push bs2ExitModeCleanupPae_rm + jmp bs2ExitMode_p32 +ENDPROC Bs2ExitMode_pae32 +%endif ; BS2_INC_PAE32 + + +%ifdef BS2_INC_PAEV86 +;; +; See Bs2ExitMode_v86. +BEGINCODELOW +BITS 16 +BEGINPROC Bs2ExitMode_paev86 + push bs2ExitModeCleanupPae_rm + jmp Bs2ExitMode_pv86 +ENDPROC Bs2ExitMode_paev86 +%endif ; BS2_INC_PAEV86 + + +%ifdef BS2_INC_LM16 +;; +; See bs2ExitMode_p16. +BEGINCODELOW +BITS 16 +BEGINPROC Bs2ExitMode_lm16 + push bs2ExitModeCleanupLm_rm + jmp bs2ExitMode_p16 +ENDPROC Bs2ExitMode_lm16 +%endif ; BS2_INC_lm16 + + +%ifdef BS2_INC_LM32 +;; +; See bs2ExitMode_p32. +BEGINCODEHIGH +BITS 32 +BEGINPROC Bs2ExitMode_lm32 + push bs2ExitModeCleanupLm_rm + jmp bs2ExitMode_p32 +ENDPROC Bs2ExitMode_lm32 +%endif ; BS2_INC_LM32 + + +%ifdef BS2_INC_LM64 +;; +; See Bs2ExitMode_v86. +BEGINCODELOW +BITS 64 +BEGINPROC Bs2ExitMode_lm64 + call Bs2Thunk_lm64_lm16 +BITS 16 + pop dword [esp] + pop word [esp] + push bs2ExitModeCleanupLm_rm + jmp bs2ExitMode_p16 +ENDPROC Bs2ExitMode_lm64 +%endif ; BS2_INC_LM64 + + +; Isn't there a better way to do this in yasm? +%ifdef BS2_INC_CMN_P16 + %define BS2_INC_BS2EXITMODE_P16 +%elifdef BS2_INC_CMN_LM + %define BS2_INC_BS2EXITMODE_P16 +%elifdef BS2_INC_CMN_P32 + %define BS2_INC_BS2EXITMODE_P16 +%endif + +%ifdef BS2_INC_BS2EXITMODE_P16 +;; +; Exit 16-bit protected or long mode (cs = CS16, ss = SS16). +; +; @returns cs,ds,ss,es,gs,fs loaded with the 0 selector. +; All other registers are preserved. +; @uses nothing +; +BEGINCODELOW +BITS 16 +BEGINPROC bs2ExitMode_p16 + push eax + pushfd + cli + + ; Make sure we've got the right SS and CS values (paranoia). + mov ax, BS2_SEL_SS16 + mov ss, ax + jmp far BS2_SEL_CS16:.code16_start + +.code16_start: + ; Turn off paging and protected mode. + mov eax, cr0 + and eax, 0ffffffffh - X86_CR0_PE - X86_CR0_PG + mov cr0, eax + jmp far 0000:.real_mode_start + +.real_mode_start: + ; Load the correct real mode segment registers. + xor ax, ax + mov ss, ax + mov ds, ax + mov es, ax + mov fs, ax + mov gs, ax + + ; Load the real mode idtr. + lidt [idtr_real_mode] + + ; Cleanup. + mov ax, [esp + 8h] + call ax + +%ifndef BS2_NOINC_COMMON + ; Set globals. + call SetCpuModeGlobals_rm +%endif + + popfd + pop eax + add sp, 2h ; cleanup routine address + ret +ENDPROC bs2ExitMode_p16 +%endif ; BS2_INC_CMN_P16 + + +%ifdef BS2_INC_CMN_P32 +;; +; Exit 32-bit protected or long mode (cs = CS32, ss = SS32). +; +; The return address as well as the stack registers must be somewhere within +; the first 64KB of the address space. +; +; @returns cs,ds,ss,es,gs,fs loaded with the 0 selector. +; All other registers are preserved. +; @uses nothing +; +BEGINCODELOW +BITS 32 +BEGINPROC bs2ExitMode_p32 + push eax + mov eax, [esp + 8h] ; return address + mov [esp + 0ah], ax + mov eax, [esp + 4h] ; cleanup routine address + mov [esp + 08h], ax + pop eax + add esp, 4h + + call Bs2Thunk_p32_p16 +BITS 16 + jmp bs2ExitMode_p16 +ENDPROC bs2ExitMode_p32 +%endif ; BS2_INC_CMN_P32 + + +;; +; Dummy cleanup routine. +BEGINCODELOW +BITS 16 +BEGINPROC bs2ExitModeCleanupNop_rm + ret +ENDPROC bs2ExitModeCleanupNop_rm + + +%ifdef BS2_INC_CMN_PAE +;; +; Cleans up after leaving PAE mode. +; @uses nothing +BEGINCODELOW +BITS 16 +BEGINPROC bs2ExitModeCleanupPae_rm + push eax + mov eax, cr4 + and eax, ~X86_CR4_PAE + mov cr4, eax + pop eax + ret +ENDPROC bs2ExitModeCleanupPae_rm +%endif + + +%ifdef BS2_INC_CMN_LM +;; +; Cleans up after leaving long mode. +; @uses nothing +BEGINCODELOW +BITS 16 +BEGINPROC bs2ExitModeCleanupLm_rm + push eax + push edx + push ecx + + mov ecx, MSR_K6_EFER + rdmsr + and eax, ~MSR_K6_EFER_LME + wrmsr + + pop ecx + pop edx + pop eax + ret +ENDPROC bs2ExitModeCleanupLm_rm +%endif + + + +; +; Thunking routines for switching between 16/32/64-bit code. +; + + +%ifdef BS2_INC_CMN_PM +;; +; Switches from 32-bit to 16-bit mode ({eip,esp,ebp} < 64KB). +; +; @returns cs,ds,ss,es,gs,fs loaded with 16-bit selectors. +; All other registers are preserved. +; @uses nothing +; +BEGINCODELOW +BITS 32 +BEGINPROC Bs2Thunk_p32_p16 + push eax + pushf + cli + mov ax, BS2_SEL_SS16 + jmp far BS2_SEL_CS16:.code16_start +BITS 16 +.code16_start: + mov ss, ax + mov ax, BS2_SEL_DS16 + mov ds, ax + mov es, ax + mov fs, ax + mov gs, ax + + ; Fix the return address and then return. + mov ax, [esp + 08h] + mov [esp + 0ah], ax + popfd + pop eax + add sp, 2h + ret +ENDPROC Bs2Thunk_p32_p16 + %define Bs2Thunk_p32_pe16 Bs2Thunk_p32_p16 ; Alternative name for TMPL_NM + %define Bs2Thunk_p32_pp16 Bs2Thunk_p32_p16 ; Alternative name for TMPL_NM + %define Bs2Thunk_p32_pae16 Bs2Thunk_p32_p16 ; Alternative name for TMPL_NM +%endif ; BS2_INC_CMN_PM + + +%ifdef BS2_INC_CMN_PM +;; +; Switches from 16-bit to 32-bit mode (cs = CS16, ds = DS16). +; +; @returns cs,ds,ss,es,gs,fs loaded with 32-bit selectors. +; ebp and esp converted to 32bit. +; All other registers are preserved. +; @uses nothing +; +BEGINCODELOW +BITS 16 +BEGINPROC Bs2Thunk_p16_p32 + push word 0 + push eax + pushfd + cli + jmp far BS2_SEL_CS32:.code32_start +BITS 32 +.code32_start: + mov eax, BS2_SEL_SS32 + mov ss, ax + mov ax, BS2_SEL_DS32 + mov ds, ax + mov es, ax + mov fs, ax + mov gs, ax + and ebp, 0ffffh + and esp, 0ffffh + + ; Fix the return address and then return. + movzx eax, word [esp + 0ah] + mov [esp + 08h], eax + popfd + pop eax + ret +ENDPROC Bs2Thunk_p16_p32 + %define Bs2Thunk_p16_pe32 Bs2Thunk_p16_p32 ; Alternative name for TMPL_NM + %define Bs2Thunk_p16_pp32 Bs2Thunk_p16_p32 ; Alternative name for TMPL_NM + %define Bs2Thunk_p16_pae32 Bs2Thunk_p16_p32 ; Alternative name for TMPL_NM +%endif ; BS2_INC_CMN_PM + + +%ifdef BS2_INC_CMN_LM +;; +; Switches from 64-bit to 16-bit mode ({rip,rsp,rbp} < 64KB). +; +; @returns cs,ds,ss,es,gs,fs loaded with 16-bit selectors. +; All other registers are preserved. +; @uses nothing +; +BEGINCODELOW +BITS 64 +BEGINPROC Bs2Thunk_lm64_lm16 + push rax + pushf + cli + mov ax, BS2_SEL_SS16 + push BS2_SEL_CS16 + push .code16_start + retf +BITS 16 +.code16_start: + mov ss, ax + mov ax, BS2_SEL_DS16 + mov ds, ax + mov es, ax + mov fs, ax + mov gs, ax + + ; Fix the return address and then return. + mov ax, [esp + 10h] + mov [esp + 16h], ax + popfd + add sp, 4h + pop eax + add sp, 4h + 6h + ret +ENDPROC Bs2Thunk_lm64_lm16 + %define Bs2Thunk_p64_lm16 Bs2Thunk_lm64_lm16 ; Alternative name for TMPL_NM +%endif ; BS2_INC_CMN_LM + + +%ifdef BS2_INC_LM16 +;; +; Switches from 16-bit to 64-bit mode (cs = CS16, ss = SS16). +; +; @returns cs,ds,ss,es,gs,fs loaded with 64-bit selectors. +; rbp and rsp converted to 16/32/64-bit. +; All other registers are preserved. +; @uses nothing +; +BEGINCODELOW +BITS 16 +BEGINPROC Bs2Thunk_lm16_lm64 + push word 0 + push dword 0 + push dword 0 + push eax + push dword 0 + pushfd + cli + mov eax, BS2_SEL_SS64 + jmp far BS2_SEL_CS64:.code64_start +BITS 64 +.code64_start: + mov ss, ax + mov ax, BS2_SEL_DS64 + mov ds, ax + mov es, ax + mov fs, ax + mov gs, ax + + and ebp, 0ffffh + and esp, 0ffffh + and edi, 0ffffffffh + and esi, 0ffffffffh + and ebx, 0ffffffffh + + ; Fix the return address and then return. + movzx rax, word [rsp + 16h] + mov [rsp + 10h], rax + popf + pop rax + ret +ENDPROC Bs2Thunk_lm16_lm64 + %define Bs2Thunk_p16_lm64 Bs2Thunk_lm16_lm64 ; Alternative name for TMPL_NM +%endif ; BS2_INC_LM16 + + +%ifdef BS2_INC_LM32 +;; +; Switches from 64-bit to 32-bit mode ({rip,rsp,rbp} < 4GB). +; +; @returns cs,ds,ss,es,gs,fs loaded with 32-bit selectors. +; All other registers are preserved. +; @uses nothing +; +BEGINCODEHIGH +BITS 64 +BEGINPROC Bs2Thunk_lm64_lm32 + push rax + pushf + cli + mov ax, BS2_SEL_SS32 + push BS2_SEL_CS32 + push .code32_start + retf +BITS 32 +.code32_start: + mov ss, ax + mov ax, BS2_SEL_DS32 + mov ds, ax + mov es, ax + mov fs, ax + mov gs, ax + + ; Fix the return address and then return. + mov eax, [esp + 10h] + mov [esp + 14h], eax + popfd + mov eax, [esp + 4h] + lea esp, [esp + 10h] + ret +ENDPROC Bs2Thunk_lm64_lm32 + %define Bs2Thunk_p64_lm32 Bs2Thunk_lm64_lm32 ; Alternative name for TMPL_NM +%endif ; BS2_INC_LM32 + + +%ifdef BS2_INC_LM32 +;; +; Switches from 32-bit to 64-bit mode (cs = CS32, ss = SS32). +; +; @returns cs,ds,ss,es,gs,fs loaded with 64-bit selectors. +; rbp and rsp converted to 32/64-bit. +; All other registers are preserved. +; @uses nothing +; +BEGINCODEHIGH +BITS 32 +BEGINPROC Bs2Thunk_lm32_lm64 + push dword 0 + push dword 0 + push eax + push dword 0 + pushfd + cli + mov eax, BS2_SEL_SS64 + jmp far BS2_SEL_CS64:.code64_start +BITS 64 +.code64_start: + mov ss, ax + mov ax, BS2_SEL_DS64 + mov ds, ax + mov es, ax + mov fs, ax + mov gs, ax + + and ebp, 0ffffffffh + and esp, 0ffffffffh + and edi, 0ffffffffh + and esi, 0ffffffffh + and ebx, 0ffffffffh + + ; Fix the return address and then return. + mov eax, [rsp + 14h] + mov [rsp + 10h], rax + popf + pop rax + ret +ENDPROC Bs2Thunk_lm32_lm64 + %define Bs2Thunk_p32_lm64 Bs2Thunk_lm32_lm64 ; Alternative name for TMPL_NM +%endif ; BS2_INC_LM32 + + + + +; +; Routines for checking if mode is supported or not. +; +; @returns al=1 & ZF=0 if supported, al=0 & ZF=1 if not. +; @uses nothing. +; + +; These are easy. +BEGINCODELOW +BITS 16 +BEGINPROC bs2IsModeSupportedYes_rm +GLOBALNAME Bs2IsModeSupported_rm_rm +GLOBALNAME Bs2IsModeSupported_rm_pe16 +GLOBALNAME Bs2IsModeSupported_rm_pe32 +GLOBALNAME Bs2IsModeSupported_rm_pev86 +GLOBALNAME Bs2IsModeSupported_rm_pp16 +GLOBALNAME Bs2IsModeSupported_rm_pp32 +GLOBALNAME Bs2IsModeSupported_rm_ppv86 + mov al, 1 + test al, al + ret +ENDPROC bs2IsModeSupportedYes_rm + + +%ifdef BS2_INC_CMN_PAE +BEGINCODELOW +BITS 16 +BEGINPROC Bs2IsPaeSupported_16 +GLOBALNAME Bs2IsModeSupported_rm_pae16 +GLOBALNAME Bs2IsModeSupported_rm_pae32 +GLOBALNAME Bs2IsModeSupported_rm_paev86 + push eax + push ebx + push ecx + push edx + + mov eax, 0 + cpuid + cmp eax, 1 + jb .no + cmp eax, 1000h + ja .no + + mov eax, 1 + cpuid + test edx, X86_CPUID_FEATURE_EDX_PAE + + pop edx + pop ecx + pop ebx + pop eax + + mov al, 0 + jz .no + mov al, 1 +.no: + ret +ENDPROC Bs2IsPaeSupported_16 +%endif ; BS2_INC_CMN_PAE + + +%ifdef BS2_INC_CMN_LM +BEGINCODELOW +BITS 16 +BEGINPROC Bs2IsLongModeSupported_16 +GLOBALNAME Bs2IsModeSupported_rm_lm16 +GLOBALNAME Bs2IsModeSupported_rm_lm32 +GLOBALNAME Bs2IsModeSupported_rm_lm64 + push eax + push ebx + push ecx + push edx + + mov eax, 080000000h + cpuid + cmp eax, 080000001h + jb .no + cmp eax, 080001000h + ja .no + + mov eax, 080000001h + cpuid + test edx, X86_CPUID_EXT_FEATURE_EDX_LONG_MODE + + pop edx + pop ecx + pop ebx + pop eax + + mov al, 0 + jz .no + mov al, 1 +.no: + ret +ENDPROC Bs2IsLongModeSupported_16 +%endif ; BS2_INC_CMN_LM + + +; +; Include addition init/base code. +; +%ifdef BS2_WITH_TRAPS + %include "bootsector2-common-init-traps.mac" +%endif + + +; +; Include common code. +; +%ifndef BS2_NOINC_COMMON + %include "bootsector2-common-routines.mac" +%endif + +; +; Include trap records if requested. +; +%ifdef BS2_WITH_TRAPRECS + %include "bootsector2-common-traprec.mac" +%endif + +; +; Map stuff for the initial environment. +; +%ifdef BS2_INIT_RM + %define TMPL_RM +%endif +%ifdef BS2_INIT_PE32 + %define TMPL_PE32 +%endif +%ifdef BS2_INIT_PP32 + %define TMPL_PP32 +%endif +%ifdef BS2_INIT_PAE32 + %define TMPL_PAE32 +%endif +%ifdef BS2_INIT_LM64 + %define TMPL_LM64 +%endif +%include "bootsector2-template-header.mac" + + +; +; Where we jump after initialization. +; +TMPL_BEGINCODE +BITS TMPL_BITS +bs2DoneInit: +%ifdef BS2_INIT_SAVE_REGS + mov eax, cr2 + mov [BS2_REG_SAVE_ADDR + BS2REGS.cr2], eax + mov eax, cr3 + mov [BS2_REG_SAVE_ADDR + BS2REGS.cr3], eax + mov eax, cr4 + mov [BS2_REG_SAVE_ADDR + BS2REGS.cr4], eax + mov byte [BS2_REG_SAVE_ADDR + BS2REGS.cBits], 16 + xor eax, eax + mov [cs:BS2_REG_SAVE_ADDR + BS2REGS.cs], ax + mov ax, start + mov [cs:BS2_REG_SAVE_ADDR + BS2REGS.rip], eax +%endif + +%ifdef BS2_WITH_TRAPRECS + ; + ; Install the trap records. + ; + BS2_TRAP_RECS_INSTALL +%endif + + ; + ; Detect the CPU. + ; + xor eax, eax + mov [g_fCpuIntel], al + mov [g_fCpuAmd], al + cpuid + cmp ecx, 0x444d4163 + jne .not_amd + cmp edx, 0x69746e65 + jne .not_amd + cmp ebx, 0x68747541 + jne .not_amd + mov byte [g_fCpuAmd], 1 + jmp .not_intel + +.not_amd: + cmp ecx, 0x6c65746e + jne .not_intel + cmp edx, 0x49656e69 + jne .not_intel + cmp ebx, 0x756e6547 + jne .not_intel + mov byte [g_fCpuIntel], 1 +.not_intel: + + ; + ; Call the user 'main' procedure (shouldn't return). + ; + call main +.panic_again + call Bs2Panic + jmp .panic_again + diff --git a/src/VBox/ValidationKit/bootsectors/bootsector2-common-init-traps.mac b/src/VBox/ValidationKit/bootsectors/bootsector2-common-init-traps.mac new file mode 100644 index 00000000..b39a9206 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bootsector2-common-init-traps.mac @@ -0,0 +1,1609 @@ +; $Id: bootsector2-common-init-traps.mac $ +;; @file +; Common bootsector code init, traps. +; +; This is included from bootsector2-common-init-code.mac and was split out of +; that file to keep the size manageable. +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + +%ifndef BS2_WITH_TRAPS + %error "huh? BS2_WITH_TRAPS is not defined!" +%endif + + +;******************************************************************************* +;* Header Files * +;******************************************************************************* +%include "bootsector2-structures.mac" +%include "bootsector2-api.mac" + + +;******************************************************************************* +;* Global Variables * +;******************************************************************************* +BEGINCODELOW +ALIGNDATA(8) +;; Where to resume execution after a trap (if g_fTrapPrepared is set). +; @internal +g_TrapResumeRIP: + dq 0 +;; Set if we've prepared for a trap. +; @internal +g_fTrapPrepared: + db 0 +;; Benchmark indicator. +; This is set to the expected trap number when we're benchmarking and 0ffh when +; we aren't benchmarking. +; @internal +g_u8TrapBenchmarkNo: + db 0ffh + db 0 ; alignment padding. +;; The last trap number. +GLOBALNAME g_u8LastTrapNo + db 0 +;; The number of traps since last call to Bs2TrapReset. +GLOBALNAME g_u32cTraps + dd 0 +;; The last trap error code. +GLOBALNAME g_u64LastTrapErr + dq 0 +;; The register frame of the last trap (BS2REGS). +GLOBALNAME g_LastTrapRegs + times (BS2REGS_size) db 0 + +;; The RFLAGS/EFLAGS inside last invoked trap handler. +GLOBALNAME g_u64LastTrapHandlerRFlags + dq 0 +;; The CS inside last invoked trap handler. +GLOBALNAME g_u16LastTrapHandlerCS + dw 0 +;; The SS inside last invoked trap handler. +GLOBALNAME g_u16LastTrapHandlerSS + dw 0 + dw 0,0 ; alignment +;; The RSP inside the last invoked trap handler, i.e. when bs2Trap_XX_32bit is +; entered, so including fake error code and vector number. +GLOBALNAME g_u64LastTrapHandlerRSP + dq 0 + +;; +; Pointer to an array of BS2TRAPREC1 records. +GLOBALNAME g_paTrapRecs + dq 0 +;; Number of entries in the array g_paTrapRecs points to. +GLOBALNAME g_cTrapRecs + dd 0 +;; The index of the last BS2TRAPREC1 we hit. +GLOBALNAME g_iTrapRecLast + dd 0 +;; The base address the BS2TRAPREC.offWhere values are relative to. +GLOBALNAME g_pTrapRecBase + dq 0 + + +;; +; Reset all the trap globals to default. +; +; This undos the effect of any previous Bs2TrapPrepare call. +; +; @uses nothing. +; +BEGINCODELOW +BITS 16 +BEGINPROC Bs2TrapReset_rm16 + push xBP + mov xBP, xSP + push ds + push word 0 + pop ds + + mov dword [g_u32cTraps], 0 + mov byte [g_u8LastTrapNo], 0ffh + mov dword [g_u64LastTrapErr], 0 + mov dword [g_u64LastTrapErr + 4], 0 + mov dword [g_TrapResumeRIP], 0 + mov dword [g_TrapResumeRIP + 4], 0 + mov byte [g_u8TrapBenchmarkNo], 0ffh + mov byte [g_fTrapPrepared], 0 + + pop ds + leave + ret +ENDPROC Bs2TrapReset_rm16 + + +;; +; Reset all the trap globals to default. +; +; This undos the effect of any previous Bs2TrapPrepare call. +; +; @uses nothing. +; +BEGINCODELOW +BITS 16 +BEGINPROC Bs2TrapReset_p16 + push ds + push BS2_SEL_DS16 + pop ds + + mov dword [g_u32cTraps], 0 + mov byte [g_u8LastTrapNo], 0ffh + mov dword [g_u64LastTrapErr], 0 + mov dword [g_u64LastTrapErr + 4], 0 + mov dword [g_TrapResumeRIP], 0 + mov dword [g_TrapResumeRIP + 4], 0 + mov byte [g_u8TrapBenchmarkNo], 0ffh + mov byte [g_fTrapPrepared], 0 + + pop ds + ret +ENDPROC Bs2TrapReset_p16 + + + +;; +; Reset all the trap globals to default. +; +; This undos the effect of any previous Bs2TrapPrepare call. +; +; @uses nothing. +; +BEGINCODEHIGH +BITS 32 +BEGINPROC Bs2TrapReset_p32 + push ds + push BS2_SEL_DS32 + pop ds + + mov dword [g_u32cTraps], 0 + mov byte [g_u8LastTrapNo], 0ffh + mov dword [g_u64LastTrapErr], 0 + mov dword [g_u64LastTrapErr + 4], 0 + mov dword [g_TrapResumeRIP], 0 + mov dword [g_TrapResumeRIP + 4], 0 + mov byte [g_u8TrapBenchmarkNo], 0ffh + mov byte [g_fTrapPrepared], 0 + + pop ds + ret +ENDPROC Bs2TrapReset_p32 + + +;; +; Reset all the trap globals to default. +; +; This undos the effect of any previous Bs2TrapPrepare call. +; +; @uses nothing. +; +BEGINCODEHIGH +BITS 64 +BEGINPROC Bs2TrapReset_p64 + mov dword [g_u32cTraps], 0 + mov byte [g_u8LastTrapNo], 0ffh + mov qword [g_u64LastTrapErr], 0 + mov qword [g_TrapResumeRIP], 0 + mov byte [g_u8TrapBenchmarkNo], 0ffh + mov byte [g_fTrapPrepared], 0 + ret +ENDPROC Bs2TrapReset_p64 + + + +;; +; Prepare for a test that will trap. +; +; @param xAX Where to resume after the trap. +; @param dl Set to 0ffh for tests and the expected trap number when +; preparing a benchmark. +; @uses nothing. +; +BEGINCODELOW +BITS 16 +BEGINPROC Bs2TrapPrepare_rm16 + push xBP + mov xBP, xSP + push ds + push word 0 + pop ds + + mov dword [g_u32cTraps], 0 + mov byte [g_u8LastTrapNo], 0ffh + mov dword [g_u64LastTrapErr], 0 + mov dword [g_u64LastTrapErr + 4], 0 + mov word [g_TrapResumeRIP], ax + mov word [g_TrapResumeRIP + 2], 0 + mov dword [g_TrapResumeRIP + 4], 0 + mov byte [g_u8TrapBenchmarkNo], dl + mov byte [g_fTrapPrepared], 1 + + pop ds + leave + ret +ENDPROC Bs2TrapPrepare_rm16 + + +;; +; Prepare for a test that will trap. +; +; @param ax Where to resume after the trap. +; @param dl Set to 0ffh for tests and the expected trap number when +; preparing a benchmark. +; @uses nothing. +; +BEGINCODELOW +BITS 16 +BEGINPROC Bs2TrapPrepare_p16 + push ds + push BS2_SEL_DS16 + pop ds + + mov dword [g_u32cTraps], 0 + mov byte [g_u8LastTrapNo], 0ffh + mov dword [g_u64LastTrapErr], 0 + mov dword [g_u64LastTrapErr + 4], 0 + mov word [g_TrapResumeRIP], ax + mov word [g_TrapResumeRIP + 2], 0 + mov dword [g_TrapResumeRIP + 4], 0 + mov byte [g_u8TrapBenchmarkNo], dl + mov byte [g_fTrapPrepared], 1 + + pop ds + ret +ENDPROC Bs2TrapPrepare_p16 + + +;; +; Prepare for a test that will trap. +; +; @param eax Where to resume after the trap. +; @param dl Set to 0ffh for tests and the expected trap number when +; preparing a benchmark. +; @uses nothing. +; +BEGINCODEHIGH +BITS 32 +BEGINPROC Bs2TrapPrepare_p32 + push ds + push BS2_SEL_DS32 + pop ds + + mov dword [g_u32cTraps], 0 + mov byte [g_u8LastTrapNo], 0ffh + mov dword [g_u64LastTrapErr], 0 + mov dword [g_u64LastTrapErr + 4], 0 + mov dword [g_TrapResumeRIP], eax + mov dword [g_TrapResumeRIP + 4], 0 + mov byte [g_u8TrapBenchmarkNo], dl + mov byte [g_fTrapPrepared], 1 + + pop ds + ret +ENDPROC Bs2TrapPrepare_p32 + + +;; +; Prepare for a test that will trap. +; +; @param rax Where to resume after the trap. +; @param dl Set to 0ffh for tests and the expected trap number when +; preparing a benchmark. +; @uses nothing. +; +BEGINCODEHIGH +BITS 64 +BEGINPROC Bs2TrapPrepare_p64 + mov dword [g_u32cTraps], 0 + mov byte [g_u8LastTrapNo], 0ffh + mov qword [g_u64LastTrapErr], 0 + mov qword [g_TrapResumeRIP], rax + mov byte [g_u8TrapBenchmarkNo], dl + mov byte [g_fTrapPrepared], 1 + ret +ENDPROC Bs2TrapPrepare_p64 + + +BEGINCODELOW ; The TSSes, IDTs and handlers must be 16-bit addressable. + +%ifdef BS2_INC_CMN_PM +; +; 32-bit TSS (X86TSS32). +; +ALIGNDATA(16) +bs2Tss32Bit: + dw 07fffh ; selPrev - Back link to previous task. (static) + dw 0h ; padding1; + dd BS2_R0_STACK_ADDR ; esp0 - Ring-0 stack pointer. (static) + dw BS2_SEL_SS32 ; ss0 + dw 0 ; padding + dd BS2_R1_STACK_ADDR ; esp1 - Ring-1 stack pointer. (static) + dw 0 ; ss1 + dw 0 ; padding + dd BS2_R2_STACK_ADDR ; esp2 - Ring-1 stack pointer. (static) + dw 0 ; ss2 + dw 0 ; padding + dd 0ffffffffh ; cr3 - Page directory for the task. (static) + dd 0 ; eip - EIP before task switch. + dd 0 ; eflags - EFLAGS before task switch. + dd 0 ; eax - EAX before task switch. + dd 0 ; ecx - ECX before task switch. + dd 0 ; edx - EDX before task switch. + dd 0 ; ebx - EBX before task switch. + dd 0 ; esp - ESP before task switch. + dd 0 ; ebp - EBP before task switch. + dd 0 ; esi - ESI before task switch. + dd 0 ; edi - EDI before task switch. + dw 0, 0 ; es,pad - ES before task switch. + dw 0, 0 ; cs,pad - CS before task switch. + dw 0, 0 ; ss,pad - SS before task switch. + dw 0, 0 ; ds,pad - DS before task switch. + dw 0, 0 ; fs,pad - FS before task switch. + dw 0, 0 ; gs,pad - GS before task switch. + dw 0, 0 ; ldt,pad - LDTR before task switch. + dw 0 ; fDebugTrap - Debug trap flag. + dw 7fffh ; offIoBitmap - Offset relative to the TSS of the + ; start of the I/O Bitmap and the end of the + ; interrupt redirection bitmap. + ; IntRedirBitmap - 32 bytes for the virtual interrupt redirection bitmap. (VME) +bs2Tss32BitEnd: +times (68h - (bs2Tss32BitEnd - bs2Tss32Bit)) db 0 +times ((bs2Tss32BitEnd - bs2Tss32Bit) - 68h) db 0 + + +; +; 32-bit TSS for #DF (X86TSS32). +; +ALIGNDATA(16) +bs2Tss32BitDf: + dw 07fffh ; selPrev - Back link to previous task. (static) + dw 0h ; padding1; + dd BS2_DF_R0_STACK_ADDR ; esp0 - Ring-0 stack pointer. (static) + dw BS2_SEL_SS32 ; ss0 + dw 0 ; padding + dd 0 ; esp1 - Ring-1 stack pointer. (static) + dw 0 ; ss1 + dw 0 ; padding + dd 0 ; esp2 - Ring-1 stack pointer. (static) + dw 0 ; ss2 + dw 0 ; padding + dd 0ffffffffh ; cr3 - Page directory for the task. (static) + dd bs2Trap_08h_32bit ; eip - EIP before task switch. */ + dd 0 ; eflags - EFLAGS before task switch. */ + dd 0 ; eax - EAX before task switch. */ + dd 0 ; ecx - ECX before task switch. */ + dd 0 ; edx - EDX before task switch. */ + dd 0 ; ebx - EBX before task switch. */ + dd BS2_DF_R0_STACK_ADDR ; esp - ESP before task switch. */ + dd 0 ; ebp - EBP before task switch. */ + dd 0 ; esi - ESI before task switch. */ + dd 0 ; edi - EDI before task switch. */ + dw BS2_SEL_DS32, 0 ; es,pad - ES before task switch. */ + dw BS2_SEL_CS32, 0 ; cs,pad - CS before task switch. */ + dw BS2_SEL_SS32, 0 ; ss,pad - SS before task switch. */ + dw BS2_SEL_DS32, 0 ; ds,pad - DS before task switch. */ + dw BS2_SEL_DS32, 0 ; fs,pad - FS before task switch. */ + dw BS2_SEL_DS32, 0 ; gs,pad - GS before task switch. */ + dw 0, 0 ; ldt,pad- LDTR before task switch. */ + dw 0 ; fDebugTrap - Debug trap flag. + dw 7fffh ; offIoBitmap - Offset relative to the TSS of the + ; start of the I/O Bitmap and the end of the + ; interrupt redirection bitmap. + ; IntRedirBitmap - 32 bytes for the virtual interrupt redirection bitmap. (VME) +bs2Tss32BitDfEnd: +times (68h - (bs2Tss32BitDfEnd - bs2Tss32BitDf)) db 0 +times ((bs2Tss32BitDfEnd - bs2Tss32BitDf) - 68h) db 0 + + +; +; 32-bit IDT (X86DESCGATE). +; +ALIGNDATA(16) +bs2Idt32bit: + dw bs2Trap_00h_32bit, BS2_SEL_CS32, 08e00h, 00000h ; p=1 dpl=0 type=int32gate + dw bs2Trap_01h_32bit, BS2_SEL_CS32, 08e00h, 00000h ; p=1 dpl=0 type=int32gate + dw bs2Trap_02h_32bit, BS2_SEL_CS32, 08e00h, 00000h ; p=1 dpl=0 type=int32gate +bs2Idt32bit_BP: + dw bs2Trap_03h_32bit, BS2_SEL_CS32, 08e00h, 00000h ; p=1 dpl=0 type=int32gate + dw bs2Trap_04h_32bit, BS2_SEL_CS32, 08e00h, 00000h ; p=1 dpl=0 type=int32gate + dw bs2Trap_05h_32bit, BS2_SEL_CS32, 08e00h, 00000h ; p=1 dpl=0 type=int32gate + dw bs2Trap_06h_32bit, BS2_SEL_CS32, 08e00h, 00000h ; p=1 dpl=0 type=int32gate + dw bs2Trap_07h_32bit, BS2_SEL_CS32, 08e00h, 00000h ; p=1 dpl=0 type=int32gate + dw 0, BS2_SEL_TSS32_DF, 08500h, 00000h ; p=1 dpl=0 type=taskgate + dw bs2Trap_09h_32bit, BS2_SEL_CS32, 08e00h, 00000h ; p=1 dpl=0 type=int32gate + dw bs2Trap_0ah_32bit, BS2_SEL_CS32, 08e00h, 00000h ; p=1 dpl=0 type=int32gate + dw bs2Trap_0bh_32bit, BS2_SEL_CS32, 08e00h, 00000h ; p=1 dpl=0 type=int32gate + dw bs2Trap_0ch_32bit, BS2_SEL_CS32, 08e00h, 00000h ; p=1 dpl=0 type=int32gate + dw bs2Trap_0dh_32bit, BS2_SEL_CS32, 08e00h, 00000h ; p=1 dpl=0 type=int32gate + dw bs2Trap_0eh_32bit, BS2_SEL_CS32, 08e00h, 00000h ; p=1 dpl=0 type=int32gate + dw bs2Trap_0fh_32bit, BS2_SEL_CS32, 08e00h, 00000h ; p=1 dpl=0 type=int32gate + dw bs2Trap_10h_32bit, BS2_SEL_CS32, 08e00h, 00000h ; p=1 dpl=0 type=int32gate + dw bs2Trap_11h_32bit, BS2_SEL_CS32, 08e00h, 00000h ; p=1 dpl=0 type=int32gate + dw bs2Trap_12h_32bit, BS2_SEL_CS32, 08e00h, 00000h ; p=1 dpl=0 type=int32gate + dw bs2Trap_13h_32bit, BS2_SEL_CS32, 08e00h, 00000h ; p=1 dpl=0 type=int32gate + dw bs2Trap_14h_32bit, BS2_SEL_CS32, 08e00h, 00000h ; p=1 dpl=0 type=int32gate + dw bs2Trap_15h_32bit, BS2_SEL_CS32, 08e00h, 00000h ; p=1 dpl=0 type=int32gate + dw bs2Trap_16h_32bit, BS2_SEL_CS32, 08e00h, 00000h ; p=1 dpl=0 type=int32gate + dw bs2Trap_17h_32bit, BS2_SEL_CS32, 08e00h, 00000h ; p=1 dpl=0 type=int32gate + dw bs2Trap_18h_32bit, BS2_SEL_CS32, 08e00h, 00000h ; p=1 dpl=0 type=int32gate + dw bs2Trap_19h_32bit, BS2_SEL_CS32, 08e00h, 00000h ; p=1 dpl=0 type=int32gate + dw bs2Trap_1ah_32bit, BS2_SEL_CS32, 08e00h, 00000h ; p=1 dpl=0 type=int32gate + dw bs2Trap_1bh_32bit, BS2_SEL_CS32, 08e00h, 00000h ; p=1 dpl=0 type=int32gate + dw bs2Trap_1ch_32bit, BS2_SEL_CS32, 08e00h, 00000h ; p=1 dpl=0 type=int32gate + dw bs2Trap_1dh_32bit, BS2_SEL_CS32, 08e00h, 00000h ; p=1 dpl=0 type=int32gate + dw bs2Trap_1eh_32bit, BS2_SEL_CS32, 08e00h, 00000h ; p=1 dpl=0 type=int32gate + dw bs2Trap_1fh_32bit, BS2_SEL_CS32, 08e00h, 00000h ; p=1 dpl=0 type=int32gate + dw bs2TrapService32bit,BS2_SEL_CS32,0ee00h, 00000h, 0, 0, 0, 0 ; p=1 dpl=3 type=int32gate +%define BS2_TRAP_SERVICE_NO 30h +;; @todo +bs2Idt32bitEnd + +; +; 32-bit trap handlers. +; +BITS 32 +%macro bs2Trap_XX_32bit_macro 1 +bs2Trap_ %+ %1 %+ _32bit: + push %1 + jmp bs2Trap_XX_32bit +%endmacro +%macro bs2Trap_XX_32bit_macro_no_err 1 +bs2Trap_ %+ %1 %+ _32bit: + push 0 + push %1 + jmp bs2Trap_XX_32bit +%endmacro + bs2Trap_XX_32bit_macro_no_err 00h + bs2Trap_XX_32bit_macro_no_err 01h + bs2Trap_XX_32bit_macro_no_err 02h + bs2Trap_XX_32bit_macro_no_err 03h + bs2Trap_XX_32bit_macro_no_err 04h + bs2Trap_XX_32bit_macro_no_err 05h + bs2Trap_XX_32bit_macro_no_err 06h + bs2Trap_XX_32bit_macro_no_err 07h + bs2Trap_XX_32bit_macro 08h + bs2Trap_XX_32bit_macro_no_err 09h + bs2Trap_XX_32bit_macro 0ah + bs2Trap_XX_32bit_macro 0bh + bs2Trap_XX_32bit_macro 0ch + bs2Trap_XX_32bit_macro 0dh + bs2Trap_XX_32bit_macro 0eh + bs2Trap_XX_32bit_macro_no_err 0fh + bs2Trap_XX_32bit_macro_no_err 10h + bs2Trap_XX_32bit_macro 11h + bs2Trap_XX_32bit_macro_no_err 12h + bs2Trap_XX_32bit_macro_no_err 13h + bs2Trap_XX_32bit_macro_no_err 14h + bs2Trap_XX_32bit_macro_no_err 15h + bs2Trap_XX_32bit_macro_no_err 16h + bs2Trap_XX_32bit_macro_no_err 17h + bs2Trap_XX_32bit_macro_no_err 18h + bs2Trap_XX_32bit_macro_no_err 19h + bs2Trap_XX_32bit_macro_no_err 1ah + bs2Trap_XX_32bit_macro_no_err 1bh + bs2Trap_XX_32bit_macro_no_err 1ch + bs2Trap_XX_32bit_macro_no_err 1dh + bs2Trap_XX_32bit_macro_no_err 1eh + bs2Trap_XX_32bit_macro_no_err 1fh + +;; +; Common 32-bit trap handler. +; +; return GS ebp + 2ch - v86 +; return FS ebp + 28h - v86 +; return DS ebp + 24h - v86 +; return ES ebp + 20h - v86 +; return SS ebp + 1ch - higher privilege +; return ESP ebp + 18h - higher privilege +; return EFLAGS ebp + 14h +; return CS ebp + 10h +; return EIP ebp + 0ch +; error code ebp + 08h +; vector # ebp + 04h +BITS 32 +BEGINCODEHIGH +BEGINPROC bs2Trap_XX_32bit + push ebp ; ebp + 00h + mov ebp, esp + pushfd ; ebp - 04h + push eax ; ebp - 08h + push ebx ; ebp - 0ch + push ecx ; ebp - 10h + push ds ; ebp - 14h + + mov eax, ss ; load flat DS. Using SS here because of conforming IDTE.CS tests. + mov ds, ax + + pushfd ; Clear the AC flag. + and dword [esp], ~X86_EFL_AC + popfd + + ; + ; Benchmark mode? Then resume the action right away! + ; + mov eax, [ebp + 04h] + cmp [g_u8TrapBenchmarkNo], al + jne .test_mode + cmp byte [g_fTrapPrepared], 0 + je .test_mode + mov eax, [g_TrapResumeRIP] + mov [ebp + 0ch], eax + + pop ds + pop ecx + pop ebx + ;pop eax + ;popfd + leave + add esp, 08h ; Skip the vector # and error code. + xor eax, eax + iret + + + ; + ; Update the globals. + ; +.test_mode: + xor ecx, ecx ; zero register + inc dword [g_u32cTraps] + mov eax, [ebp + 04h] + mov [g_u8LastTrapNo], al + mov eax, [ebp + 08h] + mov [g_u64LastTrapErr], eax + mov [g_u64LastTrapErr + 4], ecx + mov eax, [ebp - 04h] + mov [g_u64LastTrapHandlerRFlags], eax + mov dword [g_u64LastTrapHandlerRFlags + 4], ecx + mov ax, cs + mov [g_u16LastTrapHandlerCS], ax + mov ax, ss + mov [g_u16LastTrapHandlerSS], ax + lea eax, [ebp + 4] + mov [g_u64LastTrapHandlerRSP], eax + mov [g_u64LastTrapHandlerRSP + 4], ecx + + ; + ; Save the registers. + ; + lea ebx, [g_LastTrapRegs] + mov eax, [ebp - 08h] + mov [ebx + BS2REGS.rax], eax + mov [ebx + BS2REGS.rax + 4], ecx + mov eax, [ebp - 0ch] + mov [ebx + BS2REGS.rbx], eax + mov [ebx + BS2REGS.rbx + 4], ecx + mov eax, [ebp - 10h] + mov [ebx + BS2REGS.rcx], eax + mov [ebx + BS2REGS.rcx + 4], ecx + mov [ebx + BS2REGS.rdx], edx + mov [ebx + BS2REGS.rdx + 4], ecx + mov [ebx + BS2REGS.rdi], edi + mov [ebx + BS2REGS.rdi + 4], ecx + mov [ebx + BS2REGS.rsi], esi + mov [ebx + BS2REGS.rsi + 4], ecx + mov eax, [ebp] + mov [ebx + BS2REGS.rbp], eax + mov [ebx + BS2REGS.rbp + 4], ecx + mov eax, [ebp + 0ch] + mov [ebx + BS2REGS.rip], eax + mov [ebx + BS2REGS.rip + 4], ecx + mov [ebx + BS2REGS.r8], ecx + mov [ebx + BS2REGS.r8 + 4], ecx + mov [ebx + BS2REGS.r9], ecx + mov [ebx + BS2REGS.r9 + 4], ecx + mov [ebx + BS2REGS.r10], ecx + mov [ebx + BS2REGS.r10 + 4], ecx + mov [ebx + BS2REGS.r11], ecx + mov [ebx + BS2REGS.r11 + 4], ecx + mov [ebx + BS2REGS.r12], ecx + mov [ebx + BS2REGS.r12 + 4], ecx + mov [ebx + BS2REGS.r13], ecx + mov [ebx + BS2REGS.r13 + 4], ecx + mov [ebx + BS2REGS.r14], ecx + mov [ebx + BS2REGS.r14 + 4], ecx + mov [ebx + BS2REGS.r15], ecx + mov [ebx + BS2REGS.r15 + 4], ecx + mov eax, [ebp + 14h] + mov [ebx + BS2REGS.rflags], eax + mov [ebx + BS2REGS.rflags+4],ecx + mov eax, [ebp + 10h] + mov [ebx + BS2REGS.cs], ax + mov [ebx + BS2REGS.cBits], byte 32 + + ; Part of the stack varies depending on the trap context. + test dword [ebx + BS2REGS.rflags], X86_EFL_VM + jnz .v86 + test ax, 7h + jz .ring0 + +.ring0: + lea eax, [ebp + 18h] + mov [ebx + BS2REGS.rsp], eax + mov [ebx + BS2REGS.rsp + 4], ecx + mov [ebx + BS2REGS.ss], ss + mov eax, [ebp - 14h] + mov [ebx + BS2REGS.ds], ax + mov [ebx + BS2REGS.es], es + mov [ebx + BS2REGS.fs], fs + mov [ebx + BS2REGS.gs], gs + jmp .do_crX + +.higher_privilege: + mov eax, [ebp + 18h] + mov [ebx + BS2REGS.rsp], eax + mov [ebx + BS2REGS.rsp + 4], ecx + mov eax, [ebp + 20h] + mov [ebx + BS2REGS.ss], ax + mov eax, [ebp - 14h] + mov [ebx + BS2REGS.ds], ax + mov [ebx + BS2REGS.es], es + mov [ebx + BS2REGS.fs], fs + mov [ebx + BS2REGS.gs], gs + jmp .do_crX + +.v86: + mov eax, [ebp + 18h] + mov [ebx + BS2REGS.rsp], eax + mov [ebx + BS2REGS.rsp + 4], ecx + mov eax, [ebp + 1ch] + mov [ebx + BS2REGS.ss], ax + mov eax, [ebp + 24h] + mov [ebx + BS2REGS.ds], ax + mov eax, [ebp + 20h] + mov [ebx + BS2REGS.es], ax + mov eax, [ebp + 28h] + mov [ebx + BS2REGS.fs], ax + mov eax, [ebp + 2ch] + mov [ebx + BS2REGS.gs], ax + ;jmp .do_crX + +.do_crX: + ; The CRx registers are only accessible from ring-0 (CS=conforming, CPL < 0) + test byte [ebx + BS2REGS.ss], 3 + jnz .skip_crX + mov eax, cr0 + mov [ebx + BS2REGS.cr0], eax + mov [ebx + BS2REGS.cr0 + 4], ecx + mov eax, cr2 + mov [ebx + BS2REGS.cr2], eax + mov [ebx + BS2REGS.cr2 + 4], ecx + mov eax, cr3 + mov [ebx + BS2REGS.cr3], eax + mov [ebx + BS2REGS.cr3 + 4], ecx + mov eax, cr4 + mov [ebx + BS2REGS.cr4], eax + mov [ebx + BS2REGS.cr4 + 4], ecx + mov [ebx + BS2REGS.cr8], ecx + mov [ebx + BS2REGS.cr8 + 4], ecx +.skip_crX: + + ; + ; Advance to a prepared resume position or panic. + ; + cmp byte [g_fTrapPrepared], 0 + je .no_resume_pos + mov byte [g_fTrapPrepared], 0 + mov eax, [g_TrapResumeRIP] + mov [ebp + 0ch], eax + +.resume: +%ifdef BS2_WITH_XCPT_DB_CLEARING_TF + cmp byte [ebp + 04h], X86_XCPT_DB ; make sure we won't trap again due to a TF. + jne .resume_no_clear_trap_flags + and word [ebp + 14h], ~X86_EFL_TF +.resume_no_clear_trap_flags: +%endif + pop ds + pop ecx + pop ebx + pop eax + ;popfd + leave + add esp, 8h + iret + + +.no_resume_pos: + ; + ; Look for a trap record. + ; + mov ecx, [g_cTrapRecs] ; the number of records. + test ecx, ecx + jz .panic + mov eax, [g_LastTrapRegs + BS2REGS.rip] + sub eax, [g_pTrapRecBase] ; the offWhere we're looking for. + jb .panic + + ; Look starting at the previous record first. + mov ebx, [g_iTrapRecLast] + sub ecx, ebx + jbe .traprec_loop2 ; g_iTrapRecLast is out of range. + shl ebx, BS2TRAPREC_SIZE_SHIFT + add ebx, [g_paTrapRecs] ; ebx points to the record we hit last time. +.traprec_loop1_next: + cmp [ebx + BS2TRAPREC.offWhere], eax + je .traprec_found + add ebx, BS2TRAPREC_size + dec ecx + jnz .traprec_loop1_next + + ; Start searching from the start, stopping at the previous record. +.traprec_loop2: + mov ecx, [g_iTrapRecLast] + or ecx, ecx + jz .panic ; not found. + mov ebx, [g_paTrapRecs] +.traprec_loop2_next: + cmp [ebx + BS2TRAPREC.offWhere], eax + je .traprec_found + add ebx, BS2TRAPREC_size + dec ecx + jnz .traprec_loop2_next + jmp .panic ; not found + +.traprec_found: + ; Remember the hit for the next trap. + mov eax, ebx + sub eax, [g_paTrapRecs] + shr eax, BS2TRAPREC_SIZE_SHIFT + mov [g_iTrapRecLast], eax + + ; + ; Fail the test if we got the wrong trap or error code. + ; + mov al, [g_u8LastTrapNo] + cmp al, [ebx + BS2TRAPREC.u8TrapNo] + je .traprec_ok_trap + push eax + movzx eax, byte [ebx + BS2TRAPREC.u8TrapNo] + push eax + push .s_szWrongTrap + call NAME(TestFailedF_p32) + add esp, 12 + +.traprec_ok_trap: + mov ax, [g_u64LastTrapErr] + cmp ax, [ebx + BS2TRAPREC.u16ErrCd] + je .traprec_ok_err_cd + push eax + movzx eax, word [ebx + BS2TRAPREC.u16ErrCd] + push eax + push .s_szWrongErrCd + call NAME(TestFailedF_p32) + add esp, 12 + +.traprec_ok_err_cd: + ; + ; Advance the EIP and resume execution. + ; + movzx eax, byte [ebx + BS2TRAPREC.offResumeAddend] + add eax, [g_LastTrapRegs + BS2REGS.rip] + mov [ebp + 0ch], eax + jmp .resume + + + ; + ; Write panic message and then halt. + ; +.panic: + push dword [g_LastTrapRegs + BS2REGS.rflags] + push dword [g_LastTrapRegs + BS2REGS.ss] + push dword [g_LastTrapRegs + BS2REGS.gs] + push dword [g_LastTrapRegs + BS2REGS.fs] + push dword [g_LastTrapRegs + BS2REGS.es] + push dword [g_LastTrapRegs + BS2REGS.ds] + push dword [g_LastTrapRegs + BS2REGS.cs] + ; line break + push dword [g_LastTrapRegs + BS2REGS.cr4] + push dword [g_LastTrapRegs + BS2REGS.cr3] + push dword [g_LastTrapRegs + BS2REGS.cr0] + push dword [g_LastTrapRegs + BS2REGS.rbp] + push dword [g_LastTrapRegs + BS2REGS.rsp] + push dword [g_LastTrapRegs + BS2REGS.rip] + ; line break + push dword [g_LastTrapRegs + BS2REGS.rdi] + push dword [g_LastTrapRegs + BS2REGS.rsi] + push dword [g_LastTrapRegs + BS2REGS.rdx] + push dword [g_LastTrapRegs + BS2REGS.rcx] + push dword [g_LastTrapRegs + BS2REGS.rbx] + push dword [g_LastTrapRegs + BS2REGS.rax] + ; line break + mov eax, [ebp + 08h] + push eax + mov eax, cr2 + push eax + mov eax, [ebp + 0ch] + push eax + movzx eax, word [ebp + 10h] + push eax + movzx eax, byte [ebp + 04h] + push eax + push .s_szPanicMsg + call NAME(TestFailedF_p32) + + call Bs2Panic + jmp .panic ; paranoia + +.s_szPanicMsg: + db 'trap #%RX8 at %RX16:%RX32 cr2=%RX32 err=%RX32', 13, 10 + db 'eax=%RX32 ebx=%RX32 ecx=%RX32 edx=%RX32 esi=%RX32 edi=%RX32', 13, 10 + db 'eip=%RX32 esp=%RX32 ebp=%RX32 cr0=%RX32 cr3=%RX32 cr4=%RX32', 13, 10 + db 'cs=%RX16 ds=%RX16 es=%RX16 fs=%RX16 gs=%RX16 ss=%RX16 eflags=%RX32', 13, 10 + db 0 +.s_szWrongTrap: + db 'Expected trap %RX8 got %RX8', 13, 10, 0 +.s_szWrongErrCd: + db 'Expected errcd %RX16 got %RX16', 13, 10, 0 +ENDPROC bs2Trap_XX_32bit + +;; +; Service IRQ handler, 32-bit version. +; +; Takes requests in eax and later maybe parameters in other registers. +; +; return GS ebp + 24h - v86 +; return FS ebp + 20h - v86 +; return DS ebp + 1ch - v86 +; return ES ebp + 18h - v86 +; return SS ebp + 14h - higher privilege +; return ESP ebp + 10h - higher privilege +; return EFLAGS ebp + 0ch +; return CS ebp + 08h +; return EIP ebp + 04h +BEGINCODELOW +BEGINPROC bs2TrapService32bit + jmp .highsegment +BEGINCODEHIGH +.highsegment: + push ebp ; ebp + mov ebp, esp + push eax ; ebp - 04h + push edx ; ebp - 08h + push ecx ; ebp - 0ch + push ebx ; ebp - 10h + push ds ; ebp - 14h + + mov dx, ss + mov ds, dx + + ; + ; Classify the caller context in cl. + ;; @todo What if CS on the stack is conforming? + ; +%define BS2_TRP_SRV_CALLER_SAME_RING 0 +%define BS2_TRP_SRV_CALLER_OTHER_RING 1 +%define BS2_TRP_SRV_CALLER_VM 2 + test dword [ebp + 0ch], X86_EFL_VM + jnz .vm_ctx + + mov cx, ss + mov ch, [ebp + 08h] ; cs + and cx, 00303h + cmp ch, cl + jz .same_ctx + mov cl, BS2_TRP_SRV_CALLER_OTHER_RING + jmp .done_ctx +.vm_ctx: + mov cl, BS2_TRP_SRV_CALLER_VM + jmp .done_ctx +.same_ctx: + mov cl, BS2_TRP_SRV_CALLER_SAME_RING +.done_ctx: + + ; + ; Switch (eax). + ; + cmp eax, BS2_SYSCALL_TO_RING3 + jbe .to_ringX + + ; Unknown request. +.failure: + mov eax, -1 +.return: ; careful with ebp here! + pop ds + pop ebx + pop ecx + pop edx + ;pop eax + leave + iretd + + ; + ; Switching to the ring specified by eax. + ; Annoying that ss:esp isn't always restored. + ; +.to_ringX: + cmp cl, BS2_TRP_SRV_CALLER_VM + je .failure + sub al, BS2_SYSCALL_TO_RING0 + + ; Fake missing stack registers if necessary. + cmp cl, BS2_TRP_SRV_CALLER_SAME_RING + jnz .have_stack_regs + + sub esp, 8h + sub ebp, 8h + xor ebx, ebx +.move_more: + mov edx, [esp + 8 + ebx] + mov [esp + ebx], edx + add ebx, 4 + cmp ebx, 9*4 + jb .move_more + + mov dx, ss + mov [ebp + 14h], edx + lea edx, [ebp + 18h] + mov [ebp + 10h], edx + +.have_stack_regs: + ; Translate the selector registers + mov dx, [ebp - 14h] + call bs2SRegToRing + mov [ebp - 14h], dx + + mov dx, es + call bs2SRegToRing + mov es, dx + + mov dx, fs + call bs2SRegToRing + mov fs, dx + + mov dx, gs + call bs2SRegToRing + mov gs, dx + + mov dx, [ebp + 08h] ; cs + call bs2SRegToRing + mov [ebp + 08h], dx + + mov dx, [ebp + 14h] ; ss + call bs2SRegToRing + mov [ebp + 14h], dx + + or dword [ebp + 0ch], X86_EFL_IOPL ; set IOPL=3 + + ; If the desired target is ring-0 we cannot use iret. + cmp al, 0 + je .iret_to_ring_with_stack + +.done_success: + xor eax, eax + jmp .return + +.iret_to_ring_with_stack: + ; + ; Move the iret-to-same-ring to the desired return position. By also + ; moving the saved ebp we make the leave instruction do stack + ; adjusting/switching for us. + ; + cli ; paranoia, it's disable already. + mov eax, [ebp + 10h] + lea edx, [ebp + 18h] + cmp eax, edx + lea ecx, [ebp + 08h] ; same stack, just shifted 8 bytes + je .move_iret_and_ebp + mov ecx, [ebp + 10h] ; different stack. + sub ecx, 10h +.move_iret_and_ebp: + mov edx, [ebp + 0ch] + mov eax, [ebp + 08h] + mov [ecx + 0ch], edx + mov [ecx + 08h], eax + mov edx, [ebp + 04h] + mov eax, [ebp + 00h] + mov [ecx + 04h], edx + mov [ecx + 00h], eax + mov ebp, ecx + xor eax, eax + jmp .return + +ENDPROC bs2TrapService32bit + +%endif ; BS2_INC_CMN_PM + + +%ifdef BS2_INC_CMN_LM +; +; 64-bit TSS (X86TSS64). +; +BEGINCODELOW +ALIGNDATA(16) +bs2Tss64Bit: + dd 0 ; 00h - u32Reserved - Reserved. + dq BS2_R0_STACK_ADDR ; 04h - rsp0 - Ring-0 stack pointer. (static) + dq BS2_R1_STACK_ADDR ; 1ch - rsp1 - Ring-1 stack pointer. (static) + dq BS2_R2_STACK_ADDR ; 14h - rsp2 - Ring-2 stack pointer. (static) + dq 0 ; 2ch - reserved + dq BS2_DF_R0_STACK_ADDR ; 24h - ist1; + dq BS2_R0_STACK_ADDR ; 3ch - ist2; + dq BS2_R0_STACK_ADDR ; 34h - ist3; + dq BS2_R0_STACK_ADDR ; 4ch - ist4; + dq BS2_R0_STACK_ADDR ; 44h - ist5; + dq BS2_R0_STACK_ADDR ; 5ch - ist6; + dq BS2_R0_STACK_ADDR ; 54h - ist7; + dw 0,0,0,0,0 ; 6ch - reserved + dw 0 ; 76h - offIoBitmap - Offset relative to the TSS of the + ; 00h - start of the I/O Bitmap and the end of the + ; 00h - interrupt redirection bitmap. +bs2Tss64BitEnd: +times (68h - (bs2Tss64BitEnd - bs2Tss64Bit)) db 0 +times ((bs2Tss64BitEnd - bs2Tss64Bit) - 68h) db 0 + +; +; 64-bit IDT (X86DESC64GATE). +; +BEGINCODELOW +ALIGNDATA(16) +bs2Idt64bit: + dw bs2Trap_00h_64bit, BS2_SEL_CS64, 08e00h, 00000h, 0, 0, 0, 0 ; p=1 dpl=0 type=int64gate + dw bs2Trap_01h_64bit, BS2_SEL_CS64, 08e00h, 00000h, 0, 0, 0, 0 ; p=1 dpl=0 type=int64gate + dw bs2Trap_02h_64bit, BS2_SEL_CS64, 08e00h, 00000h, 0, 0, 0, 0 ; p=1 dpl=0 type=int64gate +bs2Idt64bit_BP: + dw bs2Trap_03h_64bit, BS2_SEL_CS64, 08e00h, 00000h, 0, 0, 0, 0 ; p=1 dpl=0 type=int64gate + dw bs2Trap_04h_64bit, BS2_SEL_CS64, 08e00h, 00000h, 0, 0, 0, 0 ; p=1 dpl=0 type=int64gate + dw bs2Trap_05h_64bit, BS2_SEL_CS64, 08e00h, 00000h, 0, 0, 0, 0 ; p=1 dpl=0 type=int64gate + dw bs2Trap_06h_64bit, BS2_SEL_CS64, 08e00h, 00000h, 0, 0, 0, 0 ; p=1 dpl=0 type=int64gate + dw bs2Trap_07h_64bit, BS2_SEL_CS64, 08e00h, 00000h, 0, 0, 0, 0 ; p=1 dpl=0 type=int64gate + dw bs2Trap_08h_64bit, BS2_SEL_CS64, 08e00h, 00000h, 0, 0, 0, 0 ; p=1 dpl=0 type=int64gate + dw bs2Trap_09h_64bit, BS2_SEL_CS64, 08e00h, 00000h, 0, 0, 0, 0 ; p=1 dpl=0 type=int64gate + dw bs2Trap_0ah_64bit, BS2_SEL_CS64, 08e00h, 00000h, 0, 0, 0, 0 ; p=1 dpl=0 type=int64gate + dw bs2Trap_0bh_64bit, BS2_SEL_CS64, 08e00h, 00000h, 0, 0, 0, 0 ; p=1 dpl=0 type=int64gate + dw bs2Trap_0ch_64bit, BS2_SEL_CS64, 08e00h, 00000h, 0, 0, 0, 0 ; p=1 dpl=0 type=int64gate + dw bs2Trap_0dh_64bit, BS2_SEL_CS64, 08e00h, 00000h, 0, 0, 0, 0 ; p=1 dpl=0 type=int64gate + dw bs2Trap_0eh_64bit, BS2_SEL_CS64, 08e00h, 00000h, 0, 0, 0, 0 ; p=1 dpl=0 type=int64gate + dw bs2Trap_0fh_64bit, BS2_SEL_CS64, 08e00h, 00000h, 0, 0, 0, 0 ; p=1 dpl=0 type=int64gate + dw bs2Trap_10h_64bit, BS2_SEL_CS64, 08e00h, 00000h, 0, 0, 0, 0 ; p=1 dpl=0 type=int64gate + dw bs2Trap_11h_64bit, BS2_SEL_CS64, 08e00h, 00000h, 0, 0, 0, 0 ; p=1 dpl=0 type=int64gate + dw bs2Trap_12h_64bit, BS2_SEL_CS64, 08e00h, 00000h, 0, 0, 0, 0 ; p=1 dpl=0 type=int64gate + dw bs2Trap_13h_64bit, BS2_SEL_CS64, 08e00h, 00000h, 0, 0, 0, 0 ; p=1 dpl=0 type=int64gate + dw bs2Trap_14h_64bit, BS2_SEL_CS64, 08e00h, 00000h, 0, 0, 0, 0 ; p=1 dpl=0 type=int64gate + dw bs2Trap_15h_64bit, BS2_SEL_CS64, 08e00h, 00000h, 0, 0, 0, 0 ; p=1 dpl=0 type=int64gate + dw bs2Trap_16h_64bit, BS2_SEL_CS64, 08e00h, 00000h, 0, 0, 0, 0 ; p=1 dpl=0 type=int64gate + dw bs2Trap_17h_64bit, BS2_SEL_CS64, 08e00h, 00000h, 0, 0, 0, 0 ; p=1 dpl=0 type=int64gate + dw bs2Trap_18h_64bit, BS2_SEL_CS64, 08e00h, 00000h, 0, 0, 0, 0 ; p=1 dpl=0 type=int64gate + dw bs2Trap_19h_64bit, BS2_SEL_CS64, 08e00h, 00000h, 0, 0, 0, 0 ; p=1 dpl=0 type=int64gate + dw bs2Trap_1ah_64bit, BS2_SEL_CS64, 08e00h, 00000h, 0, 0, 0, 0 ; p=1 dpl=0 type=int64gate + dw bs2Trap_1bh_64bit, BS2_SEL_CS64, 08e00h, 00000h, 0, 0, 0, 0 ; p=1 dpl=0 type=int64gate + dw bs2Trap_1ch_64bit, BS2_SEL_CS64, 08e00h, 00000h, 0, 0, 0, 0 ; p=1 dpl=0 type=int64gate + dw bs2Trap_1dh_64bit, BS2_SEL_CS64, 08e00h, 00000h, 0, 0, 0, 0 ; p=1 dpl=0 type=int64gate + dw bs2Trap_1eh_64bit, BS2_SEL_CS64, 08e00h, 00000h, 0, 0, 0, 0 ; p=1 dpl=0 type=int64gate + dw bs2Trap_1fh_64bit, BS2_SEL_CS64, 08e00h, 00000h, 0, 0, 0, 0 ; p=1 dpl=0 type=int64gate + dw bs2TrapService64bit,BS2_SEL_CS64,0ee00h, 00000h, 0, 0, 0, 0 ; p=1 dpl=3 type=int64gate +bs2Idt64bitEnd + + +; +; 64-bit trap handlers. +; +BITS 64 +%macro bs2Trap_XX_64bit_macro 1 +BEGINCODELOW +bs2Trap_ %+ %1 %+ _64bit: + push %1 + jmp bs2Trap_XX_64bit +%endmacro +%macro bs2Trap_XX_64bit_macro_no_err 1 +bs2Trap_ %+ %1 %+ _64bit: + push 0 + push %1 + jmp bs2Trap_XX_64bit +%endmacro + bs2Trap_XX_64bit_macro_no_err 00h + bs2Trap_XX_64bit_macro_no_err 01h + bs2Trap_XX_64bit_macro_no_err 02h + bs2Trap_XX_64bit_macro_no_err 03h + bs2Trap_XX_64bit_macro_no_err 04h + bs2Trap_XX_64bit_macro_no_err 05h + bs2Trap_XX_64bit_macro_no_err 06h + bs2Trap_XX_64bit_macro_no_err 07h + bs2Trap_XX_64bit_macro 08h + bs2Trap_XX_64bit_macro_no_err 09h + bs2Trap_XX_64bit_macro 0ah + bs2Trap_XX_64bit_macro 0bh + bs2Trap_XX_64bit_macro 0ch + bs2Trap_XX_64bit_macro 0dh + bs2Trap_XX_64bit_macro 0eh + bs2Trap_XX_64bit_macro_no_err 0fh + bs2Trap_XX_64bit_macro_no_err 10h + bs2Trap_XX_64bit_macro 11h + bs2Trap_XX_64bit_macro_no_err 12h + bs2Trap_XX_64bit_macro_no_err 13h + bs2Trap_XX_64bit_macro_no_err 14h + bs2Trap_XX_64bit_macro_no_err 15h + bs2Trap_XX_64bit_macro_no_err 16h + bs2Trap_XX_64bit_macro_no_err 17h + bs2Trap_XX_64bit_macro_no_err 18h + bs2Trap_XX_64bit_macro_no_err 19h + bs2Trap_XX_64bit_macro_no_err 1ah + bs2Trap_XX_64bit_macro_no_err 1bh + bs2Trap_XX_64bit_macro_no_err 1ch + bs2Trap_XX_64bit_macro_no_err 1dh + bs2Trap_XX_64bit_macro_no_err 1eh + bs2Trap_XX_64bit_macro_no_err 1fh + +;; +; Common 64-bit trap handler. +; +; return SS rbp + 38h +; return RSP rbp + 30h +; return RFLAGS rbp + 28h +; return CS rbp + 20h +; return RIP rbp + 18h +; error code rbp + 10h +; vector # rbp + 08h +BEGINCODEHIGH +BEGINPROC bs2Trap_XX_64bit + push rbp ; rbp + 00h + mov rbp, rsp + pushfq ; rbp - 08h + push rax ; rbp - 10h + push rbx ; rbp - 18h + + ; + ; Benchmark mode? Then resume the action right away! + ; + mov rax, [rbp + 08h] + cmp [g_u8TrapBenchmarkNo], al + jne .test_mode + cmp byte [g_fTrapPrepared], 0 + je .test_mode + mov rax, [g_TrapResumeRIP] + mov [rbp + 18h], rax + + pop rbx + ;pop rax + ;popfq + leave + add rsp, 10h ; Skip the vector # and error code. + xor rax, rax + iretq + + ; + ; Save the trap information + ; +.test_mode: + inc dword [g_u32cTraps] + mov rax, [rbp + 08h] + mov [g_u8LastTrapNo], al + mov rax, [rbp + 10h] + mov [g_u64LastTrapErr], rax + mov rax, [rbp - 08h] + mov [g_u64LastTrapHandlerRFlags], rax + mov ax, cs + mov [g_u16LastTrapHandlerCS], ax + mov ax, ss + mov [g_u16LastTrapHandlerSS], ax + lea rax, [rbp + 8] + mov [g_u64LastTrapHandlerRSP], rax + + ; Save the registers. + lea rbx, [g_LastTrapRegs] + mov rax, [rbp - 10h] + mov [rbx + BS2REGS.rax], rax + mov rax, [rbp - 18h] + mov [rbx + BS2REGS.rbx], rax + mov [rbx + BS2REGS.rcx], rcx + mov [rbx + BS2REGS.rdx], rdx + mov [rbx + BS2REGS.rdi], rdi + mov [rbx + BS2REGS.rsi], rsi + mov rax, [rbp] + mov [rbx + BS2REGS.rbp], rax + mov rax, [rbp + 30h] + mov [rbx + BS2REGS.rsp], rax + mov rax, [rbp + 18h] + mov [rbx + BS2REGS.rip], rax + mov [rbx + BS2REGS.r8], r8 + mov [rbx + BS2REGS.r9], r9 + mov [rbx + BS2REGS.r10], r10 + mov [rbx + BS2REGS.r11], r11 + mov [rbx + BS2REGS.r12], r12 + mov [rbx + BS2REGS.r13], r13 + mov [rbx + BS2REGS.r14], r14 + mov [rbx + BS2REGS.r15], r15 + mov rax, [rbp + 28h] + mov [rbx + BS2REGS.rflags], rax + mov rax, [rbp + 20h] + mov [rbx + BS2REGS.cs], ax + mov [rbx + BS2REGS.ds], ds + mov [rbx + BS2REGS.es], es + mov [rbx + BS2REGS.fs], fs + mov [rbx + BS2REGS.gs], gs + mov rax, [rbp + 38h] + mov [rbx + BS2REGS.ss], ax + mov [rbx + BS2REGS.cBits], byte 64 + + ; The CRx registers are only accessible from ring-0 (CS=conforming, CPL < 0) + test byte [rbx + BS2REGS.ss], 3 + jnz .skip_crX + mov rax, cr0 + mov [rbx + BS2REGS.cr0], rax + mov rax, cr2 + mov [rbx + BS2REGS.cr2], rax + mov rax, cr3 + mov [rbx + BS2REGS.cr3], rax + mov rax, cr4 + mov [rbx + BS2REGS.cr4], rax + mov rax, cr8 + mov [rbx + BS2REGS.cr8], rax +.skip_crX: + + ; + ; Advance to a prepared resume position or panic. + ; + cmp byte [g_fTrapPrepared], 0 + je .no_resume_pos + mov byte [g_fTrapPrepared], 0 + mov rax, [g_TrapResumeRIP] + mov [rbp + 18h], rax + jmp .resume + +.resume: +%ifdef BS2_WITH_XCPT_DB_CLEARING_TF + cmp byte [rbp + 08h], X86_XCPT_DB ; make sure we won't trap again due to a TF. + jne .resume_no_clear_trap_flags + and word [rbp + 28h], ~X86_EFL_TF +.resume_no_clear_trap_flags: +%endif + pop rbx + pop rax + ;popfq + leave + add rsp, 10h + iretq + + +.no_resume_pos: + ; + ; Look for a trap record. + ; + push rcx + + mov ecx, [g_cTrapRecs] ; the number of records. + test ecx, ecx + jz .panic + mov rax, [g_LastTrapRegs + BS2REGS.rip] + sub rax, [g_pTrapRecBase] ; the offWhere we're looking for. + jb .panic + mov rbx, _4G + cmp rax, rbx + jae .panic ; out of range. + + ; Look starting at the previous record first. + mov ebx, [g_iTrapRecLast] + sub ecx, ebx + jbe .traprec_loop2 ; g_iTrapRecLast is out of range. + shl rbx, BS2TRAPREC_SIZE_SHIFT + add rbx, [g_paTrapRecs] ; ebx points to the record we hit last time. +.traprec_loop1_next: + cmp [rbx + BS2TRAPREC.offWhere], eax + je .traprec_found + add rbx, BS2TRAPREC_size + dec ecx + jnz .traprec_loop1_next + + ; Start searching from the start, stopping at the previous record. +.traprec_loop2: + mov ecx, [g_iTrapRecLast] + or ecx, ecx + jz .panic ; not found. + mov rbx, [g_paTrapRecs] +.traprec_loop2_next: + cmp [rbx + BS2TRAPREC.offWhere], eax + je .traprec_found + add rbx, BS2TRAPREC_size + dec ecx + jnz .traprec_loop2_next + jmp .panic ; not found + +.traprec_found: + ; Remember the hit for the next trap. + mov rax, rbx + sub rax, [g_paTrapRecs] + shr rax, BS2TRAPREC_SIZE_SHIFT + mov [g_iTrapRecLast], eax + + ; + ; Fail the test if we got the wrong trap or error code. + ; + mov al, [g_u8LastTrapNo wrt rip] + cmp al, [rbx + BS2TRAPREC.u8TrapNo] + je .traprec_ok_trap + push rax + movzx rax, byte [rbx + BS2TRAPREC.u8TrapNo] + push rax + push .s_szWrongTrap + call NAME(TestFailedF_p64) + add rsp, 24 + +.traprec_ok_trap: + mov ax, [g_u64LastTrapErr wrt rip] + cmp ax, [rbx + BS2TRAPREC.u16ErrCd] + je .traprec_ok_err_cd + push rax + movzx rax, word [rbx + BS2TRAPREC.u16ErrCd] + push rax + push .s_szWrongErrCd + call NAME(TestFailedF_p64) + add rsp, 24 + +.traprec_ok_err_cd: + ; + ; Advance the EIP and resume execution. + ; + movzx rax, byte [rbx + BS2TRAPREC.offResumeAddend] + add rax, [g_LastTrapRegs + BS2REGS.rip] + mov [rbp + 18h], rax + + pop rcx + jmp .resume + + + ; + ; Format a panic message and halt. + ; +.panic: + lea rbx, [g_LastTrapRegs] + ; line break + movzx eax, word [rbx + BS2REGS.ss] + push rax + movzx eax, word [rbx + BS2REGS.gs] + push rax + movzx eax, word [rbx + BS2REGS.fs] + push rax + movzx eax, word [rbx + BS2REGS.es] + push rax + movzx eax, word [rbx + BS2REGS.ds] + push rax + movzx eax, word [rbx + BS2REGS.cs] + push rax + ; line break + push qword [rbx + BS2REGS.rbp] + push qword [rbx + BS2REGS.rsp] + push qword [rbx + BS2REGS.rip] + ; line break + push qword [rbx + BS2REGS.rflags] + push qword [rbx + BS2REGS.r15] + push qword [rbx + BS2REGS.r14] + ; line break + push qword [rbx + BS2REGS.r13] + push qword [rbx + BS2REGS.r12] + push qword [rbx + BS2REGS.r11] + ; line break + push qword [rbx + BS2REGS.r10] + push qword [rbx + BS2REGS.r9] + push qword [rbx + BS2REGS.r8] + ; line break + push qword [rbx + BS2REGS.rdi] + push qword [rbx + BS2REGS.rsi] + push qword [rbx + BS2REGS.rdx] + ; line break + push qword [rbx + BS2REGS.rcx] + push qword [rbx + BS2REGS.rbx] + push qword [rbx + BS2REGS.rax] + ; line break + mov eax, [rbx + BS2REGS.cr8] + push rax + mov eax, [rbx + BS2REGS.cr4] + push rax + mov eax, [rbx + BS2REGS.cr3] + push rax + mov eax, [rbx + BS2REGS.cr0] + push rax + ; line break + push qword [rbp + 10h] + push qword [rbx + BS2REGS.cr2] + push qword [rbx + BS2REGS.rip] + movzx eax, word [rbp + BS2REGS.ss] + push rax + movzx eax, byte [rbp + 08h] + push rax + push .s_szPanicMsg + call NAME(TestFailedF_p64) + + call Bs2Panic + jmp .panic ; paranoia + +.s_szPanicMsg: + db 'trap #%RX8 at %RX16:%RX64 cr2=%RX64 err=%RX64', 13, 10 + db 'cr0=%RX64 cr3=%RX64 cr4=%RX64 cr8=%RX16', 13, 10 + db 'rax=%RX64 rbx=%RX64 rcx=%RX64', 13, 10 + db 'rdx=%RX64 rsi=%RX64 rdi=%RX64', 13, 10 + db 'r8 =%RX64 r9 =%RX64 r10=%RX64', 13, 10 + db 'r11=%RX64 r12=%RX64 r13=%RX64', 13, 10 + db 'r14=%RX64 r15=%RX64 rfl=%RX64', 13, 10 + db 'rip=%RX64 rsp=%RX64 rbp=%RX64 ', 13, 10 + db 'cs=%RX16 ds=%RX16 es=%RX16 fs=%RX16 gs=%RX16 ss=%RX16', 13, 10 + db 0 +.s_szWrongTrap: + db 'Expected trap %RX8 got %RX8', 13, 10, 0 +.s_szWrongErrCd: + db 'Expected errcd %RX16 got %RX16', 13, 10, 0 +ENDPROC bs2Trap_XX_64bit + + +;; +; Service IRQ handler. +; +; Takes requests in eax and later maybe parameters in other registers. +; +; return SS rbp + 28h +; return RSP rbp + 20h +; return RFLAGS rbp + 18h +; return CS rbp + 10h +; return RIP rbp + 08h +BEGINCODELOW +BEGINPROC bs2TrapService64bit + jmp .highsegment +BEGINCODEHIGH +.highsegment: + push rbp + mov rbp, rsp + push rax + push rdx + push rcx + + + ; + ; Switch (eax). + ; + cmp eax, BS2_SYSCALL_TO_RING3 + jbe .to_ringX + + ; Unknown request. + mov rax, -1 +.return: + pop rcx + pop rdx + ;pop rax + leave + iretq + + ; + ; Switching to the ring specified by eax. + ; +.to_ringX: + sub eax, BS2_SYSCALL_TO_RING0 ; al = new ring number. + + mov dx, ds + call bs2SRegToRing + mov ds, dx + + mov dx, es + call bs2SRegToRing + mov es, dx + + mov dx, fs + call bs2SRegToRing + mov fs, dx + + mov dx, gs + call bs2SRegToRing + mov gs, dx + + mov dx, [rbp + 10h] ; cs + call bs2SRegToRing + mov [rbp + 10h], dx + + mov dx, [rbp + 28h] ; ss + call bs2SRegToRing + mov [rbp + 28h], dx + + or dword [ebp + 18h], X86_EFL_IOPL ; set IOPL=3 + + jmp .done_success + +.done_success: + xor eax, eax + jmp .return + +ENDPROC bs2TrapService64bit + +%endif ; BS2_INC_CMN_LM + + +;; +; Converts a segment value (dx) to the ring specified by al. +; +; If the selector isn't a known CS, DS or SS selector it will be set to null. +; +; @returns dx +; @param al The desired ring. +; @param dx The segment to convert. +; +; @remarks WARNING! This has to work exactly the same both in 32-bit and 64-bit mode. +; +BEGINCODEHIGH +BITS 32 +BEGINPROC bs2SRegToRing + ; + ; Classify the incoming selector. + ; + cmp dx, BS2_SEL_R0_BASE + jb .null + cmp dx, BS2_SEL_R0_BASE + BS2_SEL_GRP_SIZE + jb .ring0 + + cmp dx, BS2_SEL_R1_BASE + jb .miss + cmp dx, BS2_SEL_R1_BASE + BS2_SEL_GRP_SIZE + jb .ring1 + + cmp dx, BS2_SEL_R2_BASE + jb .miss + cmp dx, BS2_SEL_R2_BASE + BS2_SEL_GRP_SIZE + jb .ring2 + + cmp dx, BS2_SEL_R3_BASE + jb .miss + cmp dx, BS2_SEL_R3_BASE + BS2_SEL_GRP_SIZE + jb .ring3 + jmp .miss + + ; + ; Convert the incoming selector to ring-0 and then from ring-0 to the + ; desired one. + ; +.ring0: + cmp al, 0 + je .done + + add dx, BS2_SEL_R1_BASE - BS2_SEL_R0_BASE + cmp al, 1 + je .done + + add dx, BS2_SEL_R2_BASE - BS2_SEL_R1_BASE + cmp al, 2 + je .done + + add dx, BS2_SEL_R3_BASE - BS2_SEL_R2_BASE + cmp al, 3 + je .done +.panic: + hlt + jmp .panic + +.ring1: + sub dx, BS2_SEL_R1_BASE - BS2_SEL_R0_BASE + jmp .ring0 +.ring2: + sub dx, BS2_SEL_R2_BASE - BS2_SEL_R0_BASE + jmp .ring0 +.ring3: + sub dx, BS2_SEL_R3_BASE - BS2_SEL_R0_BASE + jmp .ring0 + +.done: + and dl, ~3h + or dl, al ; set the RPL + ret + +.miss: +.null: + xor dx, dx + ret +ENDPROC bs2SRegToRing + +BEGINCODELOW + diff --git a/src/VBox/ValidationKit/bootsectors/bootsector2-common-macros-1.mac b/src/VBox/ValidationKit/bootsectors/bootsector2-common-macros-1.mac new file mode 100644 index 00000000..c84fcaf8 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bootsector2-common-macros-1.mac @@ -0,0 +1,50 @@ +; $Id: bootsector2-common-macros-1.mac $ +;; @file +; Common bootsector macros. +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + + +;; +; Asserts a test. +; +; @param %1 First cmp operand. +; @param %2 First cmp operand. +; @param %3 Which kind of conditional jump to make +; @param %4 The message to print (format string, no arguments please). +; +%macro TEST_ASSERT_SIMPLE 4 + cmp %1, %2 + %3 %%.ok + push dword __LINE__ + %ifdef TMPL_16BIT + push ds + %endif + push %%.s_szMsg + call TMPL_NM_CMN(TestFailedF) + add xSP, sCB*2 + jmp %%.ok +%%.s_szMsg: db %4, " (0x%RX32)", 0 +%%.ok: +%endmacro + diff --git a/src/VBox/ValidationKit/bootsectors/bootsector2-common-routines-template-1.mac b/src/VBox/ValidationKit/bootsectors/bootsector2-common-routines-template-1.mac new file mode 100644 index 00000000..2ddeac1f --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bootsector2-common-routines-template-1.mac @@ -0,0 +1,2645 @@ +; $Id: bootsector2-common-routines-template-1.mac $ +;; @file +; bootsector2 common routines - template containing code common to related modes. +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + +%include "bootsector2-template-header.mac" +%include "VBox/bios.mac" + +ALIGNCODE(32) +GLOBALNAME TMPL_NM_CMN(g_szMode) + db TMPL_MODE_STR, 0 + + +;; +; Shutdown routine. +; +; Does not return. +; +; @uses N/A +; +BEGINPROC TMPL_NM_CMN(Shutdown) +%ifdef TMPL_16BIT + jmp Bs2Shutdown +%else + cli + mov bl, 64 + mov ax, ss + mov ds, ax + mov dx, VBOX_BIOS_SHUTDOWN_PORT + mov ax, VBOX_BIOS_OLD_SHUTDOWN_PORT +.retry: + mov ecx, 8 + mov esi, .s_szShutdown + rep outsb + xchg dx, ax ; alternate between the new (VBox) and old (Bochs) ports. + dec bl + jnz .retry + ; Shutdown failed! + jmp Bs2Panic +.s_szShutdown: + db 'Shutdown', 0 +%endif +ENDPROC TMPL_NM_CMN(Shutdown) + + +;; +; Prints a 32-bit unsigned integer on the screen. +; +; @param eax The value to print. +; +; @uses nothing +; +BEGINPROC TMPL_NM_CMN(PrintU32) + push xBP + mov xBP, xSP + push sAX + push sDX + push sCX + push sBX +%ifdef TMPL_16BIT + push ds + + mov cx, ss + mov ds, cx +%endif + + ; Allocate a stack buffer and terminate it. ds:bx points ot the end. + sub xSP, 30h + mov xBX, xSP + add xBX, 2fh + mov byte [xBX], 0 + + mov ecx, 10 ; what to divide by +.next: + xor edx, edx + div ecx ; edx:eax / ecx -> eax and rest in edx. + add dl, '0' + dec xBX + mov [xBX], dl + cmp eax, 0 + jnz .next + + ; Print the string. + mov xAX, xBX + call TMPL_NM_CMN(PrintStr) + + add xSP, 30h +%ifdef TMPL_16BIT + pop ds +%endif + pop sBX + pop sCX + pop sDX + pop sAX + leave + ret +ENDPROC TMPL_NM_CMN(PrintU32) + + +;; +; Equivalent to RTPrintf, but a max output length of 1KB. +; +; @remarks This uses an entirely STACK BASED CALLING CONVENTION where the +; caller does the cleanup (cdecl sans volatile regs). +; +; @param fpszFormat The format string (far pointer on 16-bit +; systems). See StrFormatV for format details. +; @param ... Zero or more format string arguments. +; @uses nothing +; +BEGINPROC TMPL_NM_CMN(PrintF) + push xBP + mov xBP, xSP + push sAX + push xDX + push xCX + push xBX +%ifdef TMPL_16BIT + push ds + push es + push fs +%endif + sub xSP, 0400h ; string buffer (1024 bytes) + + ; + ; Format the failure string and call TestFailed. + ; +%ifdef TMPL_16BIT + mov ax, ss ; buffer address. + mov ds, ax + mov ax, sp + mov xDX, 0400h ; buffer size. + les cx, [bp + 4] ; format string + mov bx, ss ; argument list + mov fs, bx + mov bx, bp + add bx, 8 +%else + mov xAX, xSP ; buffer address + mov xDX, 0400h ; buffer size + mov xCX, [xBP + xCB * 2] ; format string + lea xBX, [xBP + xCB * 3] ; argument list. +%endif + call TMPL_NM_CMN(StrFormatV) + call TMPL_NM_CMN(PrintStr) + + add xSP, 0400h +%ifdef TMPL_16BIT + pop fs + pop es + pop ds +%endif + pop xBX + pop xCX + pop xDX + pop sAX + leave + ret +ENDPROC TMPL_NM_CMN(PrintF) + + +;; +; Print a string followed by a semicolon and at least one space. +; +; @param ds:ax The string to print. +; @param dx The desired minimum length of the output. That is +; string + colon + spaces. +; @uses nothing. +; +BEGINPROC TMPL_NM_CMN(PrintStrColonSpaces) + push xBP + mov xBP, xSP + push xAX + push xCX + + call TMPL_NM_CMN(PrintStr) + call TMPL_NM_CMN(StrLen) + mov cx, ax + mov al, ':' + call TMPL_NM_CMN(PrintChr) + inc cx + mov al, ' ' +.next_space: + call TMPL_NM_CMN(PrintChr) + inc cx + cmp cx, dx + jb .next_space + + pop xCX + pop xAX + leave + ret +ENDPROC TMPL_NM_CMN(PrintStrColonSpaces) + + +;; +; Print a string followed by a 0+ spaces, a semicolon and a space. +; +; @param ds:ax The string to print. +; @param dx The desired minimum length of the output. That is +; string + spaces + colon + space. +; @uses nothing. +; +BEGINPROC TMPL_NM_CMN(PrintStrSpacesColonSpace) + push xBP + mov xBP, xSP + push xAX + push xCX + + call TMPL_NM_CMN(PrintStr) + call TMPL_NM_CMN(StrLen) + mov cx, ax + inc cx + mov al, ' ' +.next_space: + inc cx + cmp cx, dx + jae .done_spaces + call TMPL_NM_CMN(PrintChr) + jmp .next_space +.done_spaces: + mov al, ':' + call TMPL_NM_CMN(PrintChr) + mov al, ' ' + call TMPL_NM_CMN(PrintChr) + + pop xCX + pop xAX + leave + ret +ENDPROC TMPL_NM_CMN(PrintStrSpacesColonSpace) + + +;; +; Store the current nanosecond timestamp in [ax] (qword). +; +; @param ds:ax Where to store the 64-bit timestamp. +; +; @uses nothing +; +BEGINPROC TMPL_NM_CMN(GetNanoTS) + push sAX + push sCX + push xDX +%ifdef TMPL_16BIT + movzx ecx, ax +%else + mov xCX, xAX +%endif + + mov dx, VMMDEV_TESTING_IOPORT_TS_LOW + in eax, dx + mov [sCX], eax + + mov dx, VMMDEV_TESTING_IOPORT_TS_HIGH + in eax, dx + mov [sCX + 4], eax + + pop xDX + pop sCX + pop sAX + ret +ENDPROC TMPL_NM_CMN(GetNanoTS) + + + +;; +; Calculates the time elapsed since [ax] (qword), storing it at [ax] (qword). +; +; @param ds:ax Where to get the start timestamp (input) and where +; to store the time elapsed (output). qword +; +; @uses nothing +; +BEGINPROC TMPL_NM_CMN(GetElapsedNanoTS) + push sAX + push sCX + push xDX +%ifdef TMPL_16BIT + movzx ecx, ax +%else + mov xCX, xAX +%endif + + mov dx, VMMDEV_TESTING_IOPORT_TS_LOW + in eax, dx + sub eax, [sCX] + mov [sCX], eax + + mov dx, VMMDEV_TESTING_IOPORT_TS_HIGH + in eax, dx + sbb eax, [sCX + 4] + mov [sCX + 4], eax + + pop xDX + pop sCX + pop sAX + ret +ENDPROC TMPL_NM_CMN(GetElapsedNanoTS) + + +;; +; Sends a command to VMMDev followed by a single string. +; +; If the VMMDev is not present or is not being used, this function will +; do nothing. +; +; @param eax The command. +; @param ds:dx The string (zero terminated). +; @uses nothing +; @internal +; +BEGINPROC TMPL_NM_CMN(testSendStrCmd) + push xBP + mov xBP, xSP + push sAX + push xBX + push xDX + + cmp byte [g_fbBs2VMMDevTesting], 0 + je .no_vmmdev + + mov dx, VMMDEV_TESTING_IOPORT_CMD + out dx, eax + + mov dx, VMMDEV_TESTING_IOPORT_DATA + pop xBX + push xBX + dec xBX +.next_char: + inc xBX + mov al, [xBX] + out dx, al + test al, al + jnz .next_char + +.no_vmmdev: + pop xDX + pop xBX + pop sAX + leave + ret +ENDPROC TMPL_NM_CMN(testSendStrCmd) + + +;; +; Equivalent to RTTestCreate + RTTestBanner +; +; @param DS16:xAX Pointer to a zero terminated string naming the +; test. Must be a global constant. +; @uses nothing +; +BEGINPROC TMPL_NM_CMN(TestInit) + push xBP + mov xBP, xSP + push sAX + push xDX + + ; Initialize the globals. + mov [g_npszBs2Test], xAX + xor eax, eax + mov [g_uscBs2TestErrors], ax + mov [g_npszBs2SubTest], eax + mov [g_uscBs2SubTestAtErrors], ax + mov byte [g_fbBs2SubTestReported], 1 + mov [g_uscBs2SubTests], ax + mov [g_uscBs2SubTestsFailed], ax + + ; Print the name. RTTestBanner + mov xAX, [g_npszBs2Test] + call TMPL_NM_CMN(PrintStr) + mov xAX, .s_szTesting + call TMPL_NM_CMN(PrintStr) + + ; Report it to the VMMDev. + mov eax, VMMDEV_TESTING_CMD_INIT + mov xDX, [g_npszBs2Test] + call TMPL_NM_CMN(testSendStrCmd) + + pop xDX + pop sAX + leave + ret +.s_szTesting: + db ': TESTING...', 13, 10, 0 +ENDPROC TMPL_NM_CMN(TestInit) + + +;; +; rtTestSubTestReport +; @uses nothing +; @internal +BEGINPROC TMPL_NM_CMN(testSubTestReport) + push xBP + mov xBP, xSP + push sAX + push sCX + push xDX + + ; Check if there is anything to do. + cmp byte [g_fbBs2SubTestReported], 0 + jne .done + xor xAX, xAX ; load the sub test name pointer for later + mov xAX, [g_npszBs2SubTest] + test xAX, xAX + jz .done + + ; Start the printing. + mov dx, 48 + call TMPL_NM_CMN(PrintStrSpacesColonSpace) + + mov byte [g_fbBs2SubTestReported], 1 + mov cx, [g_uscBs2TestErrors] + sub cx, [g_uscBs2SubTestAtErrors] + and ecx, 0ffffh + jnz .failed + + ; passed + mov xAX, .s_szPassed + call TMPL_NM_CMN(PrintStr) + jmp .vmmdev + + ; failed +.failed: + mov xAX, .s_szFailure + call TMPL_NM_CMN(PrintStr) + mov eax, ecx + call TMPL_NM_CMN(PrintU32) + mov xAX, .s_szFailureEnd + call TMPL_NM_CMN(PrintStr) + + ; report to VMMDev +.vmmdev: + cmp byte [g_fbBs2VMMDevTesting], 0 + je .no_vmmdev + + mov dx, VMMDEV_TESTING_IOPORT_CMD + mov eax, VMMDEV_TESTING_CMD_SUB_DONE + out dx, eax + + mov dx, VMMDEV_TESTING_IOPORT_DATA + mov eax, ecx + out dx, eax + +.no_vmmdev: +.done: + pop xDX + pop sCX + pop sAX + leave + ret +.s_szPassed: + db 'PASSED', 13, 10, 0 +.s_szFailure: + db 'FAILED (', 0 +.s_szFailureEnd: + db ' errors)', 13, 10, 0 +ENDPROC TMPL_NM_CMN(testSubTestReport) + + +;; +; rtTestSubCleanup +; @uses nothing +; @internal +BEGINPROC TMPL_NM_CMN(testSubCleanup) + push xBP + mov xBP, xSP + + cmp dword [g_npszBs2SubTest], 0 + je .cleaned_up + + call TMPL_NM_CMN(testSubTestReport) + mov dword [g_npszBs2SubTest], 0 + mov byte [g_fbBs2SubTestReported], 0 + +.cleaned_up: + leave + ret +ENDPROC TMPL_NM_CMN(testSubCleanup) + + +;; +; Equivalent to RTTestSub. +; +; @param ds:xAX Pointer to a zero terminated string naming the sub test. +; @uses nothing +; +BEGINPROC TMPL_NM_CMN(TestSub) + push xBP + mov xBP, xSP + push sAX + push xDX + + ; Complete and cleanup any current sub test. + call TMPL_NM_CMN(testSubCleanup) + + ; Start a new sub test. + inc word [g_uscBs2SubTests] + mov dx, [g_uscBs2TestErrors] + mov [g_uscBs2SubTestAtErrors], dx + mov [g_npszBs2SubTest], xAX + mov byte [g_fbBs2SubTestReported], 0 + + ; Report it to the VMMDev. + mov xDX, xAX + mov eax, VMMDEV_TESTING_CMD_SUB_NEW + call TMPL_NM_CMN(testSendStrCmd) + + pop xDX + pop sAX + leave + ret +ENDPROC TMPL_NM_CMN(TestSub) + + +;; +; Calculates the error count for the current sub test. +; +; @returns ax Error count for the current sub test. +; @uses ax +; +BEGINPROC TMPL_NM_CMN(TestSubErrorCount) + pushf + + mov ax, [g_uscBs2TestErrors] + sub ax, [g_uscBs2SubTestAtErrors] + + popf + ret +ENDPROC TMPL_NM_CMN(TestSubErrorCount) + + + +;; +; Equivalent to RTTestValue. +; +; @param ds:ax The value name. +; @param edx The 32-bit value to report. +; @param cl The unit (VMMDEV_TESTING_UNIT_XXX). +; @uses nothing +; +BEGINPROC TMPL_NM_CMN(TestValueU32) + push xBP + mov xBP, xSP + push sDX + push sCX + push sAX + push sSI + pushf + cld + + mov xSI, xAX ; xSI = name + + ; Print it. + mov dx, 48 + call TMPL_NM_CMN(PrintStrSpacesColonSpace) + mov eax, [xBP - sCB] + call TMPL_NM_CMN(PrintU32) + mov al, ' ' + call TMPL_NM_CMN(PrintChr) + movzx sAX, cl ; ASSUMES correct input. + mov edx, eax ; edx = unit + shl xAX, 4 ; * 16 + add xAX, g_aszBs2TestUnitNames + call TMPL_NM_CMN(PrintStr) + mov al, 13 + call TMPL_NM_CMN(PrintChr) + mov al, 10 + call TMPL_NM_CMN(PrintChr) + + ; Report it to the host. + cmp byte [g_fbBs2VMMDevTesting], 0 + je .no_vmmdev + mov ecx, edx ; ecx = unit + + mov dx, VMMDEV_TESTING_IOPORT_CMD + mov eax, VMMDEV_TESTING_CMD_VALUE + out dx, eax + + mov dx, VMMDEV_TESTING_IOPORT_DATA + mov eax, [xBP - sCB] + out dx, eax ; value - low dword + xor eax, eax + out dx, eax ; value - high dword + mov eax, ecx + out dx, eax ; unit +.next_char: + lodsb + out dx, al + test al, al + jnz .next_char + +.no_vmmdev: + popf + pop sSI + pop sAX + pop sCX + pop sDX + leave + ret +ENDPROC TMPL_NM_CMN(TestValueU32) + + +;; +; RTTestValue + DBGFR3RegNmQueryU64. +; +; @param ds:ax The value name and register name separated by a colon. +; @uses nothing +; +BEGINPROC TMPL_NM_CMN(TestValueReg) + push xBP + mov xBP, xSP + push sDX + push sAX + push sSI + pushf + cld + + mov xSI, xAX ; xSI = name + + ; Report it to the host. + cmp byte [g_fbBs2VMMDevTesting], 0 + je .no_vmmdev + + mov dx, VMMDEV_TESTING_IOPORT_CMD + mov eax, VMMDEV_TESTING_CMD_VALUE_REG + out dx, eax + + mov dx, VMMDEV_TESTING_IOPORT_DATA +.next_char: + lodsb + out dx, al + test al, al + jnz .next_char + +.no_vmmdev: + popf + pop sSI + pop sAX + pop sDX + leave + ret +ENDPROC TMPL_NM_CMN(TestValueReg) + + +;; +; Equivalent to RTTestFailed("%s", ds:xAX). +; +; @param ds:xAX Failure explanation. +; @uses nothing +; +BEGINPROC TMPL_NM_CMN(TestFailed) + push xBP + mov xBP, xSP + push sAX + push xDX + + ; Increment the error count. + inc word [g_uscBs2TestErrors] + + ; Print failure message. + call TMPL_NM_CMN(PrintStr) + + ; Report it to the VMMDev. + mov xDX, xAX + mov eax, VMMDEV_TESTING_CMD_FAILED + call TMPL_NM_CMN(testSendStrCmd) + + pop xDX + pop sAX + leave + ret +ENDPROC TMPL_NM_CMN(TestFailed) + + +;; +; Equivalent to RTTestFailed. +; +; @remarks This uses an entirely STACK BASED CALLING CONVENTION where the +; caller does the cleanup (cdecl sans volatile regs). +; +; @param fpszFormat The format string (far pointer on 16-bit +; systems). See StrFormatV for format details. +; @param ... Zero or more format string arguments. +; @uses nothing +; +BEGINPROC TMPL_NM_CMN(TestFailedF) + push xBP + mov xBP, xSP + push sAX + push xDX + push xCX + push xBX +%ifdef TMPL_16BIT + push ds + push es + push fs +%endif + sub xSP, 0400h ; string buffer (1024 bytes) + + ; + ; Format the failure string and call TestFailed. + ; +%ifdef TMPL_16BIT + mov ax, ss ; buffer address. + mov ds, ax + mov ax, sp + mov xDX, 0400h ; buffer size. + les cx, [bp + 4] ; format string + mov bx, ss ; argument list + mov fs, bx + mov bx, bp + add bx, 8 +%else + mov xAX, xSP ; buffer address + mov xDX, 0400h ; buffer size + mov xCX, [xBP + xCB * 2] ; format string + lea xBX, [xBP + xCB * 3] ; argument list. +%endif + call TMPL_NM_CMN(StrFormatV) + call TMPL_NM_CMN(TestFailed) + + add xSP, 0400h +%ifdef TMPL_16BIT + pop fs + pop es + pop ds +%endif + pop xBX + pop xCX + pop xDX + pop sAX + leave + ret +ENDPROC TMPL_NM_CMN(TestFailedF) + + +;; +; Equivalent to RTTestSkipped("%s", ds:xAX). +; +; @param ds:xAX Explanation. +; @uses nothing +; +BEGINPROC TMPL_NM_CMN(TestSkipped) + push xBP + mov xBP, xSP + push sAX + push xDX + + ; Print reason. + call TMPL_NM_CMN(PrintStr) + + ; Report it to the VMMDev. + mov xDX, xAX + mov eax, VMMDEV_TESTING_CMD_SKIPPED + call TMPL_NM_CMN(testSendStrCmd) + + pop xDX + pop sAX + leave + ret +ENDPROC TMPL_NM_CMN(TestSkipped) + + + +;; +; Equivalent to RTTestSubDone. +; +; @uses nothing +; +BEGINPROC TMPL_NM_CMN(TestSubDone) + jmp TMPL_NM_CMN(testSubCleanup) +ENDPROC TMPL_NM_CMN(TestSubDone) + + +;; +; Equivalent to RTTestSummaryAndDestroy, does not return. +; +BEGINPROC TMPL_NM_CMN(TestTerm) + push xBP + mov xBP, xSP + push sAX + push sCX + push xDX + + ; Complete and cleanup any current sub test. + call TMPL_NM_CMN(testSubCleanup) + + ; Print test summary. + mov xAX, [g_npszBs2Test] + call TMPL_NM_CMN(PrintStr) + + mov cx, [g_uscBs2TestErrors] + and ecx, 0ffffh + jnz .failure + + ; success + mov xAX, .s_szSuccess + call TMPL_NM_CMN(PrintStr) + jmp .vmmdev + + ; failure +.failure: + mov xAX, .s_szFailure + call TMPL_NM_CMN(PrintStr) + mov eax, ecx + call TMPL_NM_CMN(PrintU32) + mov xAX, .s_szFailureEnd + call TMPL_NM_CMN(PrintStr) + + ; report to VMMDev +.vmmdev: + cmp byte [g_fbBs2VMMDevTesting], 0 + je .no_vmmdev + + mov dx, VMMDEV_TESTING_IOPORT_CMD + mov eax, VMMDEV_TESTING_CMD_TERM + out dx, eax + + mov dx, VMMDEV_TESTING_IOPORT_DATA + mov eax, ecx + out dx, eax +.no_vmmdev: + + ; Shut down the VM by default. + call TMPL_NM_CMN(Shutdown) + + pop xDX + pop sCX + pop sAX + leave + ret +.s_szSuccess: + db ': SUCCESS', 13, 10, 0 +.s_szFailure: + db ': FAILURE - ', 0 +.s_szFailureEnd: + db ' errors', 13, 10, 0 +ENDPROC TMPL_NM_CMN(TestTerm) + + + + +;; +; Report a result (elapsed time). +; +; @param ds:ax Pointer to the elapsed time. +; @param edx The number of tests executed. +; @param ds:cx The test description. +; +; @users nothing +; +BEGINPROC TMPL_NM_CMN(ReportResult) + push xBP + mov xBP, xSP + push sAX + push sDX + push xCX + +%if 0 + push sDX + push xCX + push sDX + mov edx, [sAX] + push sDX + mov edx, [sAX + 4] + push sDX + push .szDbg + call TMPL_NM_CMN(PrintF) + add xSP, 4 * sCB + xCB + pop sDX + jmp .end_debug +.szDbg: + db 'ReportResult(%RX32.%RX32, %RX32, %s)', 13, 10, 0 +.end_debug: +%endif + + call TMPL_NM_CMN(CalcTestPerSecond) + mov edx, eax + mov xAX, xCX + mov cl, VMMDEV_TESTING_UNIT_INSTRS_PER_SEC + call TMPL_NM_CMN(TestValueU32) + + pop xCX + pop sDX + pop sAX + leave + ret +ENDPROC TMPL_NM_CMN(ReportResult) + + +%ifdef BS2_WITH_TRAPS +;; +; Checks a trap, complains if not the expected one. +; +; @param al The expected trap number. +; @param sDX The expected trap error code. +; @param sCX The expected fault eip. +; @param sBX The expected fault address. +; @returns al=1 and ZF=0 on success. +; @returns al=0 and ZF=1 on failure +; @uses Nothing. +; +BEGINPROC TMPL_NM_CMN(TestCheckTrap) + push xBP + mov xBP, xSP +%define a_u8ExpectedTrapNo byte [xBP - xCB] + push xAX +%define a_uExpectedErr sPRE [xBP - xCB - sCB*1] + push sDX +%define a_uExpectedFaultPC sPRE [xBP - xCB - sCB*2] + push sCX +%define a_uExpectedFaultAddr sPRE [xBP - xCB - sCB*3] + push sBX + + ; Any traps at all? + cmp dword [g_u32cTraps], 0 + jne .trapped + mov xAX, .s_szNoTrap + jmp .failed +.trapped: + + ; Exactly one trap. + cmp dword [g_u32cTraps], 1 + je .one_trap + mov xAX, .s_szToManyTraps + jmp .failed +.one_trap: + + ; The right trap. + cmp byte [g_u8LastTrapNo], al + je .right_trap_no + mov xAX, .s_szWrongTrapNo + jmp .failed +.right_trap_no: + + ; The right error code. + cmp [g_u64LastTrapErr], sDX +%ifndef TMPL_64BIT + jne .bad_err_cd + cmp dword [g_u64LastTrapErr + 4], 0 +%endif + je .right_err_cd +.bad_err_cd: + mov xAX, .s_szWrongErrCd + jmp .failed +.right_err_cd: + + ; The fault PC. + cmp [g_LastTrapRegs + BS2REGS.rip], sCX +%ifndef TMPL_64BIT + jne .bad_pc + cmp dword [g_LastTrapRegs + BS2REGS.rip + 4], 0 +%endif + je .right_pc +.bad_pc: + mov xAX, .s_szWrongPc + jmp .failed +.right_pc: + + + ; The fault address (PF only). + cmp al, 0eh + jne .right_fault_address + cmp [g_LastTrapRegs + BS2REGS.cr2], sBX +%ifndef TMPL_64BIT + jne .bad_fault_address + cmp dword [g_LastTrapRegs + BS2REGS.cr2 + 4], 0 +%endif + je .right_fault_address +.bad_fault_address: + mov xAX, .s_szWrongFaultAddress + jmp .failed +.right_fault_address: + + pop sBX + pop sCX + pop sDX + pop xAX + leave + mov al, 1 + test al, al + ret + + ; + ; Reportfailure + ; +.failed: + mov xDX, xSP ; save xSP - lazy bird. + cmp a_u8ExpectedTrapNo, 0eh + jne .not_pf2 +%ifndef TMPL_64BIT + push dword 0 +%endif + push a_uExpectedFaultAddr +.not_pf1: +%ifndef TMPL_64BIT + push dword 0 +%endif + push a_uExpectedErr +%ifndef TMPL_64BIT + push dword 0 +%endif + push a_uExpectedFaultPC + movzx xBX, a_u8ExpectedTrapNo + push xBX + ; line break + cmp a_u8ExpectedTrapNo, 0eh + jne .not_pf2 +%ifndef TMPL_64BIT + push dword [g_LastTrapRegs + BS2REGS.cr2 + 4] +%endif + push sPRE [g_LastTrapRegs + BS2REGS.cr2] +.not_pf2: +%ifndef TMPL_64BIT + push dword [g_u64LastTrapErr + 4] +%endif + push sPRE [g_u64LastTrapErr] +%ifndef TMPL_64BIT + push dword [g_LastTrapRegs + BS2REGS.rip + 4] +%endif + push sPRE [g_LastTrapRegs + BS2REGS.rip] + movzx xBX, byte [g_u8LastTrapNo] + push xBX + push xAX ; msg + mov xAX, .s_szFailureMsg + cmp a_u8ExpectedTrapNo, 0eh + jne .not_pf3 + mov xAX, .s_szFailurePfMsg +.not_pf3: + push xAX ; format string + call TMPL_NM_CMN(TestFailedF) + mov xSP, xDX ; clean up call frame + +.done: + pop sBX + pop sCX + pop sDX + pop xAX + leave + xor al, al + ret + +.s_szFailureMsg: + db '%s', 13, 10 + db ' got trap %RX8 pc=%RX64 err=%RX64', 13, 10 + db ' expected %RX8 pc=%RX64 err=%RX64', 13, 10, 0 +.s_szFailurePfMsg: + db '%s', 13, 10 + db ' got trap %RX8 pc=%RX64 err=%RX64 cr2=%RX64', 13, 10, + db ' expected %RX8 pc=%RX64 err=%RX64 cr2=%RX64', 13, 10, 0 +.s_szNoTrap: + db 'no traps', 0 +.s_szToManyTraps: + db 'too many traps', 0 +.s_szWrongTrapNo: + db 'wrong trap number', 0 +.s_szWrongErrCd: + db 'wrong error code', 0 +.s_szWrongPc: + db 'wrong xIP', 0 +.s_szWrongFaultAddress: + db 'wrong fault address', 0 +%undef a_u8ExpectedTrapNo +%undef a_u32ExpectedErr +%undef a_u32ExpectedFaultPC +%undef a_u32ExpectedFaultAddr +ENDPROC TMPL_NM_CMN(TestCheckTrap) +%endif ; BS2_WITH_TRAPS + + +%ifdef BS2_WITH_TRAPS +;; +; Installs the active list of trap records (BS2TRAPREC). +; +; @param sAX Flat address of the trap records (BS2TRAPREC). +; Assumes that DS is FLAT. +; @param edx The number of trap records. +; @param sCX Flat image base address, i.e. what BS2TRAPREC.offWhere +; is relative to. +; @returns al=1 and ZF=0 on success. +; @returns al=0 and ZF=1 on failure +; +; @uses sAX (return value) +; +BEGINPROC TMPL_NM_CMN(TestInstallTrapRecs) + push xBP + mov xBP, xSP + push sDX + push sBX + push sCX + push sDI + push sSI + + ; Make sure the record array is within limits. + cmp edx, _4M + jae .nok + + ; Scan the trap records. + mov sDI, sAX + mov esi, edx + or esi, esi + jnz .ok +.next: + cmp dword [sDI + BS2TRAPREC.offWhere], _2G + jae .nok + + cmp dword [sDI + BS2TRAPREC.offResumeAddend], 0 + je .nok + cmp dword [sDI + BS2TRAPREC.offResumeAddend], 0xff + je .nok + + cmp dword [sDI + BS2TRAPREC.u8TrapNo], X86_XCPT_LAST + ja .nok + + ; next. + add sDI, BS2TRAPREC_size + dec esi + jnz .next + + ; Set the global variables. +.ok: + xor esi, esi + mov [g_paTrapRecs + 4], esi + mov [g_paTrapRecs], sAX + mov [g_cTrapRecs], edx + mov [g_iTrapRecLast], esi + mov [g_pTrapRecBase + 4], esi + mov [g_pTrapRecBase], sCX + mov eax, 1 + or eax, eax + +.done: + pop sSI + pop sDI + pop sBX + pop sCX + pop sDX + leave + ret + +.nok: + xor eax, eax + jmp .done +ENDPROC TMPL_NM_CMN(TestInstallTrapRecs) +%endif ; BS2_WITH_TRAPS + + +;; +; Calculate the number of tests executed per second. +; +; @param ds:ax Pointer to the elapsed time. +; @param edx The number of tests executed. +; @returns The tests per second in eax. +; +; @uses eax (return value) +; +BEGINPROC TMPL_NM_CMN(CalcTestPerSecond) + push xBP + mov xBP, xSP + push sDX + push sCX +%ifdef TMPL_16BIT + movzx eax, ax +%endif + + ; Calc NS per test. + mov ecx, edx + cmp ecx, 0 + jz .div_zero + movzx eax, ax + mov edx, [sAX + 4] + cmp edx, ecx + jae .div_overflow + mov eax, [sAX] + shld edx, eax, 10 + shl eax,10 + div ecx ; eax = NS per test + + ; Calc tests per second. + mov ecx, eax + cmp ecx, 0 + jz .div_zero + mov edx, 0xee + mov eax, 0x6b280000 ; 1024G + div ecx ; eax = tests per second + +.done: + pop sCX + pop sDX + leave + ret + +.div_zero: + mov eax, 0 + jmp .done + +.div_overflow: + mov eax, 4242424242 + jmp .done +ENDPROC TMPL_NM_CMN(CalcTestPerSecond) + + +;; +; Calculate the number of iterations for a benchmark based on the time a short +; calibration run too. +; +; @param ds:xAX Pointer to the elapsed time. +; @param edx The number of tests iterations executed. +; @param ecx The desired test length, in seconds. +; @returns The tests iterations in eax. +; +; @uses eax (return value) +; +BEGINPROC TMPL_NM_CMN(CalcBenchmarkIterations) + push xBP + mov xBP, xSP + push sDX + push sCX +%ifdef TMPL_16BIT + movzx eax, ax +%endif + + ; Calc NS per test. + mov ecx, edx + cmp ecx, 0 + jz .div_zero + movzx eax, ax + mov edx, [sAX + 4] + cmp edx, ecx + jae .div_overflow + mov eax, [sAX] + div ecx ; eax = NS per test + + ; Calc tests per second. + mov ecx, eax + cmp ecx, 0 + jz .div_zero + xor edx, edx + mov eax, 1000000000 ; 1G + div ecx ; eax = tests per second + + ; Multiply this up to the desired number of seconds. + mov edx, [xBP - xCB*2] + mul edx + test edx, edx + jnz .mult_32bit_overflow + cmp eax, _64K + jle .too_small + +.done: + pop sCX + pop sDX + leave + ret + +.too_small: + mov eax, _64K + jmp .done + +.mult_32bit_overflow: + mov eax, 0ffff0000h + jmp .done + +.div_zero: + mov eax, [xBP - xCB] + shl eax, 8 + jmp .fudge + +.div_overflow: + mov eax, [xBP - xCB] + shr eax, 4 +.fudge: + add eax, 10 + jmp .done +ENDPROC TMPL_NM_CMN(CalcBenchmarkIterations) + + +;; +; Prints a string on the screen. +; +; @param ds:ax The string to find the length of. +; @returns The string length in ax. +; +; @uses ax (return value) +; +BEGINPROC TMPL_NM_CMN(StrLen) + push xBP + mov xBP, xSP + push xBX + + mov xBX, xAX + dec xBX +.next: + inc xBX + cmp byte [xBX], byte 0 + jnz .next + + xchg xAX, xBX + sub xAX, xBX + + pop xBX + leave + ret +ENDPROC TMPL_NM_CMN(StrLen) + + + +;; +; Simple string format, taking an argument list. +; +; Implemented: +; - %RX8 +; - %RX16 +; - %RX32 +; - %RX64 +; - %s +; +; Planned: +; - %RU8 +; - %RU16 +; - %RU32 +; - %RU64 +; - %RI8 +; - %RI16 +; - %RI32 +; - %RI64 +; +; @param ds:xAX The buffer address. +; @param xDX The buffer size. +; @param es:xCX The format string. +; @param fs:xBX The argument list. +; @uses nothing +; +BEGINPROC TMPL_NM_CMN(StrFormatV) + push xBP + mov xBP, xSP + push sAX + push sDX + push sCX + push sBX + push sDI + push sSI + pushf + cld +%ifdef TMPL_16BIT + push ds + push es + push fs + push gs + + mov si, ds + mov di, es + mov ds, di + mov es, si + mov di, ax ; es:di -> output buffer. + mov si, cx ; ds:si -> format string. +%define a_pArgs [fs:bx] +%define a_pu32ArgsHighDW dword [fs:bx + 4] +%else + mov xDI, xAX ; (es:)xDI -> output buffer. + mov xSI, xCX ; (ds:)xSI -> format string. +%define a_pArgs [xBX] +%define a_pu32ArgsHighDW dword [xBX + 4] +%endif + xchg xCX, xDX ; xCX=buffer size. + + ; + ; Make sure we've got space for a terminator char in the output buffer. + ; + test xCX, xCX + jz .return + dec xCX + jz .done + + ; + ; In this loop we're free to use sDX and (with some caution) sAX. + ; +.format_loop: + lodsb + test al, al + jz .done + cmp al, '%' + je .switch + + ; Emit the character in al if there is room for it. +.emit_al: + test xCX, xCX + jz .done + stosb + dec xCX + jmp .format_loop + + ; Try recognize the format specifier. +.switch: + lodsb + cmp al, 's' + je .switch_case_string + cmp al, 'c' + je .switch_case_char + cmp al, 'R' + jne .switch_default + lodsb + cmp al, 'X' + jne .switch_case_number + cmp al, 'U' + jne .switch_case_number + cmp al, 'I' + jne .switch_case_number + +.switch_default: + test al, al + jz .done + mov al, '!' + jmp .emit_al + + ; parse the number part. +.switch_case_number: + mov ah, al ; ah = {X,U,I} + lodsb + cmp al, '8' + je .switch_case_number_8bit + cmp al, '1' + je .switch_case_number_16bit + cmp al, '3' + je .switch_case_number_32bit + cmp al, '6' + je .switch_case_number_64bit + jmp .switch_default + + + ; + ; Common code for 8-bit, 16-bit and 32-bit. + ; + ; The first part load the value into edx, ah={X,U,I}, + ; al=(max-hex, max-unsigned-dec). + ; +.switch_case_number_8bit: + mov al, (2 << 4) | 2 + movzx edx, byte a_pArgs + add xBX, xCB + cmp ah, 'I' + jne .switch_case_number_common_32bit_hex_or_unsigned + movsx edx, dl + jmp .switch_case_number_common_32bit_signed + +.switch_case_number_16bit: + lodsb + cmp al, '6' + jne .switch_default + mov al, (4 << 4) | 5 + movzx edx, word a_pArgs + add xBX, xCB + cmp ah, 'I' + jne .switch_case_number_common_32bit_hex_or_unsigned + movsx edx, dx + jmp .switch_case_number_common_32bit_signed + +.switch_case_number_32bit: + lodsb + cmp al, '2' + jne .switch_default + mov al, (8 << 4) | 10 + mov edx, dword a_pArgs + add xBX, sCB + cmp ah, 'I' + je .switch_case_number_common_32bit_signed + +.switch_case_number_common_32bit_hex_or_unsigned: + cmp ah, 'X' + jne .switch_case_number_common_32bit_unsigned + shr al, 4 + and xAX, 0fh + cmp xCX, xAX + jb .switch_case_number_bad_buf + call .format_32bit_hex_subroutine + jmp .format_loop + +.switch_case_number_common_32bit_unsigned: + and xAX, 0fh + cmp xCX, xAX + jb .switch_case_number_bad_buf + call .format_32bit_dec_subroutine + jmp .format_loop + +.switch_case_number_common_32bit_signed: + cmp edx, 0 + jge .switch_case_number_common_32bit_unsigned + and xAX, 0fh + inc xAX ; sign char + cmp xCX, xAX + jb .switch_case_number_bad_buf + ; Emit the minus sign, invert the value and join the unsigned formatting. + push xAX + mov al, '-' + stosb + dec xCX + pop xAX + neg edx + call .format_32bit_dec_subroutine + jmp .format_loop + + + ; + ; 64-bit is special, to simplify we treat all formats as hex... + ; +.switch_case_number_64bit: + lodsb + cmp al, '4' + jne .switch_default + cmp ah, 'X' + je .switch_case_number_64bit_hex + cmp ah, 'I' + je .switch_case_number_64bit_signed + jmp .switch_case_number_64bit_unsigned + +.switch_case_number_64bit_hex: + mov eax, dword a_pArgs + mov edx, a_pu32ArgsHighDW + add xBX, 8 + cmp xCX, 8+1+8 + jb .switch_case_number_bad_buf + ; Simple, format it as two 32-bit hex values. + push sAX + mov eax, 8 + call .format_32bit_hex_subroutine + mov al, 27h ; '\'' - how do we escape this with yasm? + stosb + dec xCX + pop sDX + mov eax, 8 + call .format_32bit_hex_subroutine + jmp .format_loop + +.switch_case_number_64bit_unsigned: + cmp xCX, 19 + jb .switch_case_number_bad_buf +.switch_case_number_64bit_unsigned_format_it: + ;; @todo implement me + jmp .switch_case_number_64bit_hex + +.switch_case_number_64bit_signed: + mov eax, dword a_pArgs + mov edx, a_pu32ArgsHighDW + add xBX, 8 + cmp xCX, 20 + jb .switch_case_number_bad_buf + test edx, 080000000h + jz .switch_case_number_64bit_unsigned_format_it + ; Emit the minus sign, invert the value and join the unsigned formatting. + push xAX + mov al, '-' + stosb + dec xCX + pop xAX + neg eax + neg edx + jmp .switch_case_number_64bit_unsigned_format_it + + + ; The remaining buffer is too small to hold the number. +.switch_case_number_bad_buf: + mov al, '^' + jmp .emit_al + + + ; + ; Emit a string. + ; +.switch_case_string: +%ifdef TMPL_16BIT + lgs dx, a_pArgs + add xBX, 4 +%else + mov xDX, a_pArgs + add xBX, xCB +%endif + test xCX, xCX +.switch_case_string_loop: + jz .done +%ifdef TMPL_16BIT + mov al, [gs:edx] +%else + mov al, [xDX] +%endif + test al, al + jz .format_loop + inc xDX + stosb + dec xCX + jmp .switch_case_string_loop + + ; + ; Emit a char. + ; +.switch_case_char: + mov al, byte a_pArgs + add xBX, xCB + jmp .emit_al + + + ; + ; Done, just emit the terminator char. + ; +.done: + xor al, al + stosb + +.return: +%ifdef TMPL_16BIT + pop gs + pop fs + pop es + pop ds +%endif + popf + pop sSI + pop sDI + pop sBX + pop sCX + pop sDX + pop sAX + leave + ret +%undef a_pArgs +%undef a_pu32ArgsHighDW + +;; +; Internal subroutine for formatting a hex number into the buffer. +; @param al The precision (2, 4, 8). +; @param edx The value. +; +; @uses ecx, edi +; +.format_32bit_hex_subroutine: + push xAX + push sDX + push xBX + + ; Rotate edx into position. + mov ebx, 8 + sub bl, al + shl bl, 2 + xchg cl, bl + rol edx, cl + xchg bl, cl + + mov bl, al ; Width counter +.format_32bit_hex_subroutine_next: + rol edx, 4 + mov eax, edx + and eax, 0fh + add sAX, g_achHex + mov al, [cs:sAX] + stosb + dec xCX + dec bl + jnz .format_32bit_hex_subroutine_next + + pop xBX + pop sDX + pop xAX + ret + + +;; +; Internal subroutine for formatting a hex number into the buffer. +; @param al The max precision (2, 5, 10). +; @param edx The value. +; @param xCX Counter register to decrement as characters are emited. +; @param es:xDI Where to write the output, xDI is updated. +; +; @uses xCX, xDI +; +.format_32bit_dec_subroutine: +%if 0 ;; @todo implement this + sub xSP, 20h + ; Format in reverse order into a stack buffer. + + ; Append the stack buffer to the string, reversing it in the process. + + add xSP, 20h +%else + call .format_32bit_hex_subroutine +%endif + ret + +ENDPROC TMPL_NM_CMN(StrFormatV) + + +;; +; Very limited RTStrPrintf version. +; +; @remarks This uses an entirely STACK BASED CALLING CONVENTION where the +; caller does the cleanup (cdecl sans volatile regs). +; +; @param fpszBuf The output buffer. +; @param cbBuf The output buffer size (natural size). +; @param fpszFormat The format string (far pointer in 16-bit). +; See StrFormatV for format. +; @param ... Zero or more format string arguments. +; @uses nothing +; +BEGINPROC TMPL_NM_CMN(StrFormatF) + push xBP + mov xBP, xSP + push xAX + push xDX + push xCX + push xBX +%ifdef TMPL_16BIT + push ds + push es + push fs + + lds xAX, [bp + 04h] + mov dx, [bp + 08h] + les xCX, [bp + 0ah] + mov bx, ss + mov fs, bx + mov bx, bp + add bx, 0eh +%else + mov xAX, [xBP + xCB * 2] + mov xDX, [xBP + xCB * 3] + mov xCX, [xBP + xCB * 4] + lea xBX, [xBP + xCB * 5] +%endif + call TMPL_NM_CMN(StrFormatV) + +%ifdef TMPL_16BIT + pop fs + pop es + pop ds +%endif + pop xBX + pop xCX + pop xDX + pop xAX + leave + ret +ENDPROC TMPL_NM_CMN(StrFormatF) + + +;; +; Dumps the CPU registers. +; +; @uses Nothing. +; +BEGINPROC TMPL_NM_CMN(TestDumpCurrentRegisters) +%ifndef TMPL_64BIT + push xBP + mov xBP, xSP + push eax + pushfd + + push dword [xBP - sCB - 4] ; eflags + mov eax, cr2 + push eax + xor eax, eax + mov eax, gs + push eax + mov eax, fs + push eax + mov eax, es + push eax + mov eax, ds + push eax + mov eax, cs + push eax + + mov eax, cr4 + push eax + mov eax, cr3 + push eax + mov eax, cr0 + push eax + mov eax, ebp ; return EBP + mov xAX, [xBP] + push eax + + mov eax, ebp ; return ESP + add xAX, xCB + push eax + + mov xAX, [xBP + xCB] ; return EIP + %ifdef TMPL_16BIT + movzx eax, ax + %endif + push eax + + push edi + push esi + push edx + push ecx + push ebx + push dword [xBP - sCB] ; eax + + %ifdef TMPL_16BIT + push cs + %endif + push .s_szRegFmt + call TMPL_NM_CMN(PrintF) + + popfd + pop eax + leave + ret + +.s_szRegFmt: + db 'eax=%RX32 ebx=%RX32 ecx=%RX32 edx=%RX32 esi=%RX32 edi=%RX32', 13, 10 + db 'eip=%RX32 esp=%RX32 ebp=%RX32 cr0=%RX32 cr3=%RX32 cr4=%RX32', 13, 10 + db 'cs=%RX16 ds=%RX16 es=%RX16 fs=%RX16 gs=%RX16 ss=%RX16 cr2=%RX32 eflags=%RX32', 13, 10, 0 + +%else ; 64-bit + push .s_szRegFmt + call TMPL_NM_CMN(PrintF) + ret + +.s_szRegFmt: + db 'TestDumpCurrentRegisters not implemented', 13, 10, 0 + +%endif ; 64-bit +ENDPROC TMPL_NM_CMN(TestDumpCurrentRegisters) + + + +;; +; Dumps the CPU registers. +; +; @param ds:xAX Pointer to the register frame to dump. +; @uses Nothing. +; +BEGINPROC TMPL_NM_CMN(TestDumpRegisters) + push xBP + mov xBP, xSP + pushf + push sDX + push sBX + mov xBX, xAX + + cmp byte [xBX + BS2REGS.cBits], 64 + je .dump_64bit_regs + + push -1 ; sanity + mov edx, [xBX + BS2REGS.rflags] + push sDX + mov edx, [xBX + BS2REGS.cr2] + push sDX + xor edx, edx + mov dx, [xBX + BS2REGS.ss] + push xDX + mov dx, [xBX + BS2REGS.gs] + push xDX + mov dx, [xBX + BS2REGS.fs] + push xDX + mov dx, [xBX + BS2REGS.es] + push xDX + mov dx, [xBX + BS2REGS.ds] + push xDX + mov dx, [xBX + BS2REGS.cs] + push xDX + + mov edx, [xBX + BS2REGS.cr4] + push sDX + mov edx, [xBX + BS2REGS.cr3] + push sDX + mov edx, [xBX + BS2REGS.cr0] + push sDX + mov edx, [xBX + BS2REGS.rbp] + push sDX + mov edx, [xBX + BS2REGS.rsp] + push sDX + mov edx, [xBX + BS2REGS.rip] + push sDX + + mov edx, [xBX + BS2REGS.rdi] + push sDX + mov edx, [xBX + BS2REGS.rsi] + push sDX + mov edx, [xBX + BS2REGS.rdx] + push sDX + mov edx, [xBX + BS2REGS.rcx] + push sDX + mov edx, [xBX + BS2REGS.rbx] + push sDX + mov edx, [xBX + BS2REGS.rax] + push sDX + +%ifdef TMPL_16BIT + push cs +%endif + push .s_szReg32Fmt + call TMPL_NM_CMN(PrintF) + jmp .return + +.dump_64bit_regs: +%ifdef TMPL_16BIT + push cs +%endif + push .s_szReg64Fmt + call TMPL_NM_CMN(PrintF) + +.return: + lea xSP, [xBP - sCB*2 - xCB] + pop sBX + pop sDX + popf + leave + ret + +.s_szReg32Fmt: + db 'eax=%RX32 ebx=%RX32 ecx=%RX32 edx=%RX32 esi=%RX32 edi=%RX32', 13, 10 + db 'eip=%RX32 esp=%RX32 ebp=%RX32 cr0=%RX32 cr3=%RX32 cr4=%RX32', 13, 10 + db 'cs=%RX16 ds=%RX16 es=%RX16 fs=%RX16 gs=%RX16 ss=%RX16 cr2=%RX32 eflags=%RX32', 13, 10 + db 0 + +.s_szReg64Fmt: + db 'TestDumpCurrentRegisters not implemented', 13, 10, 0 +ENDPROC TMPL_NM_CMN(TestDumpRegisters) + + +;; +; Saves the CPU registers. +; +; @param ds:xAX Pointer to the register frame to dump. +; @uses Nothing. +; +BEGINPROC TMPL_NM_CMN(TestSaveRegisters) + push xBP + mov xBP, xSP +%ifdef TMPL_16BIT + pushfd +%else + pushf ; - 1*sCB +%endif + push sBX ; - 2*sCB + push sAX ; - 3*sCB + push sDX ; - 4*sCB + + xor edx, edx ; zero register. + mov xBX, xAX ; xBX for addressing, xAX for scratch. + +%ifdef TMPL_64BIT + mov rax, [xSP + sCB*1] + mov [xBX + BS2REGS.rax], rax + mov rax, [xSP + sCB*2] + mov [xBX + BS2REGS.rbx], rax + mov [xBX + BS2REGS.rcx], rcx + mov rax, [xSP] + mov [xBX + BS2REGS.rdx], rax + mov [xBX + BS2REGS.rdi], rdi + mov [xBX + BS2REGS.rsi], rsi + mov rax, [xBP] + mov [xBX + BS2REGS.rbp], rax + lea rax, [xBP + 16] + mov [xBX + BS2REGS.rsp], rax + mov rax, [xBP + 8] + mov [xBX + BS2REGS.rip], rax + mov [xBX + BS2REGS.r8], r8 + mov [xBX + BS2REGS.r9], r9 + mov [xBX + BS2REGS.r10], r10 + mov [xBX + BS2REGS.r11], r11 + mov [xBX + BS2REGS.r12], r12 + mov [xBX + BS2REGS.r13], r13 + mov [xBX + BS2REGS.r14], r14 + mov [xBX + BS2REGS.r15], r15 + mov rax, [xBP - sCB] + mov [xBX + BS2REGS.rflags], rax + mov ax, cs + mov [xBX + BS2REGS.cs], ax + mov ax, ds + mov [xBX + BS2REGS.ds], ax + mov ax, es + mov [xBX + BS2REGS.es], ax + mov ax, fs + mov [xBX + BS2REGS.fs], ax + mov ax, gs + mov [xBX + BS2REGS.gs], ax + mov ax, ss + mov [xBX + BS2REGS.ss], ax + mov byte [xBX + BS2REGS.cBits], 64 + mov [xBX + BS2REGS.pad ], dl + mov [xBX + BS2REGS.pad + 1], dx + mov rax, cr0 + mov [xBX + BS2REGS.cr0], rax + mov rax, cr2 + mov [xBX + BS2REGS.cr2], rax + mov rax, cr3 + mov [xBX + BS2REGS.cr3], rax + mov rax, cr4 + mov [xBX + BS2REGS.cr4], rax + mov rax, cr8 + mov [xBX + BS2REGS.cr8], rax +%else ; !TMPL_64 + mov eax, [xBP - sCB*3] + mov dword [xBX + BS2REGS.rax], eax + mov dword [xBX + BS2REGS.rax + 4], edx + mov eax, [xBP - sCB*2] + mov dword [xBX + BS2REGS.rbx], eax + mov dword [xBX + BS2REGS.rbx + 4], edx + mov dword [xBX + BS2REGS.rcx], ecx + mov dword [xBX + BS2REGS.rcx + 4], edx + mov eax, [xBP - sCB*4] + mov dword [xBX + BS2REGS.rdx], eax + mov dword [xBX + BS2REGS.rdx + 4], edx + mov dword [xBX + BS2REGS.rdi], edi + mov dword [xBX + BS2REGS.rdi + 4], edx + mov dword [xBX + BS2REGS.rsi], esi + mov dword [xBX + BS2REGS.rsi + 4], edx + mov eax, ebp + mov ax, [xBP] + mov dword [xBX + BS2REGS.rbp], eax + mov dword [xBX + BS2REGS.rbp + 4], edx + %ifdef TMPL_16BIT + mov eax, esp + mov ax, bp + sub ax, 4 + %else + lea eax, [ebp + 8] + %endif + mov dword [xBX + BS2REGS.rsp], eax + mov dword [xBX + BS2REGS.rsp + 4], edx + %ifdef TMPL_16BIT + movzx eax, word [xBP + 2] + %else + mov eax, [xBP + 4] + %endif + mov dword [xBX + BS2REGS.rip], eax + mov dword [xBX + BS2REGS.rip + 4], edx + mov dword [xBX + BS2REGS.r8 ], edx + mov dword [xBX + BS2REGS.r8 + 4], edx + mov dword [xBX + BS2REGS.r9 ], edx + mov dword [xBX + BS2REGS.r9 + 4], edx + mov dword [xBX + BS2REGS.r10 ], edx + mov dword [xBX + BS2REGS.r10 + 4], edx + mov dword [xBX + BS2REGS.r11 ], edx + mov dword [xBX + BS2REGS.r11 + 4], edx + mov dword [xBX + BS2REGS.r12 ], edx + mov dword [xBX + BS2REGS.r12 + 4], edx + mov dword [xBX + BS2REGS.r13 ], edx + mov dword [xBX + BS2REGS.r13 + 4], edx + mov dword [xBX + BS2REGS.r14 ], edx + mov dword [xBX + BS2REGS.r14 + 4], edx + mov dword [xBX + BS2REGS.r15 ], edx + mov dword [xBX + BS2REGS.r15 + 4], edx + mov eax, [xBP - sCB] + mov dword [xBX + BS2REGS.rflags], eax + mov dword [xBX + BS2REGS.rflags + 4], edx + mov ax, cs + mov [xBX + BS2REGS.cs], ax + mov ax, ds + mov [xBX + BS2REGS.ds], ax + mov ax, es + mov [xBX + BS2REGS.es], ax + mov ax, fs + mov [xBX + BS2REGS.fs], ax + mov ax, gs + mov [xBX + BS2REGS.gs], ax + mov ax, ss + mov [xBX + BS2REGS.ss], ax + %ifdef TMPL_16BIT + mov byte [xBX + BS2REGS.cBits], 16 + %else + mov byte [xBX + BS2REGS.cBits], 32 + %endif + mov [xBX + BS2REGS.pad ], dl + mov [xBX + BS2REGS.pad + 1], dx + mov eax, cr0 + mov dword [xBX + BS2REGS.cr0], eax + mov dword [xBX + BS2REGS.cr0 + 4], edx + mov eax, cr2 + mov dword [xBX + BS2REGS.cr2], eax + mov dword [xBX + BS2REGS.cr2 + 4], edx + mov eax, cr3 + mov dword [xBX + BS2REGS.cr3], eax + mov dword [xBX + BS2REGS.cr3 + 4], edx + mov eax, cr4 + mov dword [xBX + BS2REGS.cr4], eax + mov dword [xBX + BS2REGS.cr4 + 4], edx + mov dword [xBX + BS2REGS.cr8], edx + mov dword [xBX + BS2REGS.cr8 + 4], edx +%endif ; !TMPL_64 + +.return: + pop sDX + pop sAX + pop sBX +%ifdef TMPL_16BIT + popfd +%else + popf +%endif + leave + ret +ENDPROC TMPL_NM_CMN(TestSaveRegisters) + + +;; +; Restores the CPU registers, except for rsp, rip, cs, ss and ds. +; +; @param ds:xAX Pointer to the register frame to dump. +; @uses All, but RSP, RIP, CS, SS and DS. +; +BEGINPROC TMPL_NM_CMN(TestRestoreRegisters) + push xBP + mov xBP, xSP +%ifdef TMPL_16BIT + pushfd +%else + pushf ; - 1*sCB +%endif + push sBX ; - 2*sCB + push sAX ; - 3*sCB + + mov xBX, xAX ; xBX for addressing, xAX for scratch. + + mov sAX, [xBX + BS2REGS.rax] + mov [xBP - 3*sCB], sAX + mov sAX, [xBX + BS2REGS.rbx] + mov [xBP - 2*sCB], sAX + mov sCX, [xBX + BS2REGS.rcx] + mov sDX, [xBX + BS2REGS.rdx] + mov sDI, [xBX + BS2REGS.rdi] + mov sSI, [xBX + BS2REGS.rsi] + ; skip rsp, rbp or rip. +%ifdef TMPL_64BIT + mov r8, [xBX + BS2REGS.r8] + mov r9, [xBX + BS2REGS.r9] + mov r10, [xBX + BS2REGS.r10] + mov r11, [xBX + BS2REGS.r11] + mov r12, [xBX + BS2REGS.r12] + mov r13, [xBX + BS2REGS.r13] + mov r14, [xBX + BS2REGS.r14] + mov r15, [xBX + BS2REGS.r15] +%endif + mov sAX, [xBX + BS2REGS.rflags] + mov [xBP - sCB], sAX + ; skip cs & ds. + mov ax, [xBX + BS2REGS.es] + mov es, ax + mov ax, [xBX + BS2REGS.fs] + mov fs, ax + mov ax, [xBX + BS2REGS.gs] + mov gs, ax + ; skip ss + mov sAX, [xBX + BS2REGS.cr0] + mov cr0, sAX + mov sAX, [xBX + BS2REGS.cr2] + mov cr2, sAX + mov sAX, [xBX + BS2REGS.cr3] + mov cr3, sAX + mov sAX, [xBX + BS2REGS.cr4] + mov cr4, sAX + +.return: + pop sAX + pop sBX +%ifdef TMPL_16BIT + popfd +%else + popf +%endif + leave + ret +ENDPROC TMPL_NM_CMN(TestRestoreRegisters) + + +;; +; Enables the A20 gate. +; +; @uses Nothing. +; +BEGINPROC TMPL_NM_CMN(Bs2EnableA20) + call TMPL_NM_CMN(Bs2EnableA20ViaPortA) +; call TMPL_NM_CMN(Bs2EnableA20ViaKbd) + ret +ENDPROC TMPL_NM_CMN(Bs2EnableA20) + + +;; +; Disables the A20 gate. +; +; @uses Nothing. +; +BEGINPROC TMPL_NM_CMN(Bs2DisableA20) + ; Must call both because they may be ORed together on real HW. + call TMPL_NM_CMN(Bs2DisableA20ViaKbd) + call TMPL_NM_CMN(Bs2DisableA20ViaPortA) + ret +ENDPROC TMPL_NM_CMN(Bs2DisableA20) + + +;; +; Waits for the keyboard controller to become ready. +; +; @uses Nothing +; +BEGINPROC TMPL_NM_CMN(Bs2KbdWait) + push xAX + +.check_status: + in al, 64h + test al, 1 ; KBD_STAT_OBF + jnz .read_data_and_status + test al, 2 ; KBD_STAT_IBF + jnz .check_status + + pop xAX + ret + +.read_data_and_status: + in al, 60h + jmp .check_status +ENDPROC TMPL_NM_CMN(Bs2KbdWait) + + +;; +; Sends a read command to the keyboard controller and gets the result. +; +; The caller is responsible for making sure the keyboard controller is ready +; for a command (call Bs2KbdWait if unsure). +; +; @param al The read command. +; @returns The value read is returned. +; @uses al (obviously) +; +BEGINPROC TMPL_NM_CMN(Bs2KbdRead) + out 64h, al ; Write the command. + +.check_status: + in al, 64h + test al, 1 ; KBD_STAT_OBF + jz .check_status + + in al, 60h ; Read the data. + ret +ENDPROC TMPL_NM_CMN(Bs2KbdRead) + + +;; +; Sends a write command to the keyboard controller and then sends the data. +; +; The caller is responsible for making sure the keyboard controller is ready +; for a command (call Bs2KbdWait if unsure). +; +; @param al The write command. +; @param ah The data to write. +; @uses Nothing. +; +; @todo Return status? +; +BEGINPROC TMPL_NM_CMN(Bs2KbdWrite) + out 64h, al ; Write the command. + call TMPL_NM_CMN(Bs2KbdWait) + + xchg al, ah + out 60h, al ; Write the data. + call TMPL_NM_CMN(Bs2KbdWait) + xchg al, ah + + ret +ENDPROC TMPL_NM_CMN(Bs2KbdWrite) + + +;; +; Enables the A20 gate via the keyboard controller. +; +; @uses Nothing. +; +BEGINPROC TMPL_NM_CMN(Bs2EnableA20ViaKbd) + push xAX + pushf + cli + + call TMPL_NM_CMN(Bs2KbdWait) + mov al, 0d0h ; KBD_CCMD_READ_OUTPORT + call TMPL_NM_CMN(Bs2KbdRead) + + mov ah, 002h + or ah, al + mov al, 0d1h ; KBD_CCMD_WRITE_OUTPORT + call TMPL_NM_CMN(Bs2KbdWrite) + + mov al, 0ffh ; KBD_CMD_RESET + out 64h, al + call TMPL_NM_CMN(Bs2KbdWait) + + popf + pop xAX + ret +ENDPROC TMPL_NM_CMN(Bs2EnableA20ViaKbd) + + +;; +; Disables the A20 gate via the keyboard controller. +; +; @uses Nothing. +; +BEGINPROC TMPL_NM_CMN(Bs2DisableA20ViaKbd) + push xAX + pushf + cli + + call TMPL_NM_CMN(Bs2KbdWait) + mov al, 0d0h ; KBD_CCMD_READ_OUTPORT + call TMPL_NM_CMN(Bs2KbdRead) + + mov ah, 0fdh ; ~2 + and ah, al + mov al, 0d1h ; KBD_CCMD_WRITE_OUTPORT + call TMPL_NM_CMN(Bs2KbdWrite) + + mov al, 0ffh ; KBD_CMD_RESET + out 64h, al + call TMPL_NM_CMN(Bs2KbdWait) + + popf + pop xAX + ret +ENDPROC TMPL_NM_CMN(Bs2DisableA20ViaKbd) + + +;; +; Enables the A20 gate via control port A (PS/2 style). +; +; @uses Nothing. +; +BEGINPROC TMPL_NM_CMN(Bs2EnableA20ViaPortA) + push xAX + + ; Use Control port A, assuming a PS/2 style system. + in al, 092h + test al, 02h + jnz .done ; avoid trouble writing back the same value. + or al, 2 ; enable the A20 gate. + out 092h, al + +.done: + pop xAX + ret +ENDPROC TMPL_NM_CMN(Bs2EnableA20ViaPortA) + + +;; +; Disables the A20 gate via control port A (PS/2 style). +; +; @uses Nothing. +; +BEGINPROC TMPL_NM_CMN(Bs2DisableA20ViaPortA) + push xAX + + ; Use Control port A, assuming a PS/2 style system. + in al, 092h + test al, 02h + jz .done ; avoid trouble writing back the same value. + and al, 0fdh ; disable the A20 gate. + out 092h, al + +.done: + pop xAX + ret +ENDPROC TMPL_NM_CMN(Bs2DisableA20ViaPortA) + + +;; +; Checks if the no-execution bit is supported. +; +; @returns AL=1 and ZF=0 if supported. +; @returns AL=0 and ZF=1 if not. +; @uses al +; +BEGINPROC TMPL_NM_CMN(Bs2IsNXSupported) + push xBP + mov xBP, xSP + push sBX + push sDX + push sCX + push sAX + + mov eax, 080000000h + cpuid + cmp eax, 080000001h + jb .not_supported + cmp eax, 080001000h + jae .not_supported + + mov eax, 080000001h + cpuid + test edx, X86_CPUID_EXT_FEATURE_EDX_NX + jz .not_supported + + ; supported + pop sAX + mov al, 1 + +.return: + pop sCX + pop sDX + pop sBX + leave + ret +.not_supported: + pop sAX + xor al, al + jmp .return +ENDPROC TMPL_NM_CMN(Bs2IsNXSupported) + + +;; +; Sets EFER.NXE=al if NXE is supported. +; +; @param al 0 if NXE should be disabled, non-zero if it should +; be enabled. +; @uses nothing. +; +BEGINPROC TMPL_NM_CMN(Bs2SetupNX) + push xBP + mov xBP, xSP + push sAX + push sDX + push sCX + + call TMPL_NM_CMN(Bs2IsNXSupported) + jz .done + + mov ecx, MSR_K6_EFER + rdmsr + test byte [xBP - sCB], 0ffh + jz .disable_it + or eax, MSR_K6_EFER_NXE + jmp .set_it +.disable_it: + and eax, ~MSR_K6_EFER_NXE +.set_it: + wrmsr + +.done: + pop sCX + pop sDX + pop sAX + leave + ret +ENDPROC TMPL_NM_CMN(Bs2SetupNX) + + +;; +; Disables NX if supported. +; +; @uses nothing. +; +BEGINPROC TMPL_NM_CMN(Bs2DisableNX) + push xBP + mov xBP, xSP + push xAX + + xor al, al + call TMPL_NM_CMN(Bs2SetupNX) + + pop xAX + leave + ret +ENDPROC TMPL_NM_CMN(Bs2DisableNX) + + +;; +; Enables NX if supported. +; +; @uses nothing. +; +BEGINPROC TMPL_NM_CMN(Bs2EnableNX) + push xBP + mov xBP, xSP + push xAX + + mov al, 1 + call TMPL_NM_CMN(Bs2SetupNX) + + pop xAX + leave + ret +ENDPROC TMPL_NM_CMN(Bs2EnableNX) + + +;; +; Panics if the testing feature of the VMMDev is missing. +; +; A message will be printed. +; +; @uses Nothing. +; +BEGINPROC TMPL_NM_CMN(Bs2PanicIfVMMDevTestingIsMissing) + push xDX + push sAX + + xor eax, eax + mov dx, VMMDEV_TESTING_IOPORT_NOP + in eax, dx + cmp eax, VMMDEV_TESTING_NOP_RET + je .ok + + mov xAX, .s_szMissingVMMDevTesting + call TMPL_NM_CMN(PrintStr) + call Bs2Panic + +.ok: + pop sAX + pop xDX + ret + +.s_szMissingVMMDevTesting: + db 'fatal error: The testing feature of the VMMDevVMMDev is not present!', 13, 10, 0 +ENDPROC TMPL_NM_CMN(Bs2PanicIfVMMDevTestingIsMissing) + + + +%ifdef BS2_WITH_TRAPS + +;; +; Switches to ring-0 from whatever the current mode is. +; +; @uses cs, ss, ds, es, fs, gs +; +BEGINPROC TMPL_NM_CMN(Bs2ToRing0) + push sAX + mov sAX, BS2_SYSCALL_TO_RING0 + int BS2_TRAP_SYSCALL + pop sAX + ret +ENDPROC TMPL_NM_CMN(Bs2ToRing0) + +;; +; Switches to ring-1 from whatever the current mode is. +; +; @uses cs, ss, ds, es, fs, gs +; +BEGINPROC TMPL_NM_CMN(Bs2ToRing1) + push sAX + mov sAX, BS2_SYSCALL_TO_RING1 + int BS2_TRAP_SYSCALL + pop sAX + ret +ENDPROC TMPL_NM_CMN(Bs2ToRing1) + +;; +; Switches to ring-0 from whatever the current mode is. +; +; @uses cs, ss, ds, es, fs, gs +; +BEGINPROC TMPL_NM_CMN(Bs2ToRing2) + push sAX + mov sAX, BS2_SYSCALL_TO_RING2 + int BS2_TRAP_SYSCALL + pop sAX + ret +ENDPROC TMPL_NM_CMN(Bs2ToRing2) + +;; +; Switches to ring-3 from whatever the current mode is. +; +; @uses cs, ss, ds, es, fs, gs +; +BEGINPROC TMPL_NM_CMN(Bs2ToRing3) + push sAX + mov sAX, BS2_SYSCALL_TO_RING3 + int BS2_TRAP_SYSCALL + pop sAX + ret +ENDPROC TMPL_NM_CMN(Bs2ToRing3) + +;; +; Switches the given ring from whatever the current mode is. +; +; @param AL The desired ring. +; @uses cs, ss, ds, es, fs, gs +; +BEGINPROC TMPL_NM_CMN(Bs2ToRingN) + pushf + cmp al, 3 + je .ring3 + cmp al, 2 + je .ring2 + cmp al, 1 + je .ring1 +.ring0: + call TMPL_NM_CMN(Bs2ToRing0) +.done: + popf + ret + +.ring1: + call TMPL_NM_CMN(Bs2ToRing1) + jmp .done +.ring2: + call TMPL_NM_CMN(Bs2ToRing2) + jmp .done +.ring3: + call TMPL_NM_CMN(Bs2ToRing3) + jmp .done +ENDPROC TMPL_NM_CMN(Bs2ToRingN) + +%endif ; BS2_WITH_TRAPS + + + +; +; Wrapper for dynamically calling the right specific method. +; This avoid putting large portions of the code in the 2nd template. +; + +TMPL_NM_CMN(g_pfnPrintStrInternal): TMPL_PTR_DEF 0 +TMPL_NM_CMN(g_pfnPrintChrInternal): TMPL_PTR_DEF 0 + +BEGINPROC TMPL_NM_CMN(PrintStr) + jmp [TMPL_NM_CMN(g_pfnPrintStrInternal)] +ENDPROC TMPL_NM_CMN(PrintStr) + +BEGINPROC TMPL_NM_CMN(PrintChr) + jmp [TMPL_NM_CMN(g_pfnPrintChrInternal)] +ENDPROC TMPL_NM_CMN(PrintChr) + + +%include "bootsector2-template-footer.mac" + diff --git a/src/VBox/ValidationKit/bootsectors/bootsector2-common-routines-template-2.mac b/src/VBox/ValidationKit/bootsectors/bootsector2-common-routines-template-2.mac new file mode 100644 index 00000000..c53e9826 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bootsector2-common-routines-template-2.mac @@ -0,0 +1,214 @@ +; $Id: bootsector2-common-routines-template-2.mac $ +;; @file +; bootsector2 common routines - template containing code specific to each mode. +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + +%include "bootsector2-template-header.mac" +ALIGNCODE(32) +GLOBALNAME TMPL_NM(g_szMode) + db TMPL_MODE_STR, 0 + + +;; +; Prints a string on the screen. +; +; @param ds:ax The string to print (null terminated). +; +; @uses nothing +; +BEGINPROC TMPL_NM(PrintStr) + push xBP + mov xBP, xSP + push xAX + push xBX + push xSI + + mov xSI, xAX +.next: + lodsb + test al, al + jz .done +%ifdef TMPL_HAVE_BIOS + mov bx, 0ff00h + mov ah, 0eh + int 10h +%else + call TMPL_NM(PrintChr) +%endif + jmp .next + +.done: + pop xSI + pop xBX + pop xAX + leave + ret +ENDPROC TMPL_NM(PrintStr) + + +;; +; Prints a string on the screen. +; +; @param al The character to print. +; +; @uses nothing +; +BEGINCODELOW +BEGINPROC TMPL_NM(PrintChr) + push xBP + mov xBP, xSP + push xAX + push xBX + +%ifndef TMPL_HAVE_BIOS + %ifdef BS2_WITH_TRAPS + mov bx, cs + and xBX, 0x3 + push xBX + jz .ring_ok + call TMPL_NM_CMN(Bs2ToRing0) +.ring_ok: + %endif + + mov bl, al + call TMPL_NM(LeaveCpuMode) + mov al, bl +BITS 16 +%endif + + mov bx, 0ff00h + mov ah, 0eh + int 10h + +%ifndef TMPL_HAVE_BIOS + call TMPL_NM(EnterCpuMode) +BITS TMPL_BITS + %ifdef BS2_WITH_TRAPS + pop xAX + test al, al + jz .ring_restored + call TMPL_NM_CMN(Bs2ToRingN) +.ring_restored: + %endif +%endif + + pop xBX + pop xAX + leave + ret +ENDPROC TMPL_NM(PrintChr) +TMPL_BEGINCODE + + +%ifndef TMPL_HAVE_BIOS + +;; +; Leaves the current CPU mode and returns to real mode. +; +; @uses nothing +; +BEGINPROC TMPL_NM(LeaveCpuMode) + jmp TMPL_NM(Bs2ExitMode) +ENDPROC TMPL_NM(LeaveCpuMode) + + +;; +; Undo what LeaveCpuMode did. +; +; @uses nothing +; +BEGINCODELOW +BITS 16 +BEGINPROC TMPL_NM(EnterCpuMode) + jmp TMPL_NM(Bs2EnterMode_rm) +ENDPROC TMPL_NM(EnterCpuMode) +TMPL_BEGINCODE +BITS TMPL_BITS + +%endif ; TMPL_HAVE_BIOS + + +;; +; Sets the global variable for the current CPU mode. +; +; @uses nothing. +; +BEGINPROC TMPL_NM(SetCpuModeGlobals) +%ifdef TMPL_CMN_PE + %ifdef BS2_INC_PE16 + mov word [g_pfnPrintStrInternal_p16], PrintStr_pe16 + mov word [g_pfnPrintChrInternal_p16], PrintChr_pe16 + %endif + %ifdef BS2_INC_PE32 + mov dword [g_pfnPrintStrInternal_p32], PrintStr_pe32 + mov dword [g_pfnPrintChrInternal_p32], PrintChr_pe32 + %endif + +%elifdef TMPL_CMN_PP + %ifdef BS2_INC_PP16 + mov word [g_pfnPrintStrInternal_p16], PrintStr_pp16 + mov word [g_pfnPrintChrInternal_p16], PrintChr_pp16 + %endif + %ifdef BS2_INC_PP32 + mov dword [g_pfnPrintStrInternal_p32], PrintStr_pp32 + mov dword [g_pfnPrintChrInternal_p32], PrintChr_pp32 + %endif + +%elifdef TMPL_CMN_PAE + %ifdef BS2_INC_PAE16 + mov word [g_pfnPrintStrInternal_p16], PrintStr_pae16 + mov word [g_pfnPrintChrInternal_p16], PrintChr_pae16 + %endif + %ifdef BS2_INC_PAE32 + mov dword [g_pfnPrintStrInternal_p32], PrintStr_pae32 + mov dword [g_pfnPrintChrInternal_p32], PrintChr_pae32 + %endif + +%elifdef TMPL_CMN_LM + %ifdef BS2_INC_LM16 + mov word [g_pfnPrintStrInternal_p16], PrintStr_lm16 + mov word [g_pfnPrintChrInternal_p16], PrintChr_lm16 + %endif + %ifdef BS2_INC_LM32 + mov dword [g_pfnPrintStrInternal_p32], PrintStr_lm32 + mov dword [g_pfnPrintChrInternal_p32], PrintChr_lm32 + %endif + %ifdef BS2_INC_LM64 + mov dword [g_pfnPrintStrInternal_p64], PrintStr_lm64 + mov dword [g_pfnPrintChrInternal_p64], PrintChr_lm64 + %endif + +%elifdef TMPL_16BIT + mov word [TMPL_NM_CMN(g_pfnPrintStrInternal)], TMPL_NM(PrintStr) + mov word [TMPL_NM_CMN(g_pfnPrintChrInternal)], TMPL_NM(PrintChr) +%else + %error "missing case" +%endif + ret +ENDPROC TMPL_NM(SetCpuModeGlobals) + + + +%include "bootsector2-template-footer.mac" + diff --git a/src/VBox/ValidationKit/bootsectors/bootsector2-common-routines.mac b/src/VBox/ValidationKit/bootsectors/bootsector2-common-routines.mac new file mode 100644 index 00000000..5aae57a0 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bootsector2-common-routines.mac @@ -0,0 +1,222 @@ +; $Id: bootsector2-common-routines.mac $ +;; @file +; Common bootsector routines. +; +; This is just a bit file with common code that can be included at the end of +; a bootsector2-xxx.asm file. Conventions (used elsewhere as well): +; - _rm - real-mode function suffix. +; - _r86 - common real and virtual 8086 mode suffix. +; - _p16 - common 16-bit protected mode suffix. +; - _p32 - common 32-bit protected mode suffix. +; - _p64 - common 64-bit long mode suffix. +; - _pe16 - 16-bit unpaged protected mode suffix. +; - _pe32 - 32-bit unpaged protected mode suffix. +; - _pev86 - v8086 unpaged protected mode suffix. +; - _pp16 - 16-bit paged protected mode suffix. +; - _pp32 - 32-bit paged protected mode suffix. +; - _ppv86 - v8086 paged protected mode suffix. +; - _pae16 - 16-bit pae protected mode suffix. +; - _pae32 - 32-bit pae protected mode suffix. +; - _paev86- v8086 pae protected mode suffix. +; - _lm16 - 16-bit long mode suffix. +; - _lm32 - 32-bit long mode suffix. +; - _lm64 - 64-bit long mode suffix. +; +; The routines uses a custom register based calling convention for all cpu +; modes so that the users can template multi mode code. To make life easy for +; the programmer all registers are preserved with the exception of rflags and +; any return registers that may be used. Routines that does not return +; anything will only clobber eflags. +; +; The parameter register allocation order: +; rax, rdx, rcx, rbx, rsi, rdi(, r8, r9, r10, r11) +; +; When pointers are passed by 16-bit code, segments registers are allocated in +; the following order: +; ds, es, fs, gs. +; +; The return register allocations are: +; - edx:eax for 64-bit values in 16 and 32-bit mode, +; - eax for 32-bit, +; - ax for 16-bit, +; - al for 8-bit. +; +; Routines may use other calling convensions will be named differently. +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + + +;******************************************************************************* +;* Structures and Typedefs * +;******************************************************************************* + + +;******************************************************************************* +;* Global Variables * +;******************************************************************************* +BEGINCODELOW +ALIGNDATA(32) +;; Indicates whether the VMMDev is operational. +GLOBALNAME g_fbBs2VMMDevTesting + db 1 + db 0 ; padding + +;; The test name (DS16:xxx). +g_npszBs2Test: + dd 0 +;; The number of tests that have failed. +g_uscBs2TestErrors: + dw 0 +;; The subtest name (DS16:xxx). +g_npszBs2SubTest + dd 0 +;; The start error count of the current subtest. +g_uscBs2SubTestAtErrors: + dw 0 +;; Whether we've reported the sub-test result or not. +g_fbBs2SubTestReported: + db 0 + db 0 ; padding +;; The number of sub tests. +g_uscBs2SubTests: + dw 0 +;; The number of sub tests that failed. +g_uscBs2SubTestsFailed: + dw 0 + + +;; VMMDEV_TESTING_UNIT_XXX -> string +g_aszBs2TestUnitNames: + db 'i','n','v', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + db '%', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + db 'b','y','t','e','s', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + db 'b','y','t','e','s','/','s', 0, 0, 0, 0, 0, 0, 0, 0, 0 + db 'K','B', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + db 'K','B','/','s', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + db 'M','B', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + db 'M','B','/','s', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + db 'p','a','c','k','e','t','s', 0, 0, 0, 0, 0, 0, 0, 0, 0 + db 'p','a','c','k','e','t','s','/','s', 0, 0, 0, 0, 0, 0, 0 + db 'f','r','a','m','e','s', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + db 'f','r','a','m','e','s','/', 0, 0, 0, 0, 0, 0, 0, 0, 0 + db 'o','c','c', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + db 'o','c','c','/','s', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + db 'r','n','d','t','r','p', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + db 'c','a','l','l','s', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + db 'c','a','l','l','s','/','s', 0, 0, 0, 0, 0, 0, 0, 0, 0 + db 's', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + db 'm','s', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + db 'n','s', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + db 'n','s','/','c','a','l','l', 0, 0, 0, 0, 0, 0, 0, 0, 0 + db 'n','s','/','f','r','a','m','e', 0, 0, 0, 0, 0, 0, 0, 0 + db 'n','s','/','o','c','c', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + db 'n','s','/','p','a','c','k','e','t', 0, 0, 0, 0, 0, 0, 0 + db 'n','s','/','r','n','d','t','r','p', 0, 0, 0, 0, 0, 0, 0 + db 'i','n','s', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + db 'i','n','s','/','s', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; none + db 'p','p','1','k', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + db 'p','p','1','0','k', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + db 'p','p','m', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + db 'p','p','b', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + ; 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, a, b, c, d, e, f + + +; +; Instantiate the common template code. +; +%ifdef BS2_INC_CMN_R86 + %define TMPL_RM + %include "bootsector2-common-routines-template-1.mac" +%endif +%ifdef BS2_INC_CMN_P16 + %define TMPL_PE16 + %include "bootsector2-common-routines-template-1.mac" +%endif +%ifdef BS2_INC_CMN_P32 + %define TMPL_PE32 + %include "bootsector2-common-routines-template-1.mac" +%endif +%ifdef BS2_INC_LM64 + %define TMPL_LM64 + %include "bootsector2-common-routines-template-1.mac" +%endif + +; +; Instantiate the mode specific code. +; +%ifdef BS2_INC_RM + %define TMPL_RM + %include "bootsector2-common-routines-template-2.mac" +%endif +%ifdef BS2_INC_PE16 + %define TMPL_PE16 + %include "bootsector2-common-routines-template-2.mac" +%endif +%ifdef BS2_INC_PE32 + %define TMPL_PE32 + %include "bootsector2-common-routines-template-2.mac" +%endif +%ifdef BS2_INC_PEV86 + %define TMPL_PEV86 + %include "bootsector2-common-routines-template-2.mac" +%endif +%ifdef BS2_INC_PP16 + %define TMPL_PP16 + %include "bootsector2-common-routines-template-2.mac" +%endif +%ifdef BS2_INC_PP32 + %define TMPL_PP32 + %include "bootsector2-common-routines-template-2.mac" +%endif +%ifdef BS2_INC_PPV86 + %define TMPL_PPV86 + %include "bootsector2-common-routines-template-2.mac" +%endif +%ifdef BS2_INC_PAE16 + %define TMPL_PAE16 + %include "bootsector2-common-routines-template-2.mac" +%endif +%ifdef BS2_INC_PAE32 + %define TMPL_PAE32 + %include "bootsector2-common-routines-template-2.mac" +%endif +%ifdef BS2_INC_PAEV86 + %define TMPL_PAEV86 + %include "bootsector2-common-routines-template-2.mac" +%endif +%ifdef BS2_INC_LM16 + %define TMPL_LM16 + %include "bootsector2-common-routines-template-2.mac" +%endif +%ifdef BS2_INC_LM32 + %define TMPL_LM32 + %include "bootsector2-common-routines-template-2.mac" +%endif +%ifdef BS2_INC_LM64 + %define TMPL_LM64 + %include "bootsector2-common-routines-template-2.mac" +%endif + +BEGINCODELOW + diff --git a/src/VBox/ValidationKit/bootsectors/bootsector2-common-traprec-template.mac b/src/VBox/ValidationKit/bootsectors/bootsector2-common-traprec-template.mac new file mode 100644 index 00000000..03faedab --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bootsector2-common-traprec-template.mac @@ -0,0 +1,105 @@ +; $Id: bootsector2-common-traprec-template.mac $ +;; @file +; Boot sector 2 - Trap Records, Code Template. +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + +%include "bootsector2-template-header.mac" + + +;; +; Internal worker for reporting a missing trap +; +; The callee cleans up the arguments on the stack. +; +; @param [xBP + xCB*2] bExpected Expected exception number. +; @param [xBP + xCB*2+1] szExpected The name of the exception (2 bytes + terminator). +; @uses None +; +BEGINPROC TMPL_NM_CMN(TestFailedMissingTrapInternal) + push xBP + mov xBP, xSP + pushf + push sAX + + movzx eax, byte [xBP + xCB*2] + push xAX + lea sAX, [sBP + xCB*2+1] +%ifdef TMPL_16BIT + push ss +%endif + push xAX +%ifdef TMPL_16BIT + push cs +%endif + push .szFmt + call TMPL_NM_CMN(TestFailedF) +%ifdef TMPL_16BIT + add xSP, xCB*5 +%else + add xSP, xCB*3 +%endif + + pop sAX + popf + leave + ret sCB +.szFmt: db 'Missing trap #%s (%RX8)', 13, 10, 0 +ENDPROC TMPL_NM_CMN(TestFailedMissingTrapInternal) + +%ifndef TestFailedMissingTrapTemplate_defined + ;; + ; Internal template. + %macro TestFailedMissingTrapTemplate 4 + BEGINPROC TMPL_NM_CMN(TestFailedMissingTrap_%1) + push dword RT_MAKE_U32_FROM_U8(%1, %2, %3, %4) + call TMPL_NM_CMN(TestFailedMissingTrapInternal) + ret + ENDPROC TMPL_NM_CMN(TestFailedMissingTrap_%1) + %endmacro + %define TestFailedMissingTrapTemplate_defined +%endif + +TestFailedMissingTrapTemplate X86_XCPT_DE, 'D', 'E', 0 +TestFailedMissingTrapTemplate X86_XCPT_DB, 'D', 'B', 0 +TestFailedMissingTrapTemplate X86_XCPT_NMI, 'N', 'M', 0 +TestFailedMissingTrapTemplate X86_XCPT_BP, 'B', 'P', 0 +TestFailedMissingTrapTemplate X86_XCPT_OF, 'O', 'F', 0 +TestFailedMissingTrapTemplate X86_XCPT_BR, 'B', 'R', 0 +TestFailedMissingTrapTemplate X86_XCPT_UD, 'U', 'D', 0 +TestFailedMissingTrapTemplate X86_XCPT_NM, 'N', 'M', 0 +;TestFailedMissingTrapTemplate X86_XCPT_DF, 'D', 'F', 0 +;TestFailedMissingTrapTemplate X86_XCPT_CO_SEG_OVERRUN, 'C', 'O', 0 +TestFailedMissingTrapTemplate X86_XCPT_TS, 'T', 'S', 0 +TestFailedMissingTrapTemplate X86_XCPT_NP, 'N', 'P', 0 +TestFailedMissingTrapTemplate X86_XCPT_SS, 'S', 'S', 0 +TestFailedMissingTrapTemplate X86_XCPT_GP, 'G', 'P', 0 +TestFailedMissingTrapTemplate X86_XCPT_PF, 'P', 'F', 0 +TestFailedMissingTrapTemplate X86_XCPT_MF, 'M', 'F', 0 +TestFailedMissingTrapTemplate X86_XCPT_AC, 'A', 'C', 0 +;TestFailedMissingTrapTemplate X86_XCPT_MC, 'M', 'C', 0 +TestFailedMissingTrapTemplate X86_XCPT_XF, 'X', 'F', 0 + + +%include "bootsector2-template-footer.mac" + diff --git a/src/VBox/ValidationKit/bootsectors/bootsector2-common-traprec.mac b/src/VBox/ValidationKit/bootsectors/bootsector2-common-traprec.mac new file mode 100644 index 00000000..441fcd7d --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bootsector2-common-traprec.mac @@ -0,0 +1,199 @@ +; $Id: bootsector2-common-traprec.mac $ +;; @file +; Boot sector 2 - Trap Records. +; +; @note Don't forget to cinldue bootsector2-common-traprec-end.mac! +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + +%ifndef ___bootsector2_common_traprec_mac___ +%define ___bootsector2_common_traprec_mac___ + + +;******************************************************************************* +;* Header Files * +;******************************************************************************* +%include "iprt/x86.mac" + + +;******************************************************************************* +;* Defined Constants And Macros * +;******************************************************************************* +;; +; The base address for the records (only important for 64-bit code +; loaded above 4GB). +; We use 0 by default so we don't create too complex expressions for YASM. +%ifndef BS2_TRAP_RECS_BASE + %define BS2_TRAP_RECS_BASE 0 +%endif + +;; +; Macro to emit an trapping instruction. +; +; @param 1 The trap number (X86_XCPT_XXX). +; @param 2 The error code, 0 if none. +; @param 3+ The instruction. +; +; @sa BS2_TRAP_BRANCH_INSTR +; +%macro BS2_TRAP_INSTR 3+, + [section .traprecs] + istruc BS2TRAPREC + at BS2TRAPREC.offWhere, dd (%%trapinstr - BS2_TRAP_RECS_BASE) + at BS2TRAPREC.offResumeAddend, db (%%resume - %%trapinstr) + at BS2TRAPREC.u8TrapNo, db %1 + at BS2TRAPREC.u16ErrCd, dw %2 + iend + __SECT__ + %if %1 != X86_XCPT_BP + %%trapinstr: + %3 + %else + %3 + %%trapinstr: + %endif + call TMPL_NM_CMN(TestFailedMissingTrap_ %+ %1) + %%resume: +%endmacro + +;; +; Macro to emit an trapping instruction. +; +; @param 1 The trap number (X86_XCPT_XXX). +; @param 2 The error code, 0 if none. +; @param 3 The name of the branch label. +; @param 4+ The instruction. +; +%macro BS2_TRAP_BRANCH_INSTR 4+, + [section .traprecs] + istruc BS2TRAPREC + at BS2TRAPREC.offWhere, dd (%%trapinstr - BS2_TRAP_RECS_BASE) + at BS2TRAPREC.offResumeAddend, db (%%resume - %%trapinstr) + at BS2TRAPREC.u8TrapNo, db %1 + at BS2TRAPREC.u16ErrCd, dw %2 + iend + __SECT__ + %%trapinstr: + %4 + %3: + call TMPL_NM_CMN(TestFailedMissingTrap_ %+ %1) + %%resume: +%endmacro + +;; +; Sets up the trap records section. +; @internal +%macro BS2_TRAP_RECS_BEGIN 0, + [section .traprecs] ; Declared in bootsector2-common-init-code.mac + dq 0ffffffffeeeeeeeeh +g_aTrapRecs: + __SECT__ +%endmacro + +;; +; Terminates the trap records section. +; @internal +%macro BS2_TRAP_RECS_END 0, + [section .traprecs] +g_aTrapRecsEnd: + dq 0ddddddddcccccccch + __SECT__ +%endmacro + + +;; +; Macro for installing the trap records. +; +; This must be invoked prior to the traps. +; +; @uses Stack +; +%macro BS2_TRAP_RECS_INSTALL 0, + push sAX + push sDX + push sCX + + mov sAX, NAME(g_aTrapRecs) + mov edx, NAME(g_aTrapRecsEnd) - NAME(g_aTrapRecs) + shr edx, BS2TRAPREC_SIZE_SHIFT + mov sCX, BS2_TRAP_RECS_BASE + call TMPL_NM_CMN(TestInstallTrapRecs) + + pop sAX + pop sDX + pop sCX +%endmacro + + +;; +; Macro for uninstalling the trap records. +; +; @uses Stack +; +%macro BS2_TRAP_RECS_UNINSTALL 0, + push sAX + push sDX + push sCX + + xor sAX, sAX + xor edx, edx + xor sCX, sCX + call TMPL_NM_CMN(TestInstallTrapRecs) + + pop sAX + pop sDX + pop sCX +%endmacro + + +; +; Setup the trap record segment. +; +BS2_TRAP_RECS_BEGIN +BEGINCODELOW + + +; +; Instantiate code templates. +; +%ifdef BS2_INC_CMN_R86 + %define TMPL_RM + %include "bootsector2-common-traprec-template.mac" +%endif +%ifdef BS2_INC_CMN_P16 + %define TMPL_PE16 + %include "bootsector2-common-traprec-template.mac" +%endif +%ifdef BS2_INC_CMN_P32 + %define TMPL_PE32 + %include "bootsector2-common-traprec-template.mac" +%endif +%ifdef BS2_INC_LM64 + %define TMPL_LM64 + %include "bootsector2-common-traprec-template.mac" +%endif + +BEGINCODELOW + +%endif + diff --git a/src/VBox/ValidationKit/bootsectors/bootsector2-cpu-a20-1-template.mac b/src/VBox/ValidationKit/bootsectors/bootsector2-cpu-a20-1-template.mac new file mode 100644 index 00000000..e000f748 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bootsector2-cpu-a20-1-template.mac @@ -0,0 +1,375 @@ +; $Id: bootsector2-cpu-a20-1-template.mac $ +;; @file +; bootsector2 A20 - multi mode template. +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + + +%include "bootsector2-template-header.mac" + + +;; +; Inner loop dealing with one 64KB segment. +; +BEGINPROC TMPL_NM(TestA20_EnabledInner) +.inner_loop: + mov ah, [es:xDI] + mov al, [ds:xSI] + cmp al, ah + jne .inner_next + + not al + mov [es:xDI], al + cmp al, [ds:xSI] + mov [es:xDI], ah + je .failed + +.inner_next: + inc xDI + inc xSI + dec ecx + jnz .inner_loop + + clc + ret + +.failed: + push sBX + push sAX + push sSI + push sDI +%ifdef TMPL_16BIT + push cs +%endif + push .s_szModifiyError + call TMPL_NM_CMN(TestFailedF) + add xSP, sCB * 5 + stc + ret +.s_szModifiyError: + db TMPL_MODE_STR, '- Same memory; EDI=%RX32 ESI=%RX32 EAX=%RX32 EBX=%RX32', 13, 10, 0 +ENDPROC TMPL_NM(TestA20_EnabledInner) + + +;; +; Inner loop dealing with one 64KB segment. +; +BEGINPROC TMPL_NM(TestA20_DisabledInner) +.inner_loop: + mov ah, [es:xDI] + mov al, [ds:xSI] + cmp al, ah + jne .failed1 + + not al + mov [es:xDI], al + cmp al, [ds:xSI] + mov [es:xDI], ah + jne .failed2 + + inc xDI + inc xSI + dec ecx + jnz .inner_loop + + clc + ret + +.failed1: + push sCX + push sBX + push sAX + push sSI + push sDI +%ifdef TMPL_16BIT + push cs +%endif + push .s_szNotEqual + call TMPL_NM_CMN(TestFailedF) + add xSP, sCB * 6 + stc + ret +.s_szNotEqual: + db TMPL_MODE_STR, ' - Not equal; EDI=%RX32 ESI=%RX32 EAX=%RX32 EBX=%RX32 ECX=%RX32', 13, 10, 0 + +.failed2: + push sCX + push sBX + push sAX + push sSI + push sDI +%ifdef TMPL_16BIT + push cs +%endif + push .s_szModifiyError + call TMPL_NM_CMN(TestFailedF) + add xSP, sCB * 6 + stc + ret + +.s_szModifiyError: + db TMPL_MODE_STR, ' - Modify error; EDI=%RX32 ESI=%RX32 EAX=%RX32 EBX=%RX32 ECX=%RX32', 13, 10, 0 +ENDPROC TMPL_NM(TestA20_DisabledInner) + + +;; +; Scans memory calling sDX for each segment. +; +BEGINPROC TMPL_NM(TestA20_ScanMemory) + push sAX + push sBX + push sCX + push sDX + push sSI + push sDI + pushf + cli +%ifdef TMPL_16BIT + push es + push ds +%endif + + ; + ; The outer loop walks a segment (64 KB) at a time. + ; + mov ebx, _1M +.outer_loop: + + ; Set up the registers. +%ifdef TMPL_CMN_R86 + mov ax, 0ffffh + mov edi, 00010h + mov es, ax + mov ax, 00000h + mov esi, 00000h + mov ds, ax + mov ecx, 01000h ; at 101000 there is a VMMDevTesting MMIO page. +%elifdef TMPL_16BIT + ;; @todo need a selector we can modify. + jmp .done + +%else + mov edi, ebx + mov esi, ebx + and esi, ~_1M + mov ecx, _64K +%endif +%ifndef TMPL_CMN_R86 + ; Should we skip this segment or only check parts of it? + cmp esi, edi ; affected by A20? + je .outer_next + +%if BS2_PXX_LAST != 09ffffh + %error BS2_PXX_LAST does not have the expected value. +%endif + cmp ebx, BS2_PXX_BASE + _1M ; don't mess with page tables, stacks, MMIO or ROMs. + jb .not_low_rom_mmio_region + cmp ebx, _1M + _1M + jb .outer_next +.not_low_rom_mmio_region: + + cmp ebx, BS2_ADDR + _1M + ja .not_bs2 + mov ecx, BS2_ADDR ; don't overwrite our own code. +.not_bs2: + cmp ebx, _1M + jne .not_VMMDevTestingMMIO + mov ecx, 1000h ; don't bother with the MMIO +.not_VMMDevTestingMMIO: +%endif ; TMPL_CMN_R86 + + ; Invoke the callback. + call xDX + jc .failure + +%ifndef TMPL_CMN_R86 +.outer_next: + add ebx, _64K + cmp ebx, 32*_1M + jbe .outer_loop +%endif + +.done: +%ifdef TMPL_16BIT + pop ds + pop es +%endif + popf + pop sDI + pop sSI + pop sDX + pop sCX + pop sBX + pop sAX + ret + +.failure: +%if 1 + cmp ebx, _1M + je .contine_at_next_MB + cmp ebx, _2M + je .contine_at_next_MB + cmp ebx, _1M + _2M + je .contine_at_next_MB + cmp ebx, _4M + je .contine_at_next_MB +%endif + jmp .done + +.contine_at_next_MB: + add ebx, _1M + jmp .outer_loop +ENDPROC TMPL_NM(TestA20_ScanMemory) + + +BEGINPROC TMPL_NM(TestA20_Enabled) + push sDX + mov xDX, TMPL_NM(TestA20_EnabledInner) + call TMPL_NM(TestA20_ScanMemory) + pop sDX + ret +ENDPROC TMPL_NM(TestA20_Enabled) + + +;; +; Checks that the first 64KB at 1MB wraps is the same physical memory as at +; address 0. +; +BEGINPROC TMPL_NM(TestA20_Disabled) + push sDX + mov xDX, TMPL_NM(TestA20_DisabledInner) + call TMPL_NM(TestA20_ScanMemory) + pop sDX + ret +ENDPROC TMPL_NM(TestA20_Disabled) + + +BEGINPROC TMPL_NM(TestA20_FlushAll) + push sAX + wbinvd + mov sAX, cr3 + mov cr3, sAX + wbinvd + pop sAX + ret +ENDPROC TMPL_NM(TestA20_FlushAll) + + + +;; +; Do the A20 tests for this mode. +; +; @uses nothing +; +BEGINCODELOW +BITS 16 +BEGINPROC TMPL_NM(TestA20_rm) + push eax + + mov ax, .s_szTestName + call TestSub_r86 + + call TMPL_NM(Bs2IsModeSupported_rm) + jz .skip_not_supported + + ; + ; Do tests with A20 enabled. + ; + call Bs2EnableA20_r86 + call TMPL_NM(Bs2EnterMode_rm) +BITS TMPL_BITS + call TMPL_NM(TestA20_FlushAll) + call TMPL_NM(TestA20_Enabled) + call TMPL_NM(Bs2ExitMode) +BITS 16 + call TestSubErrorCount_r86 + cmp ax, 0 + jne .done + + ; + ; Do tests with A20 disabled. + ; + call Bs2DisableA20_r86 + call TMPL_NM(Bs2EnterMode_rm) +BITS TMPL_BITS + call TMPL_NM(TestA20_FlushAll) + call TMPL_NM(TestA20_Disabled) + call TMPL_NM(Bs2ExitMode) +BITS 16 + call TestSubErrorCount_r86 + cmp ax, 0 + jne .done + +%ifndef TMPL_CMN_V86 + ; + ; Change A20 state without leaving and entering the CPU mode. + ; + call Bs2EnableA20_r86 + call TMPL_NM(Bs2EnterMode_rm) +BITS TMPL_BITS + call TMPL_NM(TestA20_Enabled) + + call TMPL_NM_CMN(Bs2DisableA20) + call TMPL_NM(TestA20_FlushAll) + call TMPL_NM(TestA20_Disabled) + + call TMPL_NM_CMN(Bs2EnableA20) + call TMPL_NM(TestA20_FlushAll) + call TMPL_NM(TestA20_Enabled) + + call TMPL_NM_CMN(Bs2DisableA20) + call TMPL_NM(TestA20_FlushAll) + call TMPL_NM(TestA20_Disabled) + + call TMPL_NM_CMN(Bs2EnableA20) + call TMPL_NM(TestA20_FlushAll) + call TMPL_NM(TestA20_Enabled) + + call TMPL_NM(Bs2ExitMode) +BITS 16 +%endif ; !TMPL_CMN_V86 + +.done: + call Bs2DisableA20_r86 +.done1: + call TestSubDone_r86 + + pop eax + ret + +.skip_not_supported: + mov eax, .s_szSkipNotSupported + call TestSkipped_r86 + jmp .done1 + +.s_szTestName: + db TMPL_MODE_STR, 0 +.s_szSkipNotSupported: + db TMPL_MODE_STR, ' is not supported by the CPU', 10, 13, 0 +ENDPROC TMPL_NM(TestA20_rm) +TMPL_BEGINCODE +BITS TMPL_BITS + + +%include "bootsector2-template-footer.mac" + diff --git a/src/VBox/ValidationKit/bootsectors/bootsector2-cpu-a20-1.asm b/src/VBox/ValidationKit/bootsectors/bootsector2-cpu-a20-1.asm new file mode 100644 index 00000000..aa1dcbf6 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bootsector2-cpu-a20-1.asm @@ -0,0 +1,376 @@ +; $Id: bootsector2-cpu-a20-1.asm $ +;; @file +; Bootsector that checks the A20 emulation. +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + + +%include "iprt/asmdefs.mac" +%include "iprt/x86.mac" +%include "VBox/VMMDevTesting.mac" + +; +; Include and execute the init code. +; +%define BS2_WITH_TRAPS +%define BS2_INIT_RM +%define BS2_INC_PE16 +%define BS2_INC_PE32 +%define BS2_INC_PP32 +%define BS2_INC_PAE32 +%define BS2_INC_LM64 +%include "bootsector2-common-init-code.mac" + + +; +; The benchmark driver +; +BEGINPROC main + ; + ; Test prologue. + ; + mov ax, .s_szTstName + call TestInit_r86 + + ; + ; The actual tests. + ; + call TestA20_1 ; must come first + call TestA20_rm_rm + ;call TestA20_rm_pe16 + call TestA20_rm_pe32 + call TestA20_rm_pp32 + ;call TestA20_rm_pp16 + call TestA20_rm_pae32 + call TestA20_rm_lm64 + + ; + ; We're done. + ; + call TestTerm_r86 + call Bs2Panic + +.s_szTstName: + db 'tstA20-1', 0 +.s_szInitialA20Status: + db 'Initial A20 state', 0 +ENDPROC main + + +; +; Do some initial tests. +; +BEGINPROC TestA20_1 + push eax + push edx + push ecx + push ebx + push edi + + ; + ; Check that the A20 gate is disabled when we come from the BIOS. + ; + mov ax, .s_szInitialA20Status + call TestSub_r86 + + call IsA20GateEnabled_rm + mov di, ax ; save A20 state in AX for bios test. + cmp al, 0 + je .initial_state_done + mov ax, .s_szBadInitialA20Status + call TestFailed_r86 + jmp .initial_state_done +.s_szInitialA20Status: + db 'Initial A20 state', 0 +.s_szBadInitialA20Status: + db 'Initial A20 state is enabled, expected disabled', 10, 13, 0 +.initial_state_done: + call TestSubDone_r86 + + ; + ; Disable it via the BIOS interface and check. + ; + mov ax, .s_szBios + call TestSub_r86 + + ; query support + mov ax, 2403h + int 15h + jnc .bios_2403_ok + movzx edx, ax + mov ax, .s_szBios2403Error + mov cl, VMMDEV_TESTING_UNIT_NONE + call TestValueU32_r86 + jmp .bios_2403_done +.bios_2403_ok: + movzx edx, al + mov ax, .s_szBios2403Mask + mov cl, VMMDEV_TESTING_UNIT_NONE + call TestValueU32_r86 +.bios_2403_done: + + ; Check what the bios thinks the state is. + call BiosIsA20GateEnabled_rm + cmp ax, di + je .bios_2402_done + push di + push ax + push word ds + push word .s_szBios2402Error + call TestFailedF_r86 + add sp, 8 +.bios_2402_done: + + ; Loop to make sure we get all transitions and ends up with A20 disabled. + mov cx, 10h +.bios_loop: + ; enable it + mov ax, 2401h + push cx ; paranoia that seems necessary for at least one AMI bios. + int 15h + pop cx + jnc .bios_continue1 + mov ax, .s_szBiosFailed2401 + jmp .bios_failed +.bios_continue1: + + call IsA20GateEnabled_rm + cmp al, 1 + je .bios_continue2 + mov ax, .s_szBiosEnableFailed + jmp .bios_failed +.bios_continue2: + + ; disable + mov ax, 2400h + push cx ; paranoia that seems necessary for at least one AMI bios. + int 15h + pop cx + jnc .bios_continue3 + mov ax, .s_szBiosFailed2400 + jmp .bios_failed +.bios_continue3: + call IsA20GateEnabled_rm + cmp al, 0 + je .bios_continue4 + mov ax, .s_szBiosDisableFailed + jmp .bios_failed +.bios_continue4: + + loop .bios_loop + jmp .bios_done +.s_szBios: + db 'INT 15h AH=24 A20 Gate interface', 0 +.s_szBios2403Mask: + db 'AX=2403 return (AL)', 0 +.s_szBios2403Error: + db 'AX=2403 error (AX)', 10, 13, 0 +.s_szBios2402Error: + db '2402h -> AX=%RX16 expected %RX16', 10, 13, 0 +.s_szBiosFailed2400: + db '2400h interface failed', 10, 13, 0 +.s_szBiosFailed2401: + db '2401h interface failed', 10, 13, 0 +.s_szBiosDisableFailed: + db 'BIOS failed to disable A20 (or bad CPU)', 10, 13, 0 +.s_szBiosEnableFailed: + db 'BIOS failed to enable A20', 10, 13, 0 +.bios_failed: + call TestFailed_r86 +.bios_done: + call TestSubDone_r86 + call Bs2DisableA20ViaPortA_r86 + call Bs2DisableA20ViaKbd_r86 + + ; + ; Test the fast A20 gate interface. + ; + mov ax, .s_szFastA20 + call TestSub_r86 + + mov cx, 10h +.fast_loop: + call Bs2EnableA20ViaPortA_r86 + call IsA20GateEnabled_rm + cmp al, 1 + mov ax, .s_szFastEnableFailed + jne .fast_failed + + call Bs2DisableA20ViaPortA_r86 + call IsA20GateEnabled_rm + cmp al, 0 + mov ax, .s_szFastDisableFailed + jne .fast_failed + loop .fast_loop + + jmp .fast_done +.s_szFastA20: + db 'Fast A20 Gate Interface', 0 +.s_szFastDisableFailed: + db 'Fast A20 gate disabling failed', 10, 13, 0 +.s_szFastEnableFailed: + db 'Fast A20 gate enabling failed', 10, 13, 0 +.fast_failed: + call TestFailed_r86 +.fast_done: + call TestSubDone_r86 + call Bs2DisableA20ViaPortA_r86 + call Bs2DisableA20ViaKbd_r86 + + ; + ; Test the keyboard interface. + ; + mov ax, .s_szKeyboardA20 + call TestSub_r86 + + mov cx, 10h +.kbd_loop: + call Bs2EnableA20ViaKbd_r86 + call IsA20GateEnabled_rm + cmp al, 1 + mov ax, .s_szKbdEnableFailed + jne .kbd_failed + + call Bs2DisableA20ViaKbd_r86 + call IsA20GateEnabled_rm + cmp al, 0 + mov ax, .s_szKbdDisableFailed + jne .kbd_failed + loop .kbd_loop + + jmp .kbd_done +.s_szKeyboardA20: + db 'Keyboard A20 Gate Interface', 0 +.s_szKbdDisableFailed: + db 'Disabling the A20 gate via the keyboard controller failed', 10, 13, 0 +.s_szKbdEnableFailed: + db 'Enabling the A20 gate via the keyboard controller failed', 10, 13, 0 +.kbd_failed: + call TestFailed_r86 +.kbd_done: + call TestSubDone_r86 + call Bs2DisableA20ViaPortA_r86 + call Bs2DisableA20ViaKbd_r86 + + pop edi + pop ebx + pop ecx + pop edx + pop eax + ret +ENDPROC TestA20_1 + + +;; +; Checks if the A20 gate is enabled. +; +; This is do by temporarily changing a word at address 0000000h and see if this +; is reflected at address 0100000h (1 MB). The word written is +; ~*(word *)0x100000h to make sure it won't accidentally match. +; +; @returns ax 1 if enabled, 0 if disabled. +; +BEGINPROC IsA20GateEnabled_rm + push ds + push es + push dx + pushf + cli + +.once_again: + xor ax, ax + mov ds, ax + dec ax + mov es, ax + + mov ax, [es:0010h] ; 0ffff:0010 => 0100000h (1 MB) + mov dx, [ds:0000h] ; 00000:0000 => 0000000h - save it + not ax + mov [ds:0000h], ax ; 0000000h - write ~[0100000h] + cmp [es:0010h], ax ; 0100000h - same as 0000000h if A20 is disabled. + mov [ds:0000h], dx ; 0000000h - restore original value + setne al + movzx ax, al + + popf + pop dx + pop es + pop ds + ret +ENDPROC IsA20GateEnabled_rm + +;; +; Checks if the BIOS thinks the A20 gate is enabled. +; +; @returns ax 1 if enabled, 0 if disabled. +; +BEGINPROC BiosIsA20GateEnabled_rm + push ecx + push eax + + mov ax, 2402h + int 15h + jnc .ok + mov al, 080h +.ok: + mov cx, ax + pop eax + mov ax, cx + pop ecx + ret +ENDPROC BiosIsA20GateEnabled_rm + +; +; Instantiate the template code. +; +%include "bootsector2-template-footer.mac" ; reset the initial environemnt. + +%define TMPL_RM +%include "bootsector2-cpu-a20-1-template.mac" +;%define TMPL_CMN_V86 +;%include "bootsector2-cpu-a20-1-template.mac" +%define TMPL_PE16 +%include "bootsector2-cpu-a20-1-template.mac" +%define TMPL_PE32 +%include "bootsector2-cpu-a20-1-template.mac" +;%define TMPL_PP16 +;%include "bootsector2-cpu-a20-1-template.mac" +%define TMPL_PP32 +%include "bootsector2-cpu-a20-1-template.mac" +;%define TMPL_PAE16 +;%include "bootsector2-cpu-a20-1-template.mac" +%define TMPL_PAE32 +%include "bootsector2-cpu-a20-1-template.mac" +;%define TMPL_LM16 +;%include "bootsector2-cpu-a20-1-template.mac" +;%define TMPL_LM32 +;%include "bootsector2-cpu-a20-1-template.mac" +%define TMPL_LM64 +%include "bootsector2-cpu-a20-1-template.mac" + + +; +; End sections and image. +; +%include "bootsector2-common-end.mac" + diff --git a/src/VBox/ValidationKit/bootsectors/bootsector2-cpu-ac-loop.asm b/src/VBox/ValidationKit/bootsectors/bootsector2-cpu-ac-loop.asm new file mode 100644 index 00000000..268d2205 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bootsector2-cpu-ac-loop.asm @@ -0,0 +1,115 @@ +; $Id: bootsector2-cpu-ac-loop.asm $ +;; @file +; Bootsector test for debug exceptions. +; +; Recommended (but not necessary): +; VBoxManage setextradata bs-cpu-xcpt-2 VBoxInternal/Devices/VMMDev/0/Config/TestingEnabled 1 +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + + +;******************************************************************************* +;* Header Files * +;******************************************************************************* +%include "iprt/asmdefs.mac" +%include "iprt/x86.mac" +%include "VBox/VMMDevTesting.mac" + + +; +; Include and execute the init code. +; + %define BS2_INIT_PE32 + %define BS2_WITH_TRAPS + %define BS2_WITH_TRAPRECS + %define BS2_INC_PE32 + %define BS2_INC_RM ; for SetCpuModeGlobals_rm + %include "bootsector2-common-init-code.mac" + + +; +; The main() function. +; +BEGINPROC main + BITS 32 + ; + ; Test prologue. + ; + mov ax, .s_szTstName + call TestInit_p32 + call Bs2EnableA20_p32 + cli ; raw-mode hack + + ; + ; Execute the tests + ; + sub esp, 20h + + ; Get the address of the #AC IDT entry. + sidt [esp] + mov eax, [esp + 2] + add eax, 8 * X86_XCPT_AC + + ; Make it execute in ring-3. + mov word [eax + 2], BS2_SEL_R3_CS32 ; u16Sel + or byte [eax + 5], 3 << 5 ; u2Dpl = 3 + + ; Enable AC. + mov eax, cr0 + or eax, X86_CR0_AM + mov cr0, eax + + ; Switch to ring-3 + call Bs2ToRing3_p32 + + ; Enable AC. + pushfd + or dword [esp], X86_EFL_AC + popfd + + ;; Test it. - won't work as the handle touches CR2, which traps in ring-3. + ;BS2_TRAP_INSTR X86_XCPT_AC, 0, mov dword [esp + 3], 0 + + ; Misalign the stack and use it. + or esp, 3 + push esp ; this will loop forever on real intel hardware. + and esp, ~3h + + add esp, 20h + + ; + ; We're done. + ; + call TestTerm_p32 + ret + +.s_szTstName: + db 'tstCpuAcLoop', 0 +ENDPROC main + + +; +; End sections and image. +; +%include "bootsector2-common-end.mac" + diff --git a/src/VBox/ValidationKit/bootsectors/bootsector2-cpu-basic-1-template.mac b/src/VBox/ValidationKit/bootsectors/bootsector2-cpu-basic-1-template.mac new file mode 100644 index 00000000..03177258 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bootsector2-cpu-basic-1-template.mac @@ -0,0 +1,74 @@ +; $Id: bootsector2-cpu-basic-1-template.mac $ +;; @file +; bootsector2 basic #1 - multi mode template. +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + + +%include "bootsector2-template-header.mac" + + +;; +; Do the tests for this mode. +; +; @uses nothing +; +BEGINCODELOW +BITS 16 +BEGINPROC TMPL_NM(TestBasic1_rm) + push eax + + mov ax, .s_szTestName + call TestSub_r86 + + call TMPL_NM(Bs2IsModeSupported_rm) + jz .skip_not_supported + + call TMPL_NM(Bs2EnterMode_rm) +BITS TMPL_BITS + ; Later, currently just getting thru the mode switch is good enough. + nop + call TMPL_NM(Bs2ExitMode) +BITS 16 +.done1: + call TestSubDone_r86 + + pop eax + ret + +.skip_not_supported: + mov eax, .s_szSkipNotSupported + call TestSkipped_r86 + jmp .done1 + +.s_szTestName: + db TMPL_MODE_STR, 0 +.s_szSkipNotSupported: + db TMPL_MODE_STR, ' is not supported by the CPU', 10, 13, 0 +ENDPROC TMPL_NM(TestBasic1_rm) +TMPL_BEGINCODE +BITS TMPL_BITS + + +%include "bootsector2-template-footer.mac" + diff --git a/src/VBox/ValidationKit/bootsectors/bootsector2-cpu-basic-1.asm b/src/VBox/ValidationKit/bootsectors/bootsector2-cpu-basic-1.asm new file mode 100644 index 00000000..d00d424b --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bootsector2-cpu-basic-1.asm @@ -0,0 +1,119 @@ +; $Id: bootsector2-cpu-basic-1.asm $ +;; @file +; Bootsector that checks the basic CPU operation. +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + + +%include "iprt/asmdefs.mac" +%include "iprt/x86.mac" +%include "VBox/VMMDevTesting.mac" + +; +; Include and execute the init code. +; +%define BS2_WITH_TRAPS +%define BS2_INIT_RM +%define BS2_INC_PE16 +%define BS2_INC_PE32 +%define BS2_INC_PP16 +%define BS2_INC_PP32 +%define BS2_INC_PAE32 +%define BS2_INC_PAE16 +%define BS2_INC_LM16 +%define BS2_INC_LM32 +%define BS2_INC_LM64 +%include "bootsector2-common-init-code.mac" + + +; +; The benchmark driver +; +BEGINPROC main + ; + ; Test prologue. + ; + mov ax, .s_szTstName + call TestInit_r86 + + ; + ; The actual tests. + ; + call TestBasic1_rm_rm + call TestBasic1_rm_pe16 + call TestBasic1_rm_pe32 + call TestBasic1_rm_pp32 + call TestBasic1_rm_pp16 + call TestBasic1_rm_pae16 + call TestBasic1_rm_pae32 + call TestBasic1_rm_lm64 + call TestBasic1_rm_lm32 + call TestBasic1_rm_lm16 + + ; + ; We're done. + ; + call TestTerm_r86 + call Bs2Panic + +.s_szTstName: + db 'tstBasic1-1', 0 +.s_szInitialBasic1Status: + db 'Initial Basic1 state', 0 +ENDPROC main + + +; +; Instantiate the template code. +; +%include "bootsector2-template-footer.mac" ; reset the initial environemnt. + +%define TMPL_RM +%include "bootsector2-cpu-basic-1-template.mac" +;%define TMPL_CMN_V86 +;%include "bootsector2-cpu-basic-1-template.mac" +%define TMPL_PE16 +%include "bootsector2-cpu-basic-1-template.mac" +%define TMPL_PE32 +%include "bootsector2-cpu-basic-1-template.mac" +%define TMPL_PP16 +%include "bootsector2-cpu-basic-1-template.mac" +%define TMPL_PP32 +%include "bootsector2-cpu-basic-1-template.mac" +%define TMPL_PAE16 +%include "bootsector2-cpu-basic-1-template.mac" +%define TMPL_PAE32 +%include "bootsector2-cpu-basic-1-template.mac" +%define TMPL_LM16 +%include "bootsector2-cpu-basic-1-template.mac" +%define TMPL_LM32 +%include "bootsector2-cpu-basic-1-template.mac" +%define TMPL_LM64 +%include "bootsector2-cpu-basic-1-template.mac" + + +; +; End sections and image. +; +%include "bootsector2-common-end.mac" + diff --git a/src/VBox/ValidationKit/bootsectors/bootsector2-cpu-db-loop.asm b/src/VBox/ValidationKit/bootsectors/bootsector2-cpu-db-loop.asm new file mode 100644 index 00000000..d4ad6d7a --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bootsector2-cpu-db-loop.asm @@ -0,0 +1,151 @@ +; $Id: bootsector2-cpu-db-loop.asm $ +;; @file +; Bootsector test for debug exception loop. +; +; Recommended (but not necessary): +; VBoxManage setextradata bs-cpu-db-loop VBoxInternal/Devices/VMMDev/0/Config/TestingEnabled 1 +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + + +;******************************************************************************* +;* Header Files * +;******************************************************************************* +%include "iprt/asmdefs.mac" +%include "iprt/x86.mac" +%include "VBox/VMMDevTesting.mac" + + +; +; Include and execute the init code. +; + %define BS2_INIT_PE32 + %define BS2_WITH_TRAPS + %define BS2_WITH_XCPT_DB_CLEARING_TF + %define BS2_INC_PE16 + %define BS2_INC_PE32 + %define BS2_INC_RM ; for SetCpuModeGlobals_rm + %include "bootsector2-common-init-code.mac" + + +; +; The main() function. +; +BEGINPROC main + BITS 32 + ; + ; Test prologue. + ; + mov ax, .s_szTstName + call TestInit_p32 + call Bs2EnableA20_p32 + cli ; raw-mode hack + sub esp, 20h + + call Bs2Thunk_p32_p16 + BITS 16 + + ; + ; We require a stack that can wrap around here. The default stack + ; doesn't allow us to do this, so we'll configure a custom one + ; where the page tables usually are. + ; + mov eax, [bs2Gdt + BS2_SEL_SS16] + mov ebx, [bs2Gdt + BS2_SEL_SS16 + 4] + + and eax, 0xffff + or eax, (BS2_PXX_BASE & 0xffff) << 16 + and ebx, 0x00ffff00 + or ebx, BS2_PXX_BASE & 0xff000000 + or ebx, (BS2_PXX_BASE & 0x00ff0000) >> 16 + mov [bs2GdtSpare0], eax + mov [bs2GdtSpare0 + 4], ebx + + + ; + ; Switch the stack. + ; + mov ax, ss + mov es, ax ; saved ss + mov edi, esp ; saved esp + + mov ax, BS2_SEL_SPARE0 + mov ss, ax + mov esp, 0xfff0 + + + ; + ; Arm the breakpoint. + ; + and dword [esp + 2], 0 + sidt [esp] + mov eax, [esp + 2] + add eax, 8 + mov dr0, eax + mov eax, X86_DR7_RA1_MASK | X86_DR7_GE \ + | X86_DR7_L0 | X86_DR7_G0 | X86_DR7_RW(0, X86_DR7_RW_RW) | X86_DR7_LEN(0, X86_DR7_LEN_DWORD) + mov dr7, eax + + ; + ; Trigger a single step exception. + ; + pushf + or word [xSP], X86_EFL_TF + popf + xchg eax, ebx + xchg edx, ecx ; should get a #DB here. + xchg eax, ebx + xchg edx, ecx + + ; + ; If we get thus far, we've failed. + ; + mov ax, es ; restore ss + mov ss, ax + mov esp, edi ; restore esp + + call Bs2Thunk_p16_p32 + BITS 32 + + mov eax, .s_szFailed + call TestFailed_p32 + + ; + ; We're done. + ; + call TestTerm_p32 + add esp, 20h + ret + +.s_szTstName: + db 'tstCpuDbLoop', 0 +.s_szFailed: + db 'no #DB loop detected',0 +ENDPROC main + + +; +; End sections and image. +; +%include "bootsector2-common-end.mac" + diff --git a/src/VBox/ValidationKit/bootsectors/bootsector2-cpu-hidden-regs-1-template.mac b/src/VBox/ValidationKit/bootsectors/bootsector2-cpu-hidden-regs-1-template.mac new file mode 100644 index 00000000..74f1897c --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bootsector2-cpu-hidden-regs-1-template.mac @@ -0,0 +1,342 @@ +; $Id: bootsector2-cpu-hidden-regs-1-template.mac $ +;; @file +; bootsector2 hidden CPU registers - multi mode template. +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + + +%include "bootsector2-template-header.mac" + +;; +; Helper for reporting several register values at in a sequence. +; +BEGINPROC TMPL_NM(TestValueRegSZZ) + push sAX + push sBX + + mov xBX, xAX +.next: + mov xAX, xBX + call TMPL_NM_CMN(TestValueReg) +.inner_next: + inc xBX + cmp byte [xBX], 0 + jne .inner_next + + inc xBX + cmp byte [xBX], 0 + je .done + jmp .next + +.done + pop sBX + pop sAX + ret +ENDPROC TMPL_NM(TestValueRegSZZ) + +;; +; Tests various LDTR values +; +BEGINPROC TMPL_NM(doLdtrTests) + push sAX + + ; The inital LDT. + mov sAX, .szLdtrInitial + call TMPL_NM(TestValueRegSZZ) + + ; Load our LDT + mov eax, BS2_SEL_LDT + lldt ax + mov sAX, .szLdtrValid + call TMPL_NM(TestValueRegSZZ) + + ; NULL LDTR. + xor eax, eax + lldt ax + mov sAX, .szLdtr0 + call TMPL_NM(TestValueRegSZZ) + + ; NULL(1) LDTR. + mov eax, 1 + lldt ax + mov sAX, .szLdtr1 + call TMPL_NM(TestValueRegSZZ) + + ; NULL(2) LDTR. + mov eax, 2 + lldt ax + mov sAX, .szLdtr2 + call TMPL_NM(TestValueRegSZZ) + + ; NULL(3) LDTR. + mov eax, 3 + lldt ax + mov sAX, .szLdtr3 + call TMPL_NM(TestValueRegSZZ) + +.done + pop sAX + ret + +.szLdtrInitial: + db 'LDTR(Initial) sel:ldtr', 0 + db 'LDTR(Initial) base:ldtr_base', 0 + db 'LDTR(Initial) limit:ldtr_lim', 0 + db 'LDTR(Initial) attr:ldtr_attr', 0 + db 0 +.szLdtrValid: + db 'LDTR(Valid) sel:ldtr', 0 + db 'LDTR(Valid) base:ldtr_base', 0 + db 'LDTR(Valid) limit:ldtr_lim', 0 + db 'LDTR(Valid) attr:ldtr_attr', 0 + db 0 +.szLdtr0: + db 'LDTR(0) sel:ldtr', 0 + db 'LDTR(0) base:ldtr_base', 0 + db 'LDTR(0) limit:ldtr_lim', 0 + db 'LDTR(0) attr:ldtr_attr', 0 + db 0 +.szLdtr1: + db 'LDTR(1) sel:ldtr', 0 + db 'LDTR(1) base:ldtr_base', 0 + db 'LDTR(1) limit:ldtr_lim', 0 + db 'LDTR(1) attr:ldtr_attr', 0 + db 0 +.szLdtr2: + db 'LDTR(2) sel:ldtr', 0 + db 'LDTR(2) base:ldtr_base', 0 + db 'LDTR(2) limit:ldtr_lim', 0 + db 'LDTR(2) attr:ldtr_attr', 0 + db 0 +.szLdtr3: + db 'LDTR(3) sel:ldtr', 0 + db 'LDTR(3) base:ldtr_base', 0 + db 'LDTR(3) limit:ldtr_lim', 0 + db 'LDTR(3) attr:ldtr_attr', 0 + db 0 +ENDPROC TMPL_NM(doLdtrTests) + + +;; +; Tests various LDTR values +; +BEGINPROC TMPL_NM(doTrTests) + push sAX + + ; Initial TR values. + mov sAX, .szTrInitial + call TMPL_NM(TestValueRegSZZ) + jmp .next1 +.szTrInitial: + db 'TR(Initial) sel:tr', 0 + db 'TR(Initial) base:tr_base', 0 + db 'TR(Initial) limit:tr_lim', 0 + db 'TR(Initial) attr:tr_attr', 0 + db 0 +.next1: + + ; Our TR. +%ifdef TMPL_CMN_LM + mov ax, BS2_SEL_TSS64 + ltr ax + mov sAX, .szTrTss64 + call TMPL_NM(TestValueRegSZZ) + jmp .next2 +.szTrTss64: + db 'TR(64) sel:tr', 0 + db 'TR(64) base:tr_base', 0 + db 'TR(64) limit:tr_lim', 0 + db 'TR(64) attr:tr_attr', 0 + db 0 + +%elifdef TMPL_PP32 + mov ax, BS2_SEL_TSS32 + ltr ax + mov sAX, .szTrTss32 + call TMPL_NM(TestValueRegSZZ) + jmp .next2 +.szTrTss32: + db 'TR(32) sel:tr', 0 + db 'TR(32) base:tr_base', 0 + db 'TR(32) limit:tr_lim', 0 + db 'TR(32) attr:tr_attr', 0 + db 0 +;%elifdef TMPL_PP16 +; mov ax, BS2_SEL_TSS16 +; mov sAX, .szTrTss16 +; call TMPL_NM(TestValueRegSZZ) +%endif +.next2: + + ; Note! Loading 0 into TR is not possible, unlike with LDTR. + +.done + pop sAX + ret +ENDPROC TMPL_NM(doTrTests) + + +;; +; Test loading of NULL selectors. +; +BEGINPROC TMPL_NM(doNullSelTests) + push sAX + push xBX + push gs + + mov ax, ss + mov gs, ax + mov sAX, .szGsSs + call TMPL_NM(TestValueRegSZZ) + + xor eax, eax + mov gs, ax + mov sAX, .szGs0 + call TMPL_NM(TestValueRegSZZ) + + mov ax, 3 + mov gs, ax + mov sAX, .szGs3 + call TMPL_NM(TestValueRegSZZ) + +%ifdef TMPL_64BIT + pushf + cli + mov bx, ss + mov ax, 0 + mov ss, ax + mov sAX, .szSs0 + call TMPL_NM(TestValueRegSZZ) + mov ss, bx + popf + + call TMPL_NM_CMN(Bs2ToRing2) + mov bx, ss + mov ax, 2 + mov ss, ax + mov sAX, .szSs1Ring2 + call TMPL_NM(TestValueRegSZZ) + mov ss, bx + + test byte [g_fCpuAmd], 1 + jz .not_amd + mov ax, 3 + mov ss, ax + mov sAX, .szSs3Ring2 + call TMPL_NM(TestValueRegSZZ) + +.not_amd: + call TMPL_NM_CMN(Bs2ToRing0) + +%endif + + pop gs + pop xBX + pop sAX + ret + +.szGsSs: + db 'GS(ss) sel:gs', 0 + db 'GS(ss) base:gs_base', 0 + db 'GS(ss) limit:gs_lim', 0 + db 'GS(ss) attr:gs_attr', 0 + db 0 +.szGs0: + db 'GS(0) sel:gs', 0 + db 'GS(0) base:gs_base', 0 + db 'GS(0) limit:gs_lim', 0 + db 'GS(0) attr:gs_attr', 0 + db 0 +.szGs3: + db 'GS(3) sel:gs', 0 + db 'GS(3) base:gs_base', 0 + db 'GS(3) limit:gs_lim', 0 + db 'GS(3) attr:gs_attr', 0 + db 0 +%ifdef TMPL_64BIT +.szSs0: + db 'SS(0) sel:ss', 0 + db 'SS(0) base:ss_base', 0 + db 'SS(0) limit:ss_lim', 0 + db 'SS(0) attr:ss_attr', 0 + db 0 +.szSs1Ring2 + db 'ring-2 SS(2) sel:ss', 0 + db 'ring-2 SS(2) base:ss_base', 0 + db 'ring-2 SS(2) limit:ss_lim', 0 + db 'ring-2 SS(2) attr:ss_attr', 0 + db 0 +.szSs3Ring2 + db 'ring-2 SS(3) sel:ss', 0 + db 'ring-2 SS(3) base:ss_base', 0 + db 'ring-2 SS(3) limit:ss_lim', 0 + db 'ring-2 SS(3) attr:ss_attr', 0 + db 0 +%endif +ENDPROC TMPL_NM(doNullSelTests) + + +BEGINPROC TMPL_NM(doTestsWorker) + push sAX + + mov xAX, .s_szSubTest + call TMPL_NM_CMN(TestSub) + call TMPL_NM(doLdtrTests) + call TMPL_NM(doTrTests) + call TMPL_NM(doNullSelTests) + +.done + pop sAX + ret + +.s_szSubTest: + db TMPL_MODE_STR, 0 +ENDPROC TMPL_NM(doTestsWorker) + + +;; +; Do the tests for this mode. +; +; @uses nothing +; +BEGINCODELOW +BITS 16 +BEGINPROC TMPL_NM(doTests_rm) + call TMPL_NM(Bs2IsModeSupported_rm) + jz .done + call TMPL_NM(Bs2EnterMode_rm) +BITS TMPL_BITS + + call TMPL_NM(doTestsWorker) + + call TMPL_NM(Bs2ExitMode) +BITS 16 +.done: + ret +ENDPROC TMPL_NM(doTests_rm) +TMPL_BEGINCODE +BITS TMPL_BITS + + +%include "bootsector2-template-footer.mac" + diff --git a/src/VBox/ValidationKit/bootsectors/bootsector2-cpu-hidden-regs-1.asm b/src/VBox/ValidationKit/bootsectors/bootsector2-cpu-hidden-regs-1.asm new file mode 100644 index 00000000..decb67d5 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bootsector2-cpu-hidden-regs-1.asm @@ -0,0 +1,275 @@ +; $Id: bootsector2-cpu-hidden-regs-1.asm $ +;; @file +; Bootsector that shows/tests the content of hidden CPU registers. +; +; Requires VMMDevTesting. Enable it via VBoxManage: +; VBoxManage setextradata bs-cpu-hidden-regs-1 VBoxInternal/Devices/VMMDev/0/Config/TestingEnabled 1 + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + + +%include "iprt/asmdefs.mac" +%include "iprt/x86.mac" +%include "VBox/VMMDevTesting.mac" + +; +; Include and execute the init code. +; + %define BS2_INIT_RM + %define BS2_INC_PE16 + %define BS2_INC_PE32 + %define BS2_INC_PP32 + %define BS2_INC_LM64 + %define BS2_WITH_TRAPS + %define BS2_WITH_MANUAL_LTR + %include "bootsector2-common-init-code.mac" + + +; +; The benchmark driver +; +BEGINPROC main + ; + ; Test prologue. + ; + mov ax, .s_szTstName + call TestInit_r86 + call Bs2EnableA20_r86 + call Bs2PanicIfVMMDevTestingIsMissing_r86 + + call reportPostBiosValues + call rmTests + call doTests_rm_pe32 + call doTests_rm_pp32 + call doTests_rm_lm64 + + ; + ; We're done. + ; + call TestTerm_r86 + call Bs2Panic + +.s_szTstName: + db 'tstCpuHidRegs', 0 +ENDPROC main + + +; +; Reports the values of interesting hidden registers as we start the test, i.e. +; right after the BIOS completed. +; +BEGINPROC reportPostBiosValues + push ax + push bx + mov ax, .s_szTstInitial + call TestSub_r86 + + mov ax, .s_szzStart + call TestValueRegSZZ_rm + +.done + pop bx + pop ax + ret + +.s_szzStart: + db 'BIOS - ldtr:ldtr', 0; + db 'BIOS - ldtr_base:ldtr_base', 0; + db 'BIOS - ldtr_limit:ldtr_lim', 0; + db 'BIOS - ldtr_attr:ldtr_attr', 0; + db 'BIOS - tr:tr', 0; + db 'BIOS - tr_base:tr_base', 0; + db 'BIOS - tr_limit:tr_lim', 0; + db 'BIOS - tr_attr:tr_attr', 0; + db 'BIOS - cs:cs', 0; + db 'BIOS - cs_base:cs_base', 0; + db 'BIOS - cs_limit:cs_lim', 0; + db 'BIOS - cs_attr:cs_attr', 0; + db 'BIOS - ss:ss', 0; + db 'BIOS - ss_base:ss_base', 0; + db 'BIOS - ss_limit:ss_lim', 0; + db 'BIOS - ss_attr:ss_attr', 0; + db 'BIOS - ds:ds', 0; + db 'BIOS - ds_base:ds_base', 0; + db 'BIOS - ds_limit:ds_lim', 0; + db 'BIOS - ds_attr:ds_attr', 0; + db 0,0,0,0 ; terminator +.s_szTstInitial: + db 'Post BIOS Values', 0 +ENDPROC reportPostBiosValues + + +; +; Reports the values of interesting hidden registers as we start the test, i.e. +; right after the BIOS completed. +; +BEGINPROC rmTests + push eax + push ebx + pushfd + cli + + mov ax, .s_szTstRM + call TestSub_r86 + + ; Check if CS changes when leaving protected mode. + mov ax, .s_szzRMPre + call TestValueRegSZZ_rm + mov byte [cs:.s_dwDummy], 1 + call Bs2EnterMode_rm_pe32 +BITS 32 + mov eax, .s_szzProt32 + call TestValueRegSZZ_pe32 + ; mov word [cs:.s_dwDummy], 2 - this shall GP(CS). + call Bs2ExitMode_pe32 +BITS 16 + mov ax, .s_szzRMPost + call TestValueRegSZZ_rm + mov dword [cs:.s_dwDummy], 3 + + ; + ; What happens if we make CS32 execute-only and return to real-mode. + ; + mov byte [cs:.s_dwDummy], 1 + call Bs2EnterMode_rm_pe16 + jmp BS2_SEL_CS16_EO:.loaded_cs16_eo +.loaded_cs16_eo: + mov eax, .s_szzProtEO + call TestValueRegSZZ_pe16 + ; mov ax, word [cs:.s_dwDummy] - this shall GP(CS). + ; mov word [cs:.s_dwDummy], 2 - this shall GP(CS). + + ; Leave real-mode ourselves. + mov eax, cr0 + and eax, ~X86_CR0_PE + mov cr0, eax + + ; All but cs gets reloaded. + xor ax, ax + mov ss, ax + mov ds, ax + mov es, ax + mov fs, ax + mov gs, ax + + ; Display CS and do a test. + mov ax, .s_szzRMEO + call TestValueRegSZZ_rm + + mov ax, [cs:.s_dwDummy] ; works on intel + mov dword [cs:.s_dwDummy], 3 ; ditto + + jmp far 0000:.load_rm_cs +.load_rm_cs: + ; Display CS to check that it remained unchanged. + mov ax, .s_szzRMEO2 + call TestValueRegSZZ_rm + + ; Cleanup everything properly. + call Bs2EnterMode_rm_pe32 +BITS 32 + call Bs2ExitMode_pe32 +BITS 16 + + popfd + pop ebx + pop eax + ret + +.s_dwDummy: + dd 0 +.s_szzRMPre: + db 'RM Pre - cs:cs', 0; + db 'RM Pre - cs_base:cs_base', 0; + db 'RM Pre - cs_limit:cs_lim', 0; + db 'RM Pre - cs_attr:cs_attr', 0; + db 0,0,0,0 ; terminator +.s_szzProt32: + db 'Prot32 - cs:cs', 0; + db 'Prot32 - cs_base:cs_base', 0; + db 'Prot32 - cs_limit:cs_lim', 0; + db 'Prot32 - cs_attr:cs_attr', 0; + db 0,0,0,0 ; terminator +.s_szzRMPost: + db 'RM Post - cs:cs', 0; + db 'RM Post - cs_base:cs_base', 0; + db 'RM Post - cs_limit:cs_lim', 0; + db 'RM Post - cs_attr:cs_attr', 0; + db 0,0,0,0 ; terminator +.s_szzProtEO: + db 'Prot 16 EO,L-1,NA - cs:cs', 0; + db 'Prot 16 EO,L-1,NA - cs_base:cs_base', 0; + db 'Prot 16 EO,L-1,NA - cs_limit:cs_lim', 0; + db 'Prot 16 EO,L-1,NA - cs_attr:cs_attr', 0; + db 0,0,0,0 ; terminator +.s_szzRMEO: + db 'RM Post EO,L-1,NA - cs:cs', 0; + db 'RM Post EO,L-1,NA - cs_base:cs_base', 0; + db 'RM Post EO,L-1,NA - cs_limit:cs_lim', 0; + db 'RM Post EO,L-1,NA - cs_attr:cs_attr', 0; + db 0,0,0,0 ; terminator +.s_szzRMEO2: + db 'RM CS(0) EO,L-1 - cs:cs', 0; + db 'RM CS(0) EO,L-1 - cs_base:cs_base', 0; + db 'RM CS(0) EO,L-1 - cs_limit:cs_lim', 0; + db 'RM CS(0) EO,L-1 - cs_attr:cs_attr', 0; + db 0,0,0,0 ; terminator +.s_szTstRM: + db 'Real Mode Test', 0 +ENDPROC rmTests + + + +; +; Instantiate the template code. +; +%include "bootsector2-template-footer.mac" ; reset the initial environemnt. + +%define TMPL_RM +%include "bootsector2-cpu-hidden-regs-1-template.mac" +;%define TMPL_CMN_V86 +;%include "bootsector2-cpu-hidden-regs-1-template.mac" +%define TMPL_PE16 +%include "bootsector2-cpu-hidden-regs-1-template.mac" +%define TMPL_PE32 +%include "bootsector2-cpu-hidden-regs-1-template.mac" +;%define TMPL_PP16 +;%include "bootsector2-cpu-hidden-regs-1-template.mac" +%define TMPL_PP32 +%include "bootsector2-cpu-hidden-regs-1-template.mac" +;%define TMPL_PAE16 +;%include "bootsector2-cpu-hidden-regs-1-template.mac" +;%define TMPL_PAE32 +;%include "bootsector2-cpu-hidden-regs-1-template.mac" +;%define TMPL_LM16 +;%include "bootsector2-cpu-hidden-regs-1-template.mac" +;%define TMPL_LM32 +;%include "bootsector2-cpu-hidden-regs-1-template.mac" +%define TMPL_LM64 +%include "bootsector2-cpu-hidden-regs-1-template.mac" + + +; +; End sections and image. +; +%include "bootsector2-common-end.mac" + diff --git a/src/VBox/ValidationKit/bootsectors/bootsector2-cpu-instr-1-template.mac b/src/VBox/ValidationKit/bootsectors/bootsector2-cpu-instr-1-template.mac new file mode 100644 index 00000000..7b0ea8c5 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bootsector2-cpu-instr-1-template.mac @@ -0,0 +1,314 @@ +; $Id: bootsector2-cpu-instr-1-template.mac $ +;; @file +; Bootsector test for misc instruction - multi mode template. +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + + +%include "bootsector2-template-header.mac" + + + +;; +; Memory fence instructions (SSE2). +; +; @uses No registers, but BS2_SEL_SPARE0 is trashed. +; +BEGINPROC TMPL_NM(TestMemFences) + push xBP + mov xBP, xSP + push sAX + push xBX + push xCX + push xDX + push xDI + push xSI + sub xSP, 80h ; iret stack frame space. + mov xSI, xSP ; Save the stack register. + + mov xAX, .s_szSubTestName + call TMPL_NM_CMN(TestSub) + + ; + ; SSE2 supported? + ; + mov eax, 1 + xor ecx, ecx + cpuid + test edx, X86_CPUID_FEATURE_EDX_SSE2 + jz .skip + + ; + ; Check that the standard instruction encodings work. + ; + mov xBX, [xSP + 10h] + mov [xSP], xAX + mfence + mov [xSP], xCX + mov xBX, [xSP + 08h] + sfence + mov [xSP], xDX + mov xBX, [xSP] + lfence + mov bx, [xSP + 04h] + + + ; + ; The instruction encodings in the intel manual may open the RM as well + ; as prefixes open to interpretation. AMD sets RM=0 in their docs. + ; + ; lfence = 0f,ea,e8 + ; mfence = 0f,ea,f0 + ; sfence = 0f,ea,f8 + ; (RM is the lower 3 bits of the last byte.) + +%assign MY_RM 0xe8 +%rep 18h + db 0fh, 0aeh, MY_RM + db X86_OP_PRF_CS, 0fh, 0aeh, MY_RM + db X86_OP_PRF_DS, 0fh, 0aeh, MY_RM + db X86_OP_PRF_ES, 0fh, 0aeh, MY_RM + db X86_OP_PRF_FS, 0fh, 0aeh, MY_RM + db X86_OP_PRF_GS, 0fh, 0aeh, MY_RM + db X86_OP_PRF_SS, 0fh, 0aeh, MY_RM + db X86_OP_PRF_SIZE_ADDR, 0fh, 0aeh, MY_RM + BS2_TRAP_INSTR X86_XCPT_UD, 0, db X86_OP_PRF_SIZE_OP, 0fh, 0aeh, MY_RM ; (used in group) + BS2_TRAP_INSTR X86_XCPT_UD, 0, db X86_OP_PRF_LOCK, 0fh, 0aeh, MY_RM ; (used in group) + BS2_TRAP_INSTR X86_XCPT_UD, 0, db X86_OP_PRF_REPNZ, 0fh, 0aeh, MY_RM ; (used in group) + BS2_TRAP_INSTR X86_XCPT_UD, 0, db X86_OP_PRF_REPZ, 0fh, 0aeh, MY_RM ; (used in group) +%ifdef TMPL_64BIT + %assign MY_REX 0x40 + %rep 10h + ; Rex prefixes doesn't change anything. + db MY_REX, 0fh, 0aeh, MY_RM + db X86_OP_PRF_CS, MY_REX, 0fh, 0aeh, MY_RM + db X86_OP_PRF_DS, MY_REX, 0fh, 0aeh, MY_RM + db X86_OP_PRF_ES, MY_REX, 0fh, 0aeh, MY_RM + db X86_OP_PRF_FS, MY_REX, 0fh, 0aeh, MY_RM + db X86_OP_PRF_GS, MY_REX, 0fh, 0aeh, MY_RM + db X86_OP_PRF_SS, MY_REX, 0fh, 0aeh, MY_RM + db X86_OP_PRF_SIZE_ADDR, MY_REX, 0fh, 0aeh, MY_RM + BS2_TRAP_INSTR X86_XCPT_UD, 0, db X86_OP_PRF_SIZE_OP, MY_REX, 0fh, 0aeh, MY_RM ; (used in group) + BS2_TRAP_INSTR X86_XCPT_UD, 0, db X86_OP_PRF_LOCK, MY_REX, 0fh, 0aeh, MY_RM ; (used in group) + BS2_TRAP_INSTR X86_XCPT_UD, 0, db X86_OP_PRF_REPNZ, MY_REX, 0fh, 0aeh, MY_RM ; (used in group) + BS2_TRAP_INSTR X86_XCPT_UD, 0, db X86_OP_PRF_REPZ, MY_REX, 0fh, 0aeh, MY_RM ; (used in group) + %assign MY_REX (MY_REX + 1) + %endrep +%endif + %assign MY_RM (MY_RM + 1) +%endrep + + ; + ; Done. + ; + call TMPL_NM_CMN(TestSubDone) +.done: + mov xSP, xSI + add xSP, 80h + pop xSI + pop xDI + pop xDX + pop xCX + pop xBX + pop sAX + leave + ret + +.skip: + mov xAX, .s_szSse2Missing + call TMPL_NM_CMN(TestSubDone) + jmp .done + +.s_szSubTestName: + db TMPL_MODE_STR, ', mfence et al.', 0 +.s_szSse2Missing: + db 'SSE2 is missing', 0 +ENDPROC TMPL_NM(TestMemFences) + + +;; +; Proving intel manual wrong about using REX.X for BSWAP R8-R15 on 64-bit. +; Checking the 'undefined' 16-bit bswap behavior. +; +; @uses No registers, but BS2_SEL_SPARE0 is trashed. +; +BEGINPROC TMPL_NM(TestBSwap) + push xBP + mov xBP, xSP + push sAX + push xBX + push xCX + push xDX + push xDI + push xSI + sub xSP, 80h ; iret stack frame space. + mov xSI, xSP ; Save the stack register. + + mov xAX, .s_szSubTestName + call TMPL_NM_CMN(TestSub) + + ; + ; Assert sanity. + ; + mov eax, 11223344h + bswap eax + TEST_ASSERT_SIMPLE eax, 44332211h, jz, "32-bit BSWAP EAX" + + ; + ; Buggy manual (325383-041US, December 2011). + ; +%ifdef TMPL_64BIT + push r8 + + mov r8d, 55667788h + mov eax, 55667788h + db X86_OP_REX_X + bswap eax ; does it access r8 or eax? + TEST_ASSERT_SIMPLE eax, 88776655h, jz, "REX.X BSWAP EAX - Wrong EAX." + TEST_ASSERT_SIMPLE r8, 55667788h, jz, "REX.X BSWAP EAX - Wrong R8." + + mov r8d, 55667788h + mov eax, 55667788h + db X86_OP_REX_R + bswap eax ; does it access r8 or eax? + TEST_ASSERT_SIMPLE eax, 88776655h, jz, "REX.R BSWAP EAX - Wrong EAX." + TEST_ASSERT_SIMPLE r8, 55667788h, jz, "REX.R BSWAP EAX - Wrong R8." + + mov r8d, 55667788h + mov eax, 55667788h + db X86_OP_REX_B + bswap eax ; does it access r8 or eax? + TEST_ASSERT_SIMPLE rax, 55667788h, jz, "REX.B BSWAP R8D - Wrong RAX." + TEST_ASSERT_SIMPLE r8d, 88776655h, jz, "REX.B BSWAP R8D - Wrong R8D." + + pop r8 +%endif + + ; + ; 'Undefined' 16-bit behavior. + ; + ; Zeroing of the lower 16-bits has been observed on: + ; - Intel(R) Core(TM) i7-3960X CPU @ 3.30GHz + ; +%ifndef TestBSwap16_defined + %define TestBSwap16_defined + %macro TestBSwap16 3, + mov %3, %2 ; save the primary register. + %ifdef TMPL_64BIT + mov %2, 0ffffffff98765432h ; Set the upper bit as well. + %else + mov %2, 98765432h + %endif + %ifndef TMPL_16BIT + db X86_OP_PRF_SIZE_OP + %endif + bswap %1 + xchg %2, %3 ; Restore and save the result (xSP). + TEST_ASSERT_SIMPLE %3, 98760000h, jz, "Unexpected 16-bit BSWAP error." + %endmacro +%endif + + TestBSwap16 eax, sAX, sSI + TestBSwap16 ebx, sBX, sSI + TestBSwap16 ecx, sCX, sSI + TestBSwap16 edx, sDX, sSI + TestBSwap16 esp, sSP, sSI + TestBSwap16 ebp, sBP, sSI + TestBSwap16 edi, sDI, sSI + TestBSwap16 esi, sSI, sDI +%ifdef TMPL_64BIT + TestBSwap16 r8d, r8, rax + TestBSwap16 r9d, r9, rax + TestBSwap16 r10d, r10, rax + TestBSwap16 r11d, r11, rax + TestBSwap16 r12d, r12, rax + TestBSwap16 r13d, r13, rax + TestBSwap16 r14d, r14, rax + TestBSwap16 r15d, r15, rax +%endif + + ; + ; Done. + ; + call TMPL_NM_CMN(TestSubDone) +.done: + mov xSP, xSI + add xSP, 80h + pop xSI + pop xDI + pop xDX + pop xCX + pop xBX + pop sAX + leave + ret + +.s_szSubTestName: + db TMPL_MODE_STR, ', bswap', 0 +ENDPROC TMPL_NM(TestBSwap) + + +;; +; Do the tests for this mode. +; +; @uses nothing +; +BEGINCODELOW +BITS 16 +BEGINPROC TMPL_NM(DoTestsForMode_rm) + push bp + mov bp, sp + push ax + + ; + ; Check if the mode and NX is supported, do the switch. + ; + call TMPL_NM(Bs2IsModeSupported_rm) + jz .done + call TMPL_NM(Bs2EnterMode_rm) +BITS TMPL_BITS + + ; + ; Test exception handler basics using INT3 and #BP. + ; + + call TMPL_NM(TestMemFences) + call TMPL_NM(TestBSwap) + + ; + ; Back to real mode. + ; + call TMPL_NM(Bs2ExitMode) +BITS 16 + call Bs2DisableNX_r86 + +.done: + pop ax + leave + ret +ENDPROC TMPL_NM(DoTestsForMode_rm) +TMPL_BEGINCODE +BITS TMPL_BITS + +%include "bootsector2-template-footer.mac" + diff --git a/src/VBox/ValidationKit/bootsectors/bootsector2-cpu-instr-1.asm b/src/VBox/ValidationKit/bootsectors/bootsector2-cpu-instr-1.asm new file mode 100644 index 00000000..e8147936 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bootsector2-cpu-instr-1.asm @@ -0,0 +1,110 @@ +; $Id: bootsector2-cpu-instr-1.asm $ +;; @file +; Bootsector test for misc instructions. +; +; Recommended (but not necessary): +; VBoxManage setextradata bs-cpu-instr-1 VBoxInternal/Devices/VMMDev/0/Config/TestingEnabled 1 +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + + +;******************************************************************************* +;* Header Files * +;******************************************************************************* +%include "iprt/asmdefs.mac" +%include "iprt/x86.mac" +%include "VBox/VMMDevTesting.mac" + +; Include and execute the init code. +%define BS2_INIT_RM +%define BS2_WITH_TRAPS +%define BS2_INC_RM +%define BS2_INC_PE32 +%define BS2_INC_PP32 +%define BS2_INC_PAE32 +%define BS2_INC_LM32 +%define BS2_INC_LM64 +%define BS2_WITH_TRAPRECS +%include "bootsector2-common-init-code.mac" + + +; +; The main() function. +; +BEGINPROC main + BITS 16 + ; + ; Test prologue. + ; + mov ax, .s_szTstName + call TestInit_r86 + call Bs2EnableA20_r86 + + + ; + ; Execute the tests + ; +%if 1 + call NAME(DoTestsForMode_rm_pe32) +%endif +%if 1 + call NAME(DoTestsForMode_rm_pp32) +%endif +%if 1 + call NAME(DoTestsForMode_rm_pae32) +%endif +%if 1 + call NAME(DoTestsForMode_rm_lm64) +%endif + + ; + ; We're done. + ; + call TestTerm_r86 + ret + +.s_szTstName: + db 'tstCpuInstr1', 0 +ENDPROC main + + +; +; Instantiate the template code. +; +%include "bootsector2-template-footer.mac" ; reset the initial environemnt. + +%define TMPL_PE32 +%include "bootsector2-cpu-instr-1-template.mac" +%define TMPL_PP32 +%include "bootsector2-cpu-instr-1-template.mac" +%define TMPL_PAE32 +%include "bootsector2-cpu-instr-1-template.mac" +%define TMPL_LM64 +%include "bootsector2-cpu-instr-1-template.mac" + + +; +; End sections and image. +; +%include "bootsector2-common-end.mac" + diff --git a/src/VBox/ValidationKit/bootsectors/bootsector2-cpu-pf-1-template.mac b/src/VBox/ValidationKit/bootsectors/bootsector2-cpu-pf-1-template.mac new file mode 100644 index 00000000..cf763abc --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bootsector2-cpu-pf-1-template.mac @@ -0,0 +1,1051 @@ +; $Id: bootsector2-cpu-pf-1-template.mac $ +;; @file +; Bootsector test for various types of #PFs - multi mode template. +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + + +%include "bootsector2-template-header.mac" + + +;******************************************************************************* +;* Defined Constants And Macros * +;******************************************************************************* +%undef BIG_PAGE_SIZE +%undef PXE_SIZE +%ifdef TMPL_CMN_PP + %define BIG_PAGE_SIZE _4M + %define PXE_SIZE 4 +%else + %define BIG_PAGE_SIZE _2M + %define PXE_SIZE 8 +%endif + + +;; +; Do the tests for this mode. +; +; @uses nothing +; +BEGINCODELOW +BITS 16 +BEGINPROC TMPL_NM(DoTestsForMode_rm) + push bp + mov bp, sp + push ax + + ; + ; Check if the mode and NX is supported, do the switch. + ; + call TMPL_NM(Bs2IsModeSupported_rm) + jz .done + mov ax, [bp - 2] + test al, al + jz .nx_disabled + call Bs2IsNXSupported_r86 + jz .done + call Bs2EnableNX_r86 +.nx_disabled: + call TMPL_NM(Bs2EnterMode_rm) +BITS TMPL_BITS + + ; + ; Do the tests. + ; + call TMPL_NM(TestNotPresent) + ;; @todo call TMPL_NM(TestReadOnly) + ;; @todo call TMPL_NM(TestSupervisor) + ;; @todo call TMPL_NM(TestReservedBits) + + ; + ; Back to real mode. + ; + call TMPL_NM(Bs2ExitMode) +BITS 16 + call Bs2DisableNX_r86 + +.done: + pop ax + leave + ret +ENDPROC TMPL_NM(DoTestsForMode_rm) +TMPL_BEGINCODE +BITS TMPL_BITS + + +;; +; Do the tests for this mode. +; +; @uses nothing +; +BEGINCODELOW +BITS 16 +BEGINPROC TMPL_NM(DoBenchmarksForMode_rm) + push bp + mov bp, sp + push ax + + ; + ; Check if the mode and NX is supported, do the switch. + ; + call TMPL_NM(Bs2IsModeSupported_rm) + jz .done + call TMPL_NM(Bs2EnterMode_rm) +BITS TMPL_BITS + + ; + ; Do the tests. + ; + call TMPL_NM(BenchmarkNotPresent) + + ; + ; Back to real mode. + ; + call TMPL_NM(Bs2ExitMode) +BITS 16 +.done: + pop ax + leave + ret +ENDPROC TMPL_NM(DoBenchmarksForMode_rm) +TMPL_BEGINCODE +BITS TMPL_BITS + + +;; +; Does the page-not-present tests. +; +; @param al Set if NXE=1, clear if NXE=0. +; +; @uses nothing +; +BEGINPROC TMPL_NM(TestNotPresent) + push xBP + mov xBP, xSP + push sAX + push xBX + push xCX + push xDX + push xDI + push xSI + + ; + ; Setup sCX for all the following tests. + ; + xor sCX, sCX + test al, al + jz .no_nxe + mov sCX, X86_TRAP_PF_ID +.no_nxe: + + ; + ; First test, big page not present. + ; + mov xAX, .s_szBigPageNotPresent + test sCX, sCX + jz .test1_nxe + mov xAX, .s_szBigPageNotPresentNX +.test1_nxe: + call TMPL_NM_CMN(TestSub) + call TMPL_NM(TestFillTestAreaWithRet) + + mov sAX, TST_SCRATCH_PD_BASE + call TMPL_NM(TestGetPdeAddr) + and byte [sAX], ~X86_PTE_P + mov sAX, cr3 + mov cr3, sAX + + mov sAX, TST_SCRATCH_PD_BASE + mov sDX, 0 ; err code + call TMPL_NM(TestHammerPage) + jz .test1_cleanup + + mov sAX, TST_SCRATCH_PD_BASE + (BIG_PAGE_SIZE / 2 - _4K) + call TMPL_NM(TestHammerPage) + jz .test1_cleanup + + mov sAX, TST_SCRATCH_PD_BASE + (BIG_PAGE_SIZE - _4K) + call TMPL_NM(TestHammerPage) + jz .test1_cleanup + +.test1_cleanup: + mov sAX, TST_SCRATCH_PD_BASE + call TMPL_NM(TestGetPdeAddr) + or byte [sAX], X86_PTE_P + mov sAX, cr3 + mov cr3, sAX + + ; + ; The second test, normal page not present. + ; + mov xAX, .s_szPageNotPresent + test sCX, sCX + jz .test2_nxe + mov xAX, .s_szPageNotPresentNX +.test2_nxe: + call TMPL_NM_CMN(TestSub) + + mov sAX, TST_SCRATCH_PD_BASE + call TMPL_NM(TstPutPageTableAt) + + ; Make the first and last page not-present. + and byte [BS2_USER_PX_0_ADDR], ~X86_PTE_P + and byte [BS2_USER_PX_0_ADDR + 01000h - PXE_SIZE], ~X86_PTE_P + mov sAX, cr3 + mov cr3, sAX + + ; Do the tests. + mov sAX, TST_SCRATCH_PD_BASE + mov sDX, 0 ; err code + call TMPL_NM(TestHammerPage) + jz .test2_cleanup + + mov sAX, TST_SCRATCH_PD_BASE + (BIG_PAGE_SIZE - _4K) + call TMPL_NM(TestHammerPage) + jz .test2_cleanup + +.test2_cleanup: + mov sAX, TST_SCRATCH_PD_BASE + call TMPL_NM(TstRestoreBigPageAt) + + +%if PXE_SIZE == 8 ; PAE or LM + ; + ; The third test, mark a page directory pointer entry not present. + ; + mov xAX, .s_szPdpeNotPresent + test sCX, sCX + jz .test3_nxe + mov xAX, .s_szPdpeNotPresentNX +.test3_nxe: + call TMPL_NM_CMN(TestSub) + call TMPL_NM(TestFillTestAreaWithRet) + + mov sAX, TST_SCRATCH_PDPT_BASE + call TMPL_NM(TestGetPdpeAddr) + and byte [sAX], ~X86_PTE_P + mov sAX, cr3 + mov cr3, sAX + + mov sAX, TST_SCRATCH_PDPT_BASE + mov sDX, 0 ; err code + call TMPL_NM(TestHammerPage) + jz .test3_cleanup + + mov sAX, TST_SCRATCH_PDPT_BASE + (BIG_PAGE_SIZE / 2 - _4K) + call TMPL_NM(TestHammerPage) + jz .test3_cleanup + + mov sAX, TST_SCRATCH_PDPT_BASE + (BIG_PAGE_SIZE - _4K) + call TMPL_NM(TestHammerPage) + jz .test3_cleanup + +.test3_cleanup: + mov sAX, TST_SCRATCH_PDPT_BASE + call TMPL_NM(TestGetPdpeAddr) + or byte [sAX], X86_PTE_P + mov sAX, cr3 + mov cr3, sAX +%endif ; PAE || LM + + +%ifdef TMPL_LM64 + ; + ; The fourth test, mark a page map level 4 entry not present. + ; + mov xAX, .s_szPml4eNotPresent + test sCX, sCX + jz .test4_nxe + mov xAX, .s_szPml4eNotPresentNX +.test4_nxe: + call TMPL_NM_CMN(TestSub) + call TMPL_NM(TestFillTestAreaWithRet) + + mov sAX, TST_SCRATCH_PML4_BASE + call TMPL_NM(TestGetPml4eAddr) + and byte [sAX], ~X86_PTE_P + mov sAX, cr3 + mov cr3, sAX + + mov sAX, TST_SCRATCH_PML4_BASE + mov sDX, 0 ; err code + call TMPL_NM(TestHammerPage) + jz .test4_cleanup + + mov sAX, TST_SCRATCH_PML4_BASE + (BIG_PAGE_SIZE / 2 - _4K) + call TMPL_NM(TestHammerPage) + jz .test4_cleanup + + mov sAX, TST_SCRATCH_PML4_BASE + (BIG_PAGE_SIZE - _4K) + call TMPL_NM(TestHammerPage) + jz .test4_cleanup + +.test4_cleanup: + mov sAX, TST_SCRATCH_PML4_BASE + call TMPL_NM(TestGetPml4eAddr) + or byte [sAX], X86_PTE_P + mov sAX, cr3 + mov cr3, sAX +%endif + + ; + ; Done. + ; + call TMPL_NM_CMN(TestSubDone) + + pop xSI + pop xDI + pop xDX + pop xCX + pop xBX + pop sAX + leave + ret + +.s_szBigPageNotPresent: + db TMPL_MODE_STR, ', !NX, big page NP', 0 +.s_szBigPageNotPresentNX: + db TMPL_MODE_STR, ', NX, big page NP', 0 +.s_szPageNotPresent: + db TMPL_MODE_STR, ', !NX, page NP', 0 +.s_szPageNotPresentNX: + db TMPL_MODE_STR, ', NX, page NP', 0 +%if PXE_SIZE == 8 ; PAE or LM +.s_szPdpeNotPresent: + db TMPL_MODE_STR, ', !NX, PDPE NP', 0 +.s_szPdpeNotPresentNX: + db TMPL_MODE_STR, ', NX, PDPE NP', 0 +%endif +%ifdef TMPL_LM64 +.s_szPml4eNotPresent: + db TMPL_MODE_STR, ', !NX, PML4E NP', 0 +.s_szPml4eNotPresentNX: + db TMPL_MODE_STR, ', NX, PML4E NP', 0 +%endif +ENDPROC TMPL_NM(TestNotPresent) + + + +;; +; Does the page-not-present benchmark. +; +; @uses nothing +; +BEGINPROC TMPL_NM(BenchmarkNotPresent) + push xBP + mov xBP, xSP + push sAX + push xBX + push sCX + push sDX + push xDI + push xSI + sub xSP, 20h + + call TMPL_NM(TestFillTestAreaWithRet) + + ; + ; The First benchmark: Big page not present. + ; + + ; Mark the big test page not present. + mov sAX, TST_SCRATCH_PD_BASE + call TMPL_NM(TestGetPdeAddr) + and byte [sAX], ~X86_PTE_P + mov sAX, cr3 + mov cr3, sAX + + ; Benchmark. + mov sAX, TST_SCRATCH_PD_BASE + mov xDX, .s_szBigPageNotPresent + mov xCX, .s_szBigPageNotPresentFailed + call TMPL_NM(TstBenchmark32BitReads) + + ; Cleanup. + mov sAX, TST_SCRATCH_PD_BASE + call TMPL_NM(TestGetPdeAddr) + or byte [sAX], X86_PTE_P + mov sAX, cr3 + mov cr3, sAX + + ; + ; The second benchmark: Normal page not present. + ; + + ; Replace the big page with a page table and make the first and last + ; pages not-present. + mov sAX, TST_SCRATCH_PD_BASE + call TMPL_NM(TstPutPageTableAt) + + and byte [BS2_USER_PX_0_ADDR], ~X86_PTE_P + and byte [BS2_USER_PX_0_ADDR + 01000h - PXE_SIZE], ~X86_PTE_P + mov sAX, cr3 + mov cr3, sAX + + ; Benchmark. + mov sAX, TST_SCRATCH_PD_BASE + mov xDX, .s_szPageNotPresent + mov xCX, .s_szPageNotPresentFailed + call TMPL_NM(TstBenchmark32BitReads) + + ; Cleanup + mov sAX, TST_SCRATCH_PD_BASE + call TMPL_NM(TstRestoreBigPageAt) + + + ; + ; Done. + ; + add xSP, 20h + pop xSI + pop xDI + pop sDX + pop sCX + pop xBX + pop sAX + leave + ret + +.s_szBigPageNotPresent: + db TMPL_MODE_STR, ', read NP big page', 0 +.s_szBigPageNotPresentFailed: + db TMPL_MODE_STR, ', reading NP big page failed', 13, 10, 0 +.s_szPageNotPresent: + db TMPL_MODE_STR, ', read NP page', 0 +.s_szPageNotPresentFailed: + db TMPL_MODE_STR, ', reading NP page failed', 13, 10, 0 +ENDPROC TMPL_NM(BenchmarkNotPresent) + + +;; +; Benchmark 32-bit reads at a give location. +; +; Will report the result under the name given via xDX. Will report any test +; failure giving the string pointed to by xCX as explanation. +; +; @param sAX The location to do the reads. +; @param xDX The test value name. +; @param xCX The failure string +; @uses nothing +; +BEGINPROC TMPL_NM(TstBenchmark32BitReads) + push xBP + mov xBP, xSP +%define a_pu32Test [xBP - sCB] + push sAX +%define a_pszValue [xBP - sCB*2] + push sDX +%define a_pszFailure [xBP - sCB*3] + push sCX + push sSI + push sDI +%define u64NanoTS [xBP - sCB*5 - 8h] + sub xSP, 8h + + ; + ; Calibrate the test so it doesn't take forever. + ; + mov xAX, .calibrate_resume + mov dl, 0eh + call TMPL_NM_CMN(Bs2TrapPrepare) + mov ecx, TST_CALIBRATE_LOOP_COUNT + + lea xAX, u64NanoTS + call TMPL_NM_CMN(GetNanoTS) + +.calibrate_loop: + mov sAX, a_pu32Test + mov esi, [sAX] +.calibrate_resume: + test sAX, sAX + jnz .failure + dec ecx + jnz .calibrate_loop + + lea xAX, u64NanoTS + call TMPL_NM_CMN(GetElapsedNanoTS) + call TMPL_NM_CMN(Bs2TrapReset) + + ; Figure out how many iterations is required for the full benchmark. + mov ecx, TST_BENCHMARK_PERIOD_IN_SECS + mov edx, TST_CALIBRATE_LOOP_COUNT + mov xAX, xSP + call TMPL_NM_CMN(CalcBenchmarkIterations) + mov ecx, eax ; iteration count. + + ; + ; Do the full benchmark run. + ; + mov xAX, .bench_resume + mov dl, 0eh + call TMPL_NM_CMN(Bs2TrapPrepare) + mov edx, ecx ; save test count for ReportResult. + + lea xAX, u64NanoTS + call TMPL_NM_CMN(GetNanoTS) +.bench_loop: + mov xAX, a_pu32Test + mov esi, [eax] +.bench_resume: + test eax, eax + jnz .failure + dec ecx + jnz .bench_loop + + lea xAX, u64NanoTS + call TMPL_NM_CMN(GetElapsedNanoTS) + call TMPL_NM_CMN(Bs2TrapReset) + + mov xCX, a_pszValue + lea xAX, u64NanoTS + call TMPL_NM_CMN(ReportResult) + +.return: + pop sDI + pop sSI + pop sCX + pop sDX + pop sAX + leave + ret + +.failure: + call TMPL_NM_CMN(Bs2TrapReset) + mov xAX, a_pszFailure + call TMPL_NM_CMN(TestFailed) + jmp .return + +%undef a_pszFailure +%undef a_pu32Test +%undef a_pszValue +%undef a_pszFailure +%undef u64NanoTS +ENDPROC TMPL_NM(TstBenchmark32BitReads) + + +;; +; Fills the test area with return instructions. +; +; @uses nothing. +; +BEGINPROC TMPL_NM(TestFillTestAreaWithRet) + push xBP + mov xBP, xSP + push xDI + push xCX + push xAX + + mov xDI, TST_SCRATCH_PD_BASE + mov xCX, (_4M + _4M) / 4 + mov eax, 0c3c3c3c3h + rep stosd + + mov xDI, TST_SCRATCH_PDPT_BASE + mov xCX, (_4M + _4M) / 4 + mov eax, 0c3c3c3c3h + rep stosd + +%ifdef TMPL_LM64 + mov xDI, TST_SCRATCH_PML4_BASE + mov xCX, (_4M + _4M) / 8 + mov rax, 0c3c3c3c3c3c3c3c3h + rep stosq +%endif + + pop xAX + pop xCX + pop xDI + leave + ret +ENDPROC TMPL_NM(TestFillTestAreaWithRet) + + +;; +; Gets the page directory address. +; +; ASSUMES identity mapped page translation tables. +; +; @returns ds:xAX The page directory address. +; @param sAX The virtual address in question. +; @uses nothing +; +BEGINPROC TMPL_NM(TestGetPdeAddr) + push xBP + mov xBP, xSP + push sBX + push sCX + +%ifdef TMPL_CMN_PP + ; PDPE + shr sAX, X86_PD_SHIFT + and sAX, X86_PD_MASK + shl sAX, 2 + mov sBX, cr3 + and sBX, X86_CR3_PAGE_MASK + add sAX, sBX + +%else + %ifdef TMPL_CMN_LM + ; PML4E + mov sCX, sAX + shr sCX, X86_PML4_SHIFT + and sCX, X86_PML4_MASK + shl sCX, 3 + mov sBX, cr3 + and sBX, X86_CR3_AMD64_PAGE_MASK & 0ffffffffh + add sBX, sCX + mov sBX, [sBX] + and sBX, X86_PDPE_PG_MASK & 0ffffffffh + %else + mov sBX, cr3 + and sBX, X86_CR3_PAE_PAGE_MASK + %endif + + ; PDPE + mov sCX, sAX + shr sCX, X86_PDPT_SHIFT + %ifdef TMPL_CMN_LM + and sCX, X86_PDPT_MASK_AMD64 + %else + and sCX, X86_PDPT_MASK_PAE + %endif + shl sCX, 3 + add sBX, xCX + mov sBX, [sBX] + and sBX, X86_PDPE_PG_MASK & 0ffffffffh + + ; PDE + shr sAX, X86_PD_PAE_SHIFT + and sAX, X86_PD_PAE_MASK + shl sAX, 3 + add sAX, sBX +%endif + + pop sCX + pop sBX + leave + ret +ENDPROC TMPL_NM(TestGetPdeAddr) + + +%if PXE_SIZE == 8 ; PAE or LM +;; +; Gets the page directory pointer entry for an address. +; +; ASSUMES identity mapped page translation tables. +; +; @returns ds:xAX The pointer to the PDPE. +; @param sAX The virtual address in question. +; @uses nothing +; +BEGINPROC TMPL_NM(TestGetPdpeAddr) + push xBP + mov xBP, xSP + push sBX + push sCX + +%ifdef TMPL_CMN_PP + %error "misconfig" +%endif + +%ifdef TMPL_CMN_LM + ; PML4E + mov sCX, sAX + shr sCX, X86_PML4_SHIFT + and sCX, X86_PML4_MASK + shl sCX, 3 + mov sBX, cr3 + and sBX, X86_CR3_AMD64_PAGE_MASK & 0ffffffffh + add sBX, sCX + mov sBX, [sBX] + and sBX, X86_PDPE_PG_MASK & 0ffffffffh +%else + mov sBX, cr3 + and sBX, X86_CR3_PAE_PAGE_MASK +%endif + + ; PDPE + shr sAX, X86_PDPT_SHIFT +%ifdef TMPL_CMN_LM + and sAX, X86_PDPT_MASK_AMD64 +%else + and sAX, X86_PDPT_MASK_PAE +%endif + shl sAX, 3 + add sAX, sBX + + pop sCX + pop sBX + leave + ret +ENDPROC TMPL_NM(TestGetPdpeAddr) +%endif ; PAE or LM + + +%ifdef TMPL_CMN_LM +;; +; Gets the page map level 4 entry for an address. +; +; ASSUMES identity mapped page translation tables. +; +; @returns rax The pointer to the PML4E. +; @param rax The virtual address in question. +; @uses nothing +; +BEGINPROC TMPL_NM(TestGetPml4eAddr) + push xBP + mov xBP, xSP + push rbx + + ; PML4E + shr rax, X86_PML4_SHIFT + and rax, X86_PML4_MASK + shl rax, 3 + mov rbx, cr3 + and rbx, X86_CR3_AMD64_PAGE_MASK & 0ffffffffh + add rax, rbx + + pop rbx + leave + ret +ENDPROC TMPL_NM(TestGetPml4eAddr) +%endif ; TMPL_CMN_LM + + +;; +; Initialize page table #0 and hooks it up at the specified address. +; +; The page table will have identity mapped pages. The TLBs are flushed +; wholesale. The caller will have to reconstruct the PDE when finished. +; +; @param sAX The virtual address (big page -> page table). +; @uses nothing +; +BEGINPROC TMPL_NM(TstPutPageTableAt) + push xBP + mov xBP, xSP + push sAX + push sCX + push sDI + push sSI + + ; initialize a page table. + mov sDI, BS2_USER_PX_0_ADDR + mov sSI, sAX +.init_loop: +%if PXE_SIZE == 8 + mov [sDI + 4], dword 0 + mov [sDI], sSI +%else + mov [sDI], esi +%endif + or byte [sDI], X86_PTE_P | X86_PTE_RW + add sSI, _4K + add sDI, PXE_SIZE + test sDI, 0fffh + jnz .init_loop + + ; hook it up instead of the big page. + and sAX, ~(BIG_PAGE_SIZE - 1) + mov sDI, sAX + call TMPL_NM(TestGetPdeAddr) + mov dword [sAX], BS2_USER_PX_0_ADDR | X86_PDE_P | X86_PDE_RW | X86_PDE_RW +%if PXE_SIZE == 8 + mov dword [sAX + 4], 0 +%endif + mov sAX, cr3 + mov cr3, sAX + + ; Make sure it works. + mov eax, 0c3c3c3c3h + mov ecx, BIG_PAGE_SIZE / 4 + rep stosd + + pop sSI + pop sDI + pop sCX + pop sAX + leave + ret +ENDPROC TMPL_NM(TstPutPageTableAt) + + +;; +; Restores the big page for a virtual address, undoing harm done by a +; previous TstPutPageTableAt call. +; +; @param sAX The virtual address to restore to a big page. +; @uses nothing +; +BEGINPROC TMPL_NM(TstRestoreBigPageAt) + push xBP + mov xBP, xSP + push sAX + push sCX + push sDI + + ; Set it up, inheriting bits from the previous PDE. + and sAX, ~(BIG_PAGE_SIZE - 1) + mov sDI, sAX ; save it for later. + call TMPL_NM(TestGetPdeAddr) + mov sCX, [sAX - PXE_SIZE] + and sCX, X86_PDE4M_US | X86_PDE4M_RW | X86_PDE4M_G | X86_PDE4M_PAT | X86_PDE4M_AVL | X86_PDE4M_PCD | X86_PDE4M_PWT + or sCX, X86_PDE4M_P | X86_PDE4M_PS + or sCX, sDI +%if PXE_SIZE == 8 + mov dword [sAX + 4], 0 + mov [sAX], sCX +%else + mov [sAX], ecx +%endif + mov sAX, cr3 + mov cr3, sAX + + ; Make sure it works. + mov eax, 0c3c3c3c3h + mov ecx, BIG_PAGE_SIZE / 4 + rep stosd + + pop sDI + pop sCX + pop sAX + leave + ret +ENDPROC TMPL_NM(TstRestoreBigPageAt) + + + +;; +; Hammers a page. +; +; Accesses a page in a few different ways, expecting all of the accesses to +; cause some kind of page fault. The caller just makes sure the page causes +; a fault and points us to it. +; +; @returns al=1, ZF=0 on success. +; @returns al=0, ZF=1 on failure. +; @param sAX The page. +; @param sDX The base error code to expect. +; @param xCX X86_TRAP_PF_ID if NXE, otherwise 0. +; @uses al +; +BEGINPROC TMPL_NM(TestHammerPage) + push xBP + mov xBP, xSP + push sBX +%define a_uErrorExec sPRE [xBP - sCB*2] + push sCX +%define a_uErrorFixed sPRE [xBP - sCB*3] + push sDX + push sDI + push sSI +%define a_pPage sPRE [xBP - sCB*6] + push sAX + + ; + ; First reads of different sizes. + ; + mov sDI, a_pPage +.read_byte_loop: + mov dl, 0ffh + mov xAX, .read_byte_resume + call TMPL_NM_CMN(Bs2TrapPrepare) +.read_byte: + mov cl, byte [sDI] +.read_byte_resume: + mov eax, 0eh ; trap # + mov sDX, a_uErrorFixed ; err + mov sCX, .read_byte ; fault eip + mov sBX, sDI ; fault address. + call TMPL_NM_CMN(TestCheckTrap) + jz .failed + inc sDI + test sDI, 0fffh + jnz .read_byte_loop + + mov sDI, a_pPage +.read_word_loop: + mov dl, 0ffh + mov xAX, .read_word_resume + call TMPL_NM_CMN(Bs2TrapPrepare) +.read_word: + mov cx, word [sDI] +.read_word_resume: + mov eax, 0eh ; trap # + mov sDX, a_uErrorFixed ; err + mov sCX, .read_word ; fault eip + mov sBX, sDI ; fault address. + call TMPL_NM_CMN(TestCheckTrap) + jz .failed + inc sDI + test sDI, 0fffh + jnz .read_word_loop + + mov sDI, a_pPage +.read_dword_loop: + mov dl, 0ffh + mov xAX, .read_dword_resume + call TMPL_NM_CMN(Bs2TrapPrepare) +.read_dword: + mov ecx, dword [sDI] +.read_dword_resume: + mov eax, 0eh ; trap # + mov sDX, a_uErrorFixed ; err + mov sCX, .read_dword ; fault eip + mov sBX, sDI ; fault address. + call TMPL_NM_CMN(TestCheckTrap) + jz .failed + inc sDI + test sDI, 0fffh + jnz .read_dword_loop + + ; + ; Then writes of different sizes. + ; + mov sDI, a_pPage +.write_byte_loop: + mov dl, 0ffh + mov xAX, .write_byte_resume + call TMPL_NM_CMN(Bs2TrapPrepare) +.write_byte: + mov byte [sDI], 0c3h ; (ret instruction) +.write_byte_resume: + mov eax, 0eh ; trap # + mov sDX, a_uErrorFixed ; err + or sDX, X86_TRAP_PF_RW + mov sCX, .write_byte ; fault eip + mov sBX, sDI ; fault address. + call TMPL_NM_CMN(TestCheckTrap) + jz .failed + inc sDI + test sDI, 0fffh + jnz .write_byte_loop + + mov sDI, a_pPage +.write_word_loop: + mov dl, 0ffh + mov xAX, .write_word_resume + call TMPL_NM_CMN(Bs2TrapPrepare) +.write_word: + mov word [sDI], 0c3c3h ; (2 ret instructions) +.write_word_resume: + mov eax, 0eh ; trap # + mov sDX, a_uErrorFixed ; err + or sDX, X86_TRAP_PF_RW + mov sCX, .write_word ; fault eip + mov sBX, sDI ; fault address. + call TMPL_NM_CMN(TestCheckTrap) + jz .failed + inc sDI + test sDI, 0fffh + jnz .write_word_loop + + mov sDI, a_pPage +.write_dword_loop: + mov dl, 0ffh + mov xAX, .write_dword_resume + call TMPL_NM_CMN(Bs2TrapPrepare) +.write_dword: + mov dword [sDI], 0c3c3c3c3h ; (4 ret instructions) +.write_dword_resume: + mov eax, 0eh ; trap # + mov sDX, a_uErrorFixed ; err + or sDX, X86_TRAP_PF_RW + mov sCX, .write_dword ; fault eip + mov sBX, sDI ; fault address. + call TMPL_NM_CMN(TestCheckTrap) + jz .failed + inc sDI + test sDI, 0fffh + jnz .write_dword_loop + + ; + ; Execute access. + ; + mov sDI, a_pPage + mov xSI, xSP +.call_loop: + mov dl, 0ffh + mov xAX, .call_resume + call TMPL_NM_CMN(Bs2TrapPrepare) + call sDI +.call_resume: + mov xSP, xSI ; restore xSP since the call will change it before #PF'ing. + mov eax, 0eh ; trap # + mov sDX, a_uErrorFixed ; err + or sDX, a_uErrorExec + mov sCX, sDI ; fault eip + mov sBX, sDI ; fault address. + call TMPL_NM_CMN(TestCheckTrap) + jz .failed + inc sDI + test sDI, 0fffh + jnz .call_loop + + + mov sDI, a_pPage + mov xSI, xSP +.jmp_loop: + mov dl, 0ffh + mov xAX, .jmp_resume + call TMPL_NM_CMN(Bs2TrapPrepare) + push .jmp_resume ; push a return address in case of failure. + jmp sDI +.jmp_resume: + mov xSP, xSI ; restore xSP in case the jmp didn't trap. + mov eax, 0eh ; trap # + mov sDX, a_uErrorFixed ; err + or sDX, a_uErrorExec + mov sCX, sDI ; fault eip + mov sBX, sDI ; fault address. + call TMPL_NM_CMN(TestCheckTrap) + jz .failed + inc sDI + test sDI, 0fffh + jnz .jmp_loop + + ; successfull return. + pop sAX + xor al, al + inc al +.return: + pop sSI + pop sDI + pop sDX + pop sCX + pop sBX + leave + ret + +.failed: + pop sAX + xor al, al + jmp .return +%undef a_uErrorFixed +%undef a_uErrorExec +%undef a_pPage +ENDPROC TMPL_NM(TestHammerPage) + + +%include "bootsector2-template-footer.mac" + diff --git a/src/VBox/ValidationKit/bootsectors/bootsector2-cpu-pf-1.asm b/src/VBox/ValidationKit/bootsectors/bootsector2-cpu-pf-1.asm new file mode 100644 index 00000000..b71e1da8 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bootsector2-cpu-pf-1.asm @@ -0,0 +1,154 @@ +; $Id: bootsector2-cpu-pf-1.asm $ +;; @file +; Bootsector test for various types of #PFs. +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + + +;******************************************************************************* +;* Header Files * +;******************************************************************************* +%include "iprt/asmdefs.mac" +%include "iprt/x86.mac" +%include "VBox/VMMDevTesting.mac" + + +;******************************************************************************* +;* Defined Constants And Macros * +;******************************************************************************* +;; Base address at which we can start testing page tables and page directories. +%define TST_SCRATCH_PD_BASE BS2_MUCK_ABOUT_BASE +;; Base address at which we can start testing the page pointer table. +%define TST_SCRATCH_PDPT_BASE (1 << X86_PDPT_SHIFT) +;; Base address at which we can start testing the page map level 4. +%define TST_SCRATCH_PML4_BASE ((1 << X86_PML4_SHIFT) + TST_SCRATCH_PD_BASE) + +;; The number of loops done during calibration. +%define TST_CALIBRATE_LOOP_COUNT 10000 +;; The desired benchmark period (seconds). +%define TST_BENCHMARK_PERIOD_IN_SECS 2 + + + +; +; Include and execute the init code. +; + %define BS2_INIT_RM + %define BS2_WITH_TRAPS + %define BS2_INC_RM +; %define BS2_INC_PP16 + %define BS2_INC_PP32 +; %define BS2_INC_PAE16 + %define BS2_INC_PAE32 +; %define BS2_INC_LM16 +; %define BS2_INC_LM32 + %define BS2_INC_LM64 + %include "bootsector2-common-init-code.mac" + + +; +; The benchmark driver +; +BEGINPROC main + ; + ; Test prologue. + ; + mov ax, .s_szTstName + call TestInit_r86 + call Bs2EnableA20_r86 + + ; + ; Execute the tests + ; +%if 1 + %if 1 + xor eax, eax ; NXE=0 (N/A) + call NAME(DoTestsForMode_rm_pp32) + %endif + %if 1 + xor eax, eax ; NXE=0 + call NAME(DoTestsForMode_rm_pae32) + mov eax, 1 ; NXE=1 + call NAME(DoTestsForMode_rm_pae32) + %endif + %if 1 + xor eax, eax ; NXE=0 + call NAME(DoTestsForMode_rm_lm64) + mov eax, 1 ; NXE=1 + call NAME(DoTestsForMode_rm_lm64) + %endif +%endif + + ; + ; Execute benchmarks. + ; +%if 1 + mov ax, .s_szTstBenchmark + call NAME(TestSub_r86) + call NAME(DoBenchmarksForMode_rm_pp32) + call NAME(DoBenchmarksForMode_rm_pae32) + call NAME(DoBenchmarksForMode_rm_lm64) + call NAME(TestSubDone_r86) +%endif + + ; + ; We're done. + ; + call TestTerm_r86 + ret + +.s_szTstBenchmark: + db 'Benchmark', 0 +.s_szTstName: + db 'tstIOIntr', 0 +.s_szTstX: + db 'X', 0 +ENDPROC main + + +; +; Instantiate the template code. +; +%include "bootsector2-template-footer.mac" ; reset the initial environemnt. + +;%define TMPL_PP16 +;%include "bootsector2-cpu-pf-1-template.mac" +%define TMPL_PP32 +%include "bootsector2-cpu-pf-1-template.mac" +;%define TMPL_PAE16 +;%include "bootsector2-cpu-pf-1-template.mac" +%define TMPL_PAE32 +%include "bootsector2-cpu-pf-1-template.mac" +;%define TMPL_LM16 +;%include "bootsector2-cpu-pf-1-template.mac" +;%define TMPL_LM32 +;%include "bootsector2-cpu-pf-1-template.mac" +%define TMPL_LM64 +%include "bootsector2-cpu-pf-1-template.mac" + + +; +; End sections and image. +; +%include "bootsector2-common-end.mac" + diff --git a/src/VBox/ValidationKit/bootsectors/bootsector2-cpu-xcpt-1-template.mac b/src/VBox/ValidationKit/bootsectors/bootsector2-cpu-xcpt-1-template.mac new file mode 100644 index 00000000..2a664b7b --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bootsector2-cpu-xcpt-1-template.mac @@ -0,0 +1,1963 @@ +; $Id: bootsector2-cpu-xcpt-1-template.mac $ +;; @file +; Bootsector test for basic exceptions - multi mode template. +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + + +%include "bootsector2-template-header.mac" + + +;******************************************************************************* +;* Defined Constants And Macros * +;******************************************************************************* +;; +; Some 32/64 macros. +; +%if TMPL_BITS == 32 + %define bs2Idt_BP bs2Idt32bit_BP + %define MY_R0_CS BS2_SEL_CS32 + %define MY_R1_CS BS2_SEL_R1_CS32 + %define MY_R2_CS BS2_SEL_R2_CS32 + %define MY_R3_CS BS2_SEL_R3_CS32 + + %define MY_R0_DS BS2_SEL_DS32 + %define MY_R1_DS BS2_SEL_R1_DS32 + %define MY_R2_DS BS2_SEL_R2_DS32 + %define MY_R3_DS BS2_SEL_R3_DS32 + + %define MY_R0_SS BS2_SEL_SS32 + %define MY_R1_SS BS2_SEL_R1_SS32 + %define MY_R2_SS BS2_SEL_R2_SS32 + %define MY_R3_SS BS2_SEL_R3_SS32 + +%else + %define bs2Idt_BP bs2Idt64bit_BP + %define MY_R0_CS BS2_SEL_CS64 + %define MY_R1_CS BS2_SEL_R1_CS64 + %define MY_R2_CS BS2_SEL_R2_CS64 + %define MY_R3_CS BS2_SEL_R3_CS64 + + %define MY_R0_DS BS2_SEL_DS64 + %define MY_R1_DS BS2_SEL_R1_DS64 + %define MY_R2_DS BS2_SEL_R2_DS64 + %define MY_R3_DS BS2_SEL_R3_DS64 + + %define MY_R0_SS BS2_SEL_SS64 + %define MY_R1_SS BS2_SEL_R1_SS64 + %define MY_R2_SS BS2_SEL_R2_SS64 + %define MY_R3_SS BS2_SEL_R3_SS64 +%endif + +%ifdef TMPL_64BIT + %assign MY_IS_64BIT 1 +%else + %assign MY_IS_64BIT 0 +%endif + + +;******************************************************************************* +;* Global Variables * +;******************************************************************************* +%ifndef CPU_XCPT_1_GLOBALS + %define CPU_XCPT_1_GLOBALS + g_szWrongIfStateFmt: + db 'Wrong IF state (0x%RX32) on line 0x%RX32', 0 + g_szWrongHandlerCsFmt: + db 'Wrong handler CS=%RX16, expected %RX16 (line 0x%RX32)', 0 + g_szWrongCurCsFmt: + db 'Wrong CS=%RX16, expected %RX16 (line 0x%RX32)', 0 + g_szWrongCurSRegFmt_fs: + db 'Wrong FS=%RX16, expected %RX16 (line 0x%RX32)', 0 + g_szWrongCurSRegFmt_ss: + db 'Wrong SS=%RX16, expected %RX16 (line 0x%RX32)', 0 + + +;; +; Asserts a test. +; +; @param %1 First cmp operand. +; @param %2 First cmp operand. +; @param %3 Which kind of conditional jump to make +; @param %4 The message to print (format string, no arguments please). +; +%macro ASSERT_SIMPLE 4 + cmp %1, %2 + %3 %%.ok + push dword __LINE__ + %ifdef TMPL_16BIT + push ds + %endif + push %%.s_szMsg + call TMPL_NM_CMN(TestFailedF) + add xSP, sCB*2 + jmp %%.ok +%%.s_szMsg: db %4, " (0x%RX32)", 0 +%%.ok: +%endmacro + + + ;; + ; Asserts that the IF flag is set or clear when the trap handler was called. + ; + ; @param 1 jnz or jz. + ; + ; @uses rax, flags, and stack. + ; + %macro ASSERT_TRAP_EFLAGS_IF 1 + test word [g_u64LastTrapHandlerRFlags xWrtRIP], X86_EFL_IF + %1 %%.ok + %ifdef TMPL_LM64 + push __LINE__ + push qword [g_u64LastTrapHandlerRFlags xWrtRIP] + lea rax, [g_szWrongIfStateFmt wrt RIP] + push rax + call TMPL_NM_CMN(TestFailedF) + add xSP, 24 + %elifdef TMPL_16 + push dword __LINE__ + push dword [g_u64LastTrapHandlerRFlags] + push cs + push g_szWrongIfStateFmt + call TMPL_NM_CMN(TestFailedF) + add xSP, 12 + %else + push __LINE__ + push dword [g_u64LastTrapHandlerRFlags] + push g_szWrongIfStateFmt + call TMPL_NM_CMN(TestFailedF) + add xSP, 12 + %endif + %%.ok: + %endmacro + + + ;; + ; Asserts that a certain CS value when the trap handler was called. + ; + ; @param 1 The CS value. + ; + ; @uses rax, flags, and stack. + ; + %macro ASSERT_TRAP_CS_VALUE 1 + cmp word [g_u16LastTrapHandlerCS xWrtRIP], (%1) + je %%.ok + %ifdef TMPL_LM64 + push __LINE__ + push (%1) + movzx eax, word [g_u16LastTrapHandlerCS xWrtRIP] + push rax + lea rax, [g_szWrongHandlerCsFmt wrt RIP] + push rax + call TMPL_NM_CMN(TestFailedF) + add xSP, 32 + %elifdef TMPL_16 + push dword __LINE__ + push word (%1) + push word [g_u16LastTrapHandlerCS] + push cs + push g_szWrongHandlerCsFmt + call TMPL_NM_CMN(TestFailedF) + add xSP, 12 + %else + push __LINE__ + push (%1) + movzx eax, word [g_u16LastTrapHandlerCS] + push eax + push g_szWrongHandlerCsFmt + call TMPL_NM_CMN(TestFailedF) + add xSP, 16 + %endif + %%.ok: + %endmacro + + ;; + ; Asserts that a certain CS value right now, CS being loaded in BX. + ; + ; @param bx The CS value. + ; @param 1 The expected CS value. + ; + ; @uses rax, flags, and stack. + ; + %macro ASSERT_CUR_CS_VALUE_IN_BX 1 + cmp bx, (%1) + je %%.ok + %ifdef TMPL_LM64 + push __LINE__ + push (%1) + push rbx + lea rax, [g_szWrongCurCsFmt wrt RIP] + push rax + call TMPL_NM_CMN(TestFailedF) + add xSP, 32 + %elifdef TMPL_16 + push dword __LINE__ + push word (%1) + push bx + push g_szWrongCurCsFmt + call TMPL_NM_CMN(TestFailedF) + add xSP, 12 + %else + push __LINE__ + push (%1) + push ebx + push g_szWrongCurCsFmt + call TMPL_NM_CMN(TestFailedF) + add xSP, 16 + %endif + %%.ok: + %endmacro + + ;; + ; Asserts that the given segment register has a certain value right now. + ; + ; @param 1 The segment register + ; @param 2 The value. + ; + ; @uses rax, flags, and stack. + ; + %macro ASSERT_CUR_SREG_VALUE 2 + mov ax, %1 + cmp ax, (%2) + je %%.ok + %ifdef TMPL_LM64 + push __LINE__ + push (%2) + push rax + lea rax, [g_szWrongCurSRegFmt_ %+ %1 wrt RIP] + push rax + call TMPL_NM_CMN(TestFailedF) + add xSP, 32 + %elifdef TMPL_16 + push dword __LINE__ + push word (%2) + push ax + push g_szWrongCurSRegFmt_ %+ %1 + call TMPL_NM_CMN(TestFailedF) + add xSP, 12 + %else + push __LINE__ + push (%2) + push eax + push g_szWrongCurSRegFmt_ %+ %1 + call TMPL_NM_CMN(TestFailedF) + add xSP, 16 + %endif + %%.ok: + %endmacro + + +%endif + + +;; +; Checks different gate types. +; +BEGINPROC TMPL_NM(TestGateType) + push xBP + mov xBP, xSP + push sAX + push xBX + push xCX + push xDX + push xDI + push xSI + + mov xAX, .s_szSubTestName + call TMPL_NM_CMN(TestSub) + + + ; + ; Check that int3 works and save the IDTE before making changes. + ; + ; We'll be changing X86DESCGATE.u4Type, which starts at bit 0x28 (that + ; is byte 5) and is 4-bit wide, and X86DESCGATE.u1DescType, which is + ; at bit 2c. + ; + BS2_TRAP_INSTR X86_XCPT_BP, 0, int3 ; check that int3 works before we start messing around... + +%ifdef TMPL_LM64 + push qword [bs2Idt_BP xWrtRIP] + push qword [bs2Idt_BP + 8 xWrtRIP] +%else + push dword [bs2Idt_BP xWrtRIP] + push dword [bs2Idt_BP + 4 xWrtRIP] +%endif + mov xDI, xSP ; for catching stack errors + + ; + ; Check all kinds of none system selectors first (they should all GP(3+IDT)) + ; +%assign u4Type 0 +%rep 16 + and byte [bs2Idt_BP + 5 xWrtRIP], 0e0h + or byte [bs2Idt_BP + 5 xWrtRIP], RT_BIT(4) | u4Type + BS2_TRAP_INSTR X86_XCPT_GP, (3 << X86_TRAP_ERR_SEL_SHIFT) | X86_TRAP_ERR_IDT, int3 + %assign u4Type (u4Type + 1) +%endrep + + ; + ; Illegal system types. + ; +%ifdef TMPL_LM64 + %assign u4Type 0 + %rep 14 + and byte [bs2Idt_BP + 5 xWrtRIP], 0e0h + or byte [bs2Idt_BP + 5 xWrtRIP], u4Type + BS2_TRAP_INSTR X86_XCPT_GP, (3 << X86_TRAP_ERR_SEL_SHIFT) | X86_TRAP_ERR_IDT, int3 + %assign u4Type (u4Type + 1) + %endrep +%else + and byte [bs2Idt_BP + 5 xWrtRIP], 0e0h + or byte [bs2Idt_BP + 5 xWrtRIP], X86_SEL_TYPE_SYS_UNDEFINED + BS2_TRAP_INSTR X86_XCPT_GP, (3 << X86_TRAP_ERR_SEL_SHIFT) | X86_TRAP_ERR_IDT, int3 + + and byte [bs2Idt_BP + 5 xWrtRIP], 0e0h + or byte [bs2Idt_BP + 5 xWrtRIP], X86_SEL_TYPE_SYS_286_TSS_AVAIL + BS2_TRAP_INSTR X86_XCPT_GP, (3 << X86_TRAP_ERR_SEL_SHIFT) | X86_TRAP_ERR_IDT, int3 + + and byte [bs2Idt_BP + 5 xWrtRIP], 0e0h + or byte [bs2Idt_BP + 5 xWrtRIP], X86_SEL_TYPE_SYS_LDT + BS2_TRAP_INSTR X86_XCPT_GP, (3 << X86_TRAP_ERR_SEL_SHIFT) | X86_TRAP_ERR_IDT, int3 + + and byte [bs2Idt_BP + 5 xWrtRIP], 0e0h + or byte [bs2Idt_BP + 5 xWrtRIP], X86_SEL_TYPE_SYS_286_TSS_BUSY + BS2_TRAP_INSTR X86_XCPT_GP, (3 << X86_TRAP_ERR_SEL_SHIFT) | X86_TRAP_ERR_IDT, int3 + + and byte [bs2Idt_BP + 5 xWrtRIP], 0e0h + or byte [bs2Idt_BP + 5 xWrtRIP], X86_SEL_TYPE_SYS_286_CALL_GATE + BS2_TRAP_INSTR X86_XCPT_GP, (3 << X86_TRAP_ERR_SEL_SHIFT) | X86_TRAP_ERR_IDT, int3 + + and byte [bs2Idt_BP + 5 xWrtRIP], 0e0h + or byte [bs2Idt_BP + 5 xWrtRIP], X86_SEL_TYPE_SYS_UNDEFINED2 + BS2_TRAP_INSTR X86_XCPT_GP, (3 << X86_TRAP_ERR_SEL_SHIFT) | X86_TRAP_ERR_IDT, int3 + + and byte [bs2Idt_BP + 5 xWrtRIP], 0e0h + or byte [bs2Idt_BP + 5 xWrtRIP], X86_SEL_TYPE_SYS_386_TSS_AVAIL + BS2_TRAP_INSTR X86_XCPT_GP, (3 << X86_TRAP_ERR_SEL_SHIFT) | X86_TRAP_ERR_IDT, int3 + + and byte [bs2Idt_BP + 5 xWrtRIP], 0e0h + or byte [bs2Idt_BP + 5 xWrtRIP], X86_SEL_TYPE_SYS_UNDEFINED3 + BS2_TRAP_INSTR X86_XCPT_GP, (3 << X86_TRAP_ERR_SEL_SHIFT) | X86_TRAP_ERR_IDT, int3 + + and byte [bs2Idt_BP + 5 xWrtRIP], 0e0h + or byte [bs2Idt_BP + 5 xWrtRIP], X86_SEL_TYPE_SYS_386_TSS_BUSY + BS2_TRAP_INSTR X86_XCPT_GP, (3 << X86_TRAP_ERR_SEL_SHIFT) | X86_TRAP_ERR_IDT, int3 + + and byte [bs2Idt_BP + 5 xWrtRIP], 0e0h + or byte [bs2Idt_BP + 5 xWrtRIP], X86_SEL_TYPE_SYS_UNDEFINED4 + BS2_TRAP_INSTR X86_XCPT_GP, (3 << X86_TRAP_ERR_SEL_SHIFT) | X86_TRAP_ERR_IDT, int3 + + and byte [bs2Idt_BP + 5 xWrtRIP], 0e0h + or byte [bs2Idt_BP + 5 xWrtRIP], X86_SEL_TYPE_SYS_386_CALL_GATE + BS2_TRAP_INSTR X86_XCPT_GP, (3 << X86_TRAP_ERR_SEL_SHIFT) | X86_TRAP_ERR_IDT, int3 +%endif + + ; + ; Legal types. + ; + pushf + sti ; make sure interrupts are enabled. + +%ifdef TMPL_LM64 + and byte [bs2Idt_BP + 5 xWrtRIP], 0e0h + or byte [bs2Idt_BP + 5 xWrtRIP], AMD64_SEL_TYPE_SYS_INT_GATE + BS2_TRAP_INSTR X86_XCPT_BP, 0, int3 + ASSERT_TRAP_EFLAGS_IF jz + + and byte [bs2Idt_BP + 5 xWrtRIP], 0e0h + or byte [bs2Idt_BP + 5 xWrtRIP], AMD64_SEL_TYPE_SYS_TRAP_GATE + BS2_TRAP_INSTR X86_XCPT_BP, 0, int3 + ASSERT_TRAP_EFLAGS_IF jnz +%else + and byte [bs2Idt_BP + 5 xWrtRIP], 0e0h + or byte [bs2Idt_BP + 5 xWrtRIP], X86_SEL_TYPE_SYS_386_INT_GATE + BS2_TRAP_INSTR X86_XCPT_BP, 0, int3 + ASSERT_TRAP_EFLAGS_IF jz + + and byte [bs2Idt_BP + 5 xWrtRIP], 0e0h + or byte [bs2Idt_BP + 5 xWrtRIP], X86_SEL_TYPE_SYS_386_TRAP_GATE + BS2_TRAP_INSTR X86_XCPT_BP, 0, int3 + ASSERT_TRAP_EFLAGS_IF jnz + + ;; @todo X86_SEL_TYPE_SYS_TASK_GATE, X86_SEL_TYPE_SYS_286_INT_GATE, X86_SEL_TYPE_SYS_286_TRAP_GATE, X86_SEL_TYPE_SYS_386_CALL_GATE +%endif + + popf + + ; + ; Check that a not-present gate GPs. The not-present bit is 0x2f. + ; + and byte [bs2Idt_BP + 5 xWrtRIP], 0e0h +%ifdef TMPL_LM64 + or byte [bs2Idt_BP + 5 xWrtRIP], AMD64_SEL_TYPE_SYS_INT_GATE +%else + or byte [bs2Idt_BP + 5 xWrtRIP], X86_SEL_TYPE_SYS_386_TRAP_GATE +%endif + BS2_TRAP_INSTR X86_XCPT_BP, 0, int3 + + and byte [bs2Idt_BP + 5 xWrtRIP], 07fh + BS2_TRAP_INSTR X86_XCPT_NP, (3 << X86_TRAP_ERR_SEL_SHIFT) | X86_TRAP_ERR_IDT, int3 + + ; + ; Restore the descriptor and make sure it works. + ; + ASSERT_SIMPLE xDI, xSP, je, "Someone busted xSP during this test." +%ifdef TMPL_LM64 + pop qword [bs2Idt_BP + 8 xWrtRIP] + pop qword [bs2Idt_BP xWrtRIP] +%else + pop dword [bs2Idt_BP + 4 xWrtRIP] + pop dword [bs2Idt_BP xWrtRIP] +%endif + BS2_TRAP_INSTR X86_XCPT_BP, 0, int3 + + ; + ; Done. + ; + call TMPL_NM_CMN(TestSubDone) + + pop xSI + pop xDI + pop xDX + pop xCX + pop xBX + pop sAX + leave + ret + +.s_szSubTestName: + db TMPL_MODE_STR, ', IDTE type checks', 0 +ENDPROC TMPL_NM(TestGateType) + + +;; +; Checks different code selector types. +; +; @uses No registers, but BS2_SEL_SPARE0 is trashed. +; +BEGINPROC TMPL_NM(TestCodeSelector) + push xBP + mov xBP, xSP + push sAX + push xBX + push xCX + push xDX + push xDI + push xSI + + mov xAX, .s_szSubTestName + call TMPL_NM_CMN(TestSub) + + + ; + ; Modify the first extra selector to be various kinds of invalid code + ; selectors. + ; + BS2_TRAP_INSTR X86_XCPT_BP, 0, int3 ; check that int3 works before we start messing around... + +%ifdef TMPL_LM64 + push qword [bs2Idt_BP xWrtRIP] + push qword [bs2Idt_BP + 8 xWrtRIP] +%else + push dword [bs2Idt_BP xWrtRIP] + push dword [bs2Idt_BP + 4 xWrtRIP] +%endif + + mov ecx, [bs2Gdt + MY_R0_CS xWrtRIP] + mov [bs2GdtSpare0 xWrtRIP], ecx + mov ecx, [bs2Gdt + MY_R0_CS + 4 xWrtRIP] + mov [bs2GdtSpare0 + 4 xWrtRIP], ecx ; GdtSpare0 is a copy of the CS descriptor now. + + mov word [bs2Idt_BP + 2 xWrtRIP], BS2_SEL_SPARE0 + + BS2_TRAP_INSTR X86_XCPT_BP, 0, int3 ; check again to make sure the CS copy is fine. + + + ; Data selector (u4Type starts at bit 0x28, that is byte 5) . + and byte [bs2GdtSpare0 + 5 xWrtRIP], 0f0h + or byte [bs2GdtSpare0 + 5 xWrtRIP], X86_SEL_TYPE_RO + BS2_TRAP_INSTR X86_XCPT_GP, BS2_SEL_SPARE0, int3 + + and byte [bs2GdtSpare0 + 5 xWrtRIP], 0f0h + or byte [bs2GdtSpare0 + 5 xWrtRIP], X86_SEL_TYPE_RO_ACC + BS2_TRAP_INSTR X86_XCPT_GP, BS2_SEL_SPARE0, int3 + + and byte [bs2GdtSpare0 + 5 xWrtRIP], 0f0h + or byte [bs2GdtSpare0 + 5 xWrtRIP], X86_SEL_TYPE_RW + BS2_TRAP_INSTR X86_XCPT_GP, BS2_SEL_SPARE0, int3 + + and byte [bs2GdtSpare0 + 5 xWrtRIP], 0f0h + or byte [bs2GdtSpare0 + 5 xWrtRIP], X86_SEL_TYPE_RW_ACC + BS2_TRAP_INSTR X86_XCPT_GP, BS2_SEL_SPARE0, int3 + + and byte [bs2GdtSpare0 + 5 xWrtRIP], 0f0h + or byte [bs2GdtSpare0 + 5 xWrtRIP], X86_SEL_TYPE_RO_DOWN + BS2_TRAP_INSTR X86_XCPT_GP, BS2_SEL_SPARE0, int3 + + and byte [bs2GdtSpare0 + 5 xWrtRIP], 0f0h + or byte [bs2GdtSpare0 + 5 xWrtRIP], X86_SEL_TYPE_RO_DOWN_ACC + BS2_TRAP_INSTR X86_XCPT_GP, BS2_SEL_SPARE0, int3 + + and byte [bs2GdtSpare0 + 5 xWrtRIP], 0f0h + or byte [bs2GdtSpare0 + 5 xWrtRIP], X86_SEL_TYPE_RW_DOWN + BS2_TRAP_INSTR X86_XCPT_GP, BS2_SEL_SPARE0, int3 + + and byte [bs2GdtSpare0 + 5 xWrtRIP], 0f0h + or byte [bs2GdtSpare0 + 5 xWrtRIP], X86_SEL_TYPE_RW_DOWN_ACC + BS2_TRAP_INSTR X86_XCPT_GP, BS2_SEL_SPARE0, int3 + + ; Executable selector types (works fine). + and byte [bs2GdtSpare0 + 5 xWrtRIP], 0f0h + or byte [bs2GdtSpare0 + 5 xWrtRIP], X86_SEL_TYPE_EO + BS2_TRAP_INSTR X86_XCPT_BP, 0, int3 + + and byte [bs2GdtSpare0 + 5 xWrtRIP], 0f0h + or byte [bs2GdtSpare0 + 5 xWrtRIP], X86_SEL_TYPE_EO_ACC + BS2_TRAP_INSTR X86_XCPT_BP, 0, int3 + + and byte [bs2GdtSpare0 + 5 xWrtRIP], 0f0h + or byte [bs2GdtSpare0 + 5 xWrtRIP], X86_SEL_TYPE_ER + BS2_TRAP_INSTR X86_XCPT_BP, 0, int3 + + and byte [bs2GdtSpare0 + 5 xWrtRIP], 0f0h + or byte [bs2GdtSpare0 + 5 xWrtRIP], X86_SEL_TYPE_ER_ACC + BS2_TRAP_INSTR X86_XCPT_BP, 0, int3 + + and byte [bs2GdtSpare0 + 5 xWrtRIP], 0f0h + or byte [bs2GdtSpare0 + 5 xWrtRIP], X86_SEL_TYPE_EO_CONF + BS2_TRAP_INSTR X86_XCPT_BP, 0, int3 + + and byte [bs2GdtSpare0 + 5 xWrtRIP], 0f0h + or byte [bs2GdtSpare0 + 5 xWrtRIP], X86_SEL_TYPE_EO_CONF_ACC + BS2_TRAP_INSTR X86_XCPT_BP, 0, int3 + + and byte [bs2GdtSpare0 + 5 xWrtRIP], 0f0h + or byte [bs2GdtSpare0 + 5 xWrtRIP], X86_SEL_TYPE_ER_CONF + BS2_TRAP_INSTR X86_XCPT_BP, 0, int3 + + and byte [bs2GdtSpare0 + 5 xWrtRIP], 0f0h + or byte [bs2GdtSpare0 + 5 xWrtRIP], X86_SEL_TYPE_ER_CONF_ACC + BS2_TRAP_INSTR X86_XCPT_BP, 0, int3 + + ; + ; Test with the code selector set to NULL. + ; + mov word [bs2Idt_BP + 2 xWrtRIP], 0 + BS2_TRAP_INSTR X86_XCPT_GP, 0, int3 + + mov word [bs2Idt_BP + 2 xWrtRIP], 1 + BS2_TRAP_INSTR X86_XCPT_GP, 0, int3 + + mov word [bs2Idt_BP + 2 xWrtRIP], 2 + BS2_TRAP_INSTR X86_XCPT_GP, 0, int3 + + mov word [bs2Idt_BP + 2 xWrtRIP], 3 + BS2_TRAP_INSTR X86_XCPT_GP, 0, int3 + + mov word [bs2Idt_BP + 2 xWrtRIP], BS2_SEL_SPARE0 ; restore our CS + + ; + ; Test with the code selector marked as not present but otherwise valid. + ; + and byte [bs2GdtSpare0 + 5 xWrtRIP], 0f0h + or byte [bs2GdtSpare0 + 5 xWrtRIP], X86_SEL_TYPE_ER_ACC + BS2_TRAP_INSTR X86_XCPT_BP, 0, int3 + + and byte [bs2GdtSpare0 + 5 xWrtRIP], 07fh + BS2_TRAP_INSTR X86_XCPT_NP, BS2_SEL_SPARE0, int3 + + ; + ; Invalid CS selector and not present, we should get a GP. + ; Intel states that the present bit is checked after the type. + ; + and byte [bs2GdtSpare0 + 5 xWrtRIP], 070h + or byte [bs2GdtSpare0 + 5 xWrtRIP], X86_SEL_TYPE_RW_DOWN_ACC + BS2_TRAP_INSTR X86_XCPT_GP, BS2_SEL_SPARE0, int3 + +%ifdef TMPL_LM64 + ; Long mode variations on invalid (L and D bits) pitted against NP. + and byte [bs2GdtSpare0 + 5 xWrtRIP], 070h + or byte [bs2GdtSpare0 + 5 xWrtRIP], X86_SEL_TYPE_ER_ACC + and byte [bs2GdtSpare0 + 6 xWrtRIP], ~(RT_BIT(5) | RT_BIT(6)) ; (0x35=u1Long, 0x36=u1DefBig) = (0, 0) + BS2_TRAP_INSTR X86_XCPT_GP, BS2_SEL_SPARE0, int3 + + or byte [bs2GdtSpare0 + 6 xWrtRIP], RT_BIT(6) ; (0x35=u1Long, 0x36=u1DefBig) = (0, 1) + BS2_TRAP_INSTR X86_XCPT_GP, BS2_SEL_SPARE0, int3 + + or byte [bs2GdtSpare0 + 6 xWrtRIP], RT_BIT(5) ; (0x35=u1Long, 0x36=u1DefBig) = (1, 1) + BS2_TRAP_INSTR X86_XCPT_GP, BS2_SEL_SPARE0, int3 + + and byte [bs2GdtSpare0 + 6 xWrtRIP], ~(RT_BIT(5) | RT_BIT(6)) + or byte [bs2GdtSpare0 + 6 xWrtRIP], RT_BIT(5) ; restored +%endif + + and byte [bs2GdtSpare0 + 5 xWrtRIP], 070h + or byte [bs2GdtSpare0 + 5 xWrtRIP], X86_SEL_TYPE_ER_ACC | 080h ; restore CS to present & valid. + BS2_TRAP_INSTR X86_XCPT_BP, 0, int3 ; make sure this is so. + + ; + ; Check the CS DPL vs IDTE DPL. + ; X86DESCGENERIC.u2Dpl is at bit 0x2d (i.e. in byte 5). + ; + and byte [bs2GdtSpare0 + 5 xWrtRIP], ~(RT_BIT(5) | RT_BIT(6)) + or byte [bs2GdtSpare0 + 5 xWrtRIP], 0 ; CS.DPL == 0 == CPL + BS2_TRAP_INSTR X86_XCPT_BP, 0, int3 + + and byte [bs2GdtSpare0 + 5 xWrtRIP], ~(RT_BIT(5) | RT_BIT(6)) + or byte [bs2GdtSpare0 + 5 xWrtRIP], 1 << 5 ; CS.DPL == 1 < CPL + BS2_TRAP_INSTR X86_XCPT_GP, BS2_SEL_SPARE0, int3 + + and byte [bs2GdtSpare0 + 5 xWrtRIP], ~(RT_BIT(5) | RT_BIT(6)) + or byte [bs2GdtSpare0 + 5 xWrtRIP], 2 << 5 ; CS.DPL == 2 < CPL + BS2_TRAP_INSTR X86_XCPT_GP, BS2_SEL_SPARE0, int3 + + and byte [bs2GdtSpare0 + 5 xWrtRIP], ~(RT_BIT(5) | RT_BIT(6)) + or byte [bs2GdtSpare0 + 5 xWrtRIP], 3 << 5 ; CS.DPL == 3 < CPL + BS2_TRAP_INSTR X86_XCPT_GP, BS2_SEL_SPARE0, int3 + + ; Restore. + and byte [bs2GdtSpare0 + 5 xWrtRIP], 010h + or byte [bs2GdtSpare0 + 5 xWrtRIP], X86_SEL_TYPE_ER_ACC | 080h ; restore CS to present, valid and DPL=0 + BS2_TRAP_INSTR X86_XCPT_BP, 0, int3 ; make sure it's restored. + + ; + ; Is RPL is ignored? Yes, it is. + ; + and word [bs2Idt_BP + 2 xWrtRIP], X86_SEL_MASK_OFF_RPL ; RPL = 0 + BS2_TRAP_INSTR X86_XCPT_BP, 0, int3 + ASSERT_TRAP_CS_VALUE BS2_SEL_SPARE0 + + and word [bs2Idt_BP + 2 xWrtRIP], X86_SEL_MASK_OFF_RPL + or byte [bs2Idt_BP + 2 xWrtRIP], 1 ; RPL = 1 + BS2_TRAP_INSTR X86_XCPT_BP, 0, int3 + ASSERT_TRAP_CS_VALUE BS2_SEL_SPARE0 + + and word [bs2Idt_BP + 2 xWrtRIP], X86_SEL_MASK_OFF_RPL + or byte [bs2Idt_BP + 2 xWrtRIP], 2 ; RPL = 2 + BS2_TRAP_INSTR X86_XCPT_BP, 0, int3 + ASSERT_TRAP_CS_VALUE BS2_SEL_SPARE0 + + and word [bs2Idt_BP + 2 xWrtRIP], X86_SEL_MASK_OFF_RPL + or byte [bs2Idt_BP + 2 xWrtRIP], 3 ; RPL = 3 + BS2_TRAP_INSTR X86_XCPT_BP, 0, int3 + ASSERT_TRAP_CS_VALUE BS2_SEL_SPARE0 + + ; + ; Conforming CS. + ; + or byte [bs2Idt_BP + 5 xWrtRIP], (3 << 5) ; IDTE.DPL = 3 + and byte [bs2GdtSpare0 + 5 xWrtRIP], 090h + or byte [bs2GdtSpare0 + 5 xWrtRIP], X86_SEL_TYPE_ER_CONF_ACC ; CS.DPL=0, code, read, conforming + + call TMPL_NM_CMN(Bs2ToRing1) + BS2_TRAP_INSTR X86_XCPT_BP, 0, int3 + call TMPL_NM_CMN(Bs2ToRing0) + ASSERT_TRAP_CS_VALUE BS2_SEL_SPARE0 | 1 + + call TMPL_NM_CMN(Bs2ToRing2) + BS2_TRAP_INSTR X86_XCPT_BP, 0, int3 + call TMPL_NM_CMN(Bs2ToRing0) + ASSERT_TRAP_CS_VALUE BS2_SEL_SPARE0 | 2 + + call TMPL_NM_CMN(Bs2ToRing3) + BS2_TRAP_INSTR X86_XCPT_BP, 0, int3 + call TMPL_NM_CMN(Bs2ToRing0) + ASSERT_TRAP_CS_VALUE BS2_SEL_SPARE0 | 3 + + BS2_TRAP_INSTR X86_XCPT_BP, 0, int3 + ASSERT_TRAP_CS_VALUE BS2_SEL_SPARE0 | 0 + + ; RPL is ignored. Only CPL matters. + or byte [bs2Idt_BP + 2 xWrtRIP], (3 << 5) ; IDTE.CS.RPL=3 + call TMPL_NM_CMN(Bs2ToRing2) + BS2_TRAP_INSTR X86_XCPT_BP, 0, int3 + call TMPL_NM_CMN(Bs2ToRing0) + ASSERT_TRAP_CS_VALUE BS2_SEL_SPARE0 | 2 + + and word [bs2Idt_BP + 2 xWrtRIP], X86_SEL_MASK_OFF_RPL + or byte [bs2Idt_BP + 2 xWrtRIP], (1 << 5) ; IDTE.CS.RPL=1 + call TMPL_NM_CMN(Bs2ToRing2) + BS2_TRAP_INSTR X86_XCPT_BP, 0, int3 + call TMPL_NM_CMN(Bs2ToRing0) + ASSERT_TRAP_CS_VALUE BS2_SEL_SPARE0 | 2 + + and word [bs2Idt_BP + 2 xWrtRIP], X86_SEL_MASK_OFF_RPL + or byte [bs2Idt_BP + 2 xWrtRIP], (2 << 5) ; IDTE.CS.RPL=2 + call TMPL_NM_CMN(Bs2ToRing2) + BS2_TRAP_INSTR X86_XCPT_BP, 0, int3 + call TMPL_NM_CMN(Bs2ToRing0) + ASSERT_TRAP_CS_VALUE BS2_SEL_SPARE0 | 2 + + ; Change the CS.DPL to 1 and try it from ring-0. + and byte [bs2GdtSpare0 + 5 xWrtRIP], 09fh + or byte [bs2GdtSpare0 + 5 xWrtRIP], (1 << 5) ; CS.DPL=1 + BS2_TRAP_INSTR X86_XCPT_GP, BS2_SEL_SPARE0, int3 + + ; Restore. + and word [bs2Idt_BP + 2 xWrtRIP], X86_SEL_MASK_OFF_RPL + and byte [bs2Idt_BP + 5 xWrtRIP], 0x9f ; IDTE.DPL=0 + and byte [bs2GdtSpare0 + 5 xWrtRIP], 010h + or byte [bs2GdtSpare0 + 5 xWrtRIP], X86_SEL_TYPE_ER_ACC | 080h ; restore CS to present, valid and DPL=0 + BS2_TRAP_INSTR X86_XCPT_BP, 0, int3 ; make sure it's restored. + + ; + ; Limit / canonical checks. + ; + ; Messing with X86DESCGENERIC.u16LimitLow which is at bit 0, + ; X86DESCGENERIC.u4LimitHigh which is at bit 0x30, and + ; X86DESCGENERIC.u1Granularity which is at bit 0x37. + ; + mov word [bs2GdtSpare0 xWrtRIP], 0010h + and byte [bs2GdtSpare0 + 6 xWrtRIP], 070h ; setting limit to 0x10, ASSUMES IDTE.off > 0x10 +%ifdef TMPL_LM64 + BS2_TRAP_INSTR X86_XCPT_BP, 0, int3 +%else + BS2_TRAP_INSTR X86_XCPT_GP, 0, int3 +%endif + +%ifdef TMPL_LM64 + or dword [bs2Idt_BP + 8 xWrtRIP], 0x007f7f33 + BS2_TRAP_INSTR X86_XCPT_GP, 0, int3 +%endif + + ; Who takes precedence? CS NP or the above GP? NP does. + and byte [bs2GdtSpare0 + 5 xWrtRIP], 07fh + BS2_TRAP_INSTR X86_XCPT_NP, BS2_SEL_SPARE0, int3 + + +%ifdef TMPL_LM64 + ; Who takes precedence? IDTE NP or the not canoncial GP? NP does. + or byte [bs2GdtSpare0 + 5 xWrtRIP], 80h + and byte [bs2Idt_BP + 5 xWrtRIP], 07fh + BS2_TRAP_INSTR X86_XCPT_NP, (3 << X86_TRAP_ERR_SEL_SHIFT) | X86_TRAP_ERR_IDT, int3 +%endif + + ; + ; Restore the descriptor and make sure it works. + ; +%ifdef TMPL_LM64 + pop qword [bs2Idt_BP + 8 xWrtRIP] + pop qword [bs2Idt_BP xWrtRIP] +%else + pop dword [bs2Idt_BP + 4 xWrtRIP] + pop dword [bs2Idt_BP xWrtRIP] +%endif + BS2_TRAP_INSTR X86_XCPT_BP, 0, int3 + + ; + ; Done. + ; + call TMPL_NM_CMN(TestSubDone) + + pop xSI + pop xDI + pop xDX + pop xCX + pop xBX + pop sAX + leave + ret + +.s_szSubTestName: + db TMPL_MODE_STR, ', IDTE CS checks', 0 +ENDPROC TMPL_NM(TestCodeSelector) + + +;; +; Checks that the IDTE type is checked before the CS type. +; +; @uses No registers, but BS2_SEL_SPARE0 is trashed. +; +BEGINPROC TMPL_NM(TestCheckOrderCsTypeVsIdteType) + push xBP + mov xBP, xSP + push sAX + push xBX + push xCX + push xDX + push xDI + push xSI + + mov xAX, .s_szSubTestName + call TMPL_NM_CMN(TestSub) + + + ; + ; Check the int3 and save its IDTE. + ; + ; We'll be changing X86DESCGATE.u4Type, which starts at bit 0x28 (that + ; is byte 5) and is 4-bit wide, and X86DESCGATE.u1DescType, which is + ; at bit 2c. + ; + BS2_TRAP_INSTR X86_XCPT_BP, 0, int3 ; check that int3 works before we start messing around... + +%ifdef TMPL_LM64 + push qword [bs2Idt_BP xWrtRIP] + push qword [bs2Idt_BP + 8 xWrtRIP] +%else + push dword [bs2Idt_BP xWrtRIP] + push dword [bs2Idt_BP + 4 xWrtRIP] +%endif + + ; + ; Make a copy of our CS descriptor into spare one and make INT3 use it. + ; + mov ecx, [bs2Gdt + MY_R0_CS xWrtRIP] + mov [bs2GdtSpare0 xWrtRIP], ecx + mov ecx, [bs2Gdt + MY_R0_CS + 4 xWrtRIP] + mov [bs2GdtSpare0 + 4 xWrtRIP], ecx ; GdtSpare0 is a copy of the CS descriptor now. + + mov word [bs2Idt_BP + 2 xWrtRIP], BS2_SEL_SPARE0 + + BS2_TRAP_INSTR X86_XCPT_BP, 0, int3 ; check again to make sure the CS copy is fine. + + ; + ; Make both the IDTE type and CS invalid, we should end up with a IDT GP not the CS one. + ; CS = data selector and IDTE invalid 0 type. + ; + and byte [bs2GdtSpare0 + 5 xWrtRIP], 0f0h + or byte [bs2GdtSpare0 + 5 xWrtRIP], X86_SEL_TYPE_RO + + and byte [bs2Idt_BP + 5 xWrtRIP], 0e0h + or byte [bs2Idt_BP + 5 xWrtRIP], X86_SEL_TYPE_SYS_UNDEFINED + BS2_TRAP_INSTR X86_XCPT_GP, (3 << X86_TRAP_ERR_SEL_SHIFT) | X86_TRAP_ERR_IDT, int3 + + ; + ; Make the IDTE not-present but otherwise fine, keeping CS invalid. + ; + and byte [bs2Idt_BP + 5 xWrtRIP], 070h +%ifdef TMPL_LM64 + or byte [bs2Idt_BP + 5 xWrtRIP], AMD64_SEL_TYPE_SYS_INT_GATE +%else + or byte [bs2Idt_BP + 5 xWrtRIP], X86_SEL_TYPE_SYS_386_TRAP_GATE +%endif + BS2_TRAP_INSTR X86_XCPT_NP, (3 << X86_TRAP_ERR_SEL_SHIFT) | X86_TRAP_ERR_IDT, int3 + + ; + ; Make the CS not present as well. + ; + and byte [bs2GdtSpare0 + 5 xWrtRIP], 070h + or byte [bs2GdtSpare0 + 5 xWrtRIP], X86_SEL_TYPE_EO + BS2_TRAP_INSTR X86_XCPT_NP, (3 << X86_TRAP_ERR_SEL_SHIFT) | X86_TRAP_ERR_IDT, int3 + + ; + ; CS not present, IDTE invalid but present. + ; + and byte [bs2Idt_BP + 5 xWrtRIP], 0f0h + or byte [bs2Idt_BP + 5 xWrtRIP], X86_SEL_TYPE_SYS_UNDEFINED | 0x80 + BS2_TRAP_INSTR X86_XCPT_GP, (3 << X86_TRAP_ERR_SEL_SHIFT) | X86_TRAP_ERR_IDT, int3 + + ; + ; CS NULL, IDTE invalid but present. + ; + mov word [bs2Idt_BP + 2 xWrtRIP], 0 + BS2_TRAP_INSTR X86_XCPT_GP, (3 << X86_TRAP_ERR_SEL_SHIFT) | X86_TRAP_ERR_IDT, int3 + + ; + ; CS NULL, IDTE valid but not present. + ; + and byte [bs2Idt_BP + 5 xWrtRIP], 070h +%ifdef TMPL_LM64 + or byte [bs2Idt_BP + 5 xWrtRIP], AMD64_SEL_TYPE_SYS_INT_GATE +%else + or byte [bs2Idt_BP + 5 xWrtRIP], X86_SEL_TYPE_SYS_386_TRAP_GATE +%endif + BS2_TRAP_INSTR X86_XCPT_NP, (3 << X86_TRAP_ERR_SEL_SHIFT) | X86_TRAP_ERR_IDT, int3 + + ; + ; Restore the descriptor and make sure it works. + ; +%ifdef TMPL_LM64 + pop qword [bs2Idt_BP + 8 xWrtRIP] + pop qword [bs2Idt_BP xWrtRIP] +%else + pop dword [bs2Idt_BP + 4 xWrtRIP] + pop dword [bs2Idt_BP xWrtRIP] +%endif + BS2_TRAP_INSTR X86_XCPT_BP, 0, int3 + + ; + ; Done. + ; + call TMPL_NM_CMN(TestSubDone) + + pop xSI + pop xDI + pop xDX + pop xCX + pop xBX + pop sAX + leave + ret + +.s_szSubTestName: + db TMPL_MODE_STR, ', IDTE.type before CS.type', 0 +ENDPROC TMPL_NM(TestCheckOrderCsTypeVsIdteType) + + +;; +; Checks stack switching behavior. +; +; @uses none +; +BEGINPROC TMPL_NM(TestStack) + push xBP + mov xBP, xSP + push sAX + push xBX + push xCX + push xDX + push xDI + push xSI + pushf + cli + + mov xAX, .s_szSubTestName + call TMPL_NM_CMN(TestSub) + + + ; + ; Check the int3, save its IDTE, then make it ring-3 accessible. + ; + ; X86DESCGENERIC.u2Dpl is at bit 0x2d (i.e. in byte 5). + ; + BS2_TRAP_INSTR X86_XCPT_BP, 0, int3 ; check that int3 works before we start messing around... + +%ifdef TMPL_LM64 + push qword [bs2Idt_BP xWrtRIP] + push qword [bs2Idt_BP + 8 xWrtRIP] +%else + push dword [bs2Idt_BP xWrtRIP] + push dword [bs2Idt_BP + 4 xWrtRIP] +%endif + + and byte [bs2Idt_BP + 5 xWrtRIP], ~(RT_BIT(5) | RT_BIT(6)) + or byte [bs2Idt_BP + 5 xWrtRIP], 3 << 5 ; DPL == 3 + + BS2_TRAP_INSTR X86_XCPT_BP, 0, int3 + + + ; + ; In ring-0 no stack switching is performed. + ; + BS2_TRAP_INSTR X86_XCPT_BP, 0, int3 + mov xBX, [g_u64LastTrapHandlerRSP] +%ifdef TMPL_64BIT + mov rax, rsp + and rax, ~15 + sub rax, 7*8 +%else + lea eax, [esp - 5*4] +%endif + ASSERT_SIMPLE sAX, xBX, je, "Wrong xSP value for ring-0 -> ring-0 int3." + mov bx, [g_u16LastTrapHandlerSS] + mov ax, ss + ASSERT_SIMPLE ax, bx, je, "Wrong SS value for ring-0 -> ring-0 int3." + + ; + ; Switch to ring-1 and watch stack switching take place. + ; + call TMPL_NM_CMN(Bs2ToRing1) + + BS2_TRAP_INSTR X86_XCPT_BP, 0, int3 + mov xBX, [g_u64LastTrapHandlerRSP] + mov sAX, BS2_R0_STACK_ADDR +%ifdef TMPL_64BIT + and rax, ~15 + sub rax, 7*8 +%else + sub eax, 7*4 +%endif + ASSERT_SIMPLE sAX, xBX, je, "Wrong xSP value for ring-1 -> ring-0 int3." + mov bx, [g_u16LastTrapHandlerSS] +%ifdef TMPL_64BIT + mov ax, 0 +%else + mov ax, MY_R0_SS +%endif + ASSERT_SIMPLE ax, bx, je, "Wrong SS value for ring-1 -> ring-0 int3." + + call TMPL_NM_CMN(Bs2ToRing0) + + ; + ; Missaligned stack, ring-0 -> ring-0. + ; + mov xDI, xSP ; save the stack pointer. +%rep 15 + sub xSP, 1h + + BS2_TRAP_INSTR X86_XCPT_BP, 0, int3 + mov xBX, [g_u64LastTrapHandlerRSP] +%ifdef TMPL_64BIT + mov rax, rsp + and rax, ~15 + sub rax, 7*8 +%else + lea eax, [esp - 5*4] +%endif + ASSERT_SIMPLE sAX, xBX, je, "Wrong xSP value for ring-0 -> ring-0 int3, w/ unaligned stack." + mov bx, [g_u16LastTrapHandlerSS] + mov ax, ss + ASSERT_SIMPLE ax, bx, je, "Wrong SS value for ring-0 -> ring-0 int3, w/ unaligned stack." + +%endrep + mov xSP, xDI ; restore the stack pointer. + + ; + ; Missaligned stack, ring-1 -> ring-0. + ; + call TMPL_NM_CMN(Bs2ToRing1) + + mov sSI, BS2_R0_STACK_ADDR - 16 +%rep 16 + add sSI, 1 +%ifdef TMPL_64BIT + mov [bs2Tss64Bit + 4], sSI +%else + mov [bs2Tss32Bit + 4], sSI +%endif + + BS2_TRAP_INSTR X86_XCPT_BP, 0, int3 + mov xBX, [g_u64LastTrapHandlerRSP] + mov sAX, sSI +%ifdef TMPL_64BIT + and rax, ~15 + sub rax, 7*8 +%else + sub eax, 7*4 +%endif + ASSERT_SIMPLE sAX, xBX, je, "Wrong xSP value for ring-1 -> ring-0 int3, w/ unaligned ring-0 stack." + mov bx, [g_u16LastTrapHandlerSS] +%ifdef TMPL_64BIT + mov ax, 0 +%else + mov ax, MY_R0_SS +%endif + ASSERT_SIMPLE sAX, xBX, je, "Wrong SS value for ring-1 -> ring-0 int3, w/ unaligned ring-0 stack." + +%endrep + call TMPL_NM_CMN(Bs2ToRing0) + + +%ifdef TMPL_64BIT + ; + ; Stack table (AMD64 only), ring-0 -> ring-0. + ; + and byte [bs2Idt_BP + 4], ~7 + or byte [bs2Idt_BP + 4], 3 ; IDTE.IST=3 + + mov rdi, [bs2Tss64Bit + X86TSS64.ist3] + mov rsi, BS2_R0_STACK_ADDR - 128 + %rep 16 + sub rsi, 1h + mov [bs2Tss64Bit + X86TSS64.ist3], rsi + + BS2_TRAP_INSTR X86_XCPT_BP, 0, int3 + mov rbx, [g_u64LastTrapHandlerRSP] + mov rax, rsi + and rax, ~15 + sub rax, 7*8 + ASSERT_SIMPLE rax, rbx, je, "Wrong xSP value for ring-0 -> ring-0 int3, w/ unaligned IST." + mov bx, [g_u16LastTrapHandlerSS] + mov ax, ss + ASSERT_SIMPLE ax, bx, je, "Wrong SS value for ring-0 -> ring-0 int3, w/ unaligned IST." + + %endrep + + ; Continue in ring-1,2,3. + %assign uCurRing 1 + %rep 3 + call TMPL_NM_CMN(Bs2ToRing %+ uCurRing) + %rep 16 + sub rsi, 1h + mov [bs2Tss64Bit + X86TSS64.ist3], rsi + + BS2_TRAP_INSTR X86_XCPT_BP, 0, int3 + mov rbx, [g_u64LastTrapHandlerRSP] + mov rax, rsi + and rax, ~15 + sub rax, 7*8 + ASSERT_SIMPLE rax, rbx, je, "Wrong xSP value for ring-X -> ring-0 int3, w/ unaligned IST." + mov bx, [g_u16LastTrapHandlerSS] + mov ax, 0 + ASSERT_SIMPLE ax, bx, je, "Wrong SS value for ring-X -> ring-0 int3, w/ unaligned IST." + %endrep + call TMPL_NM_CMN(Bs2ToRing0) + %assign uCurRing (uCurRing + 1) + %endrep + + mov [bs2Tss64Bit + X86TSS64.ist3], rdi ; restore original value + and byte [bs2Idt_BP + 4], ~7 ; IDTE.IST=0 + + + ; + ; Check SS handling when interrupting 32-bit code with a 64-bit handler. + ; + call Bs2Thunk_lm64_lm32 + BITS 32 + BS2_TRAP_INSTR X86_XCPT_BP, 0, int3 + mov bx, [g_u16LastTrapHandlerSS] + mov ax, ss + call Bs2Thunk_lm32_lm64 + BITS 64 + ASSERT_SIMPLE ax, bx, je, "Wrong SS value for ring-0-32 -> ring-0-64 int3, w/ 32-bit stack." + + call Bs2Thunk_lm64_lm32 + BITS 32 + mov cx, ss + mov ax, BS2_SEL_SS16 + mov ss, ax + BS2_TRAP_INSTR X86_XCPT_BP, 0, int3 + mov bx, [g_u16LastTrapHandlerSS] + mov ss, cx + call Bs2Thunk_lm32_lm64 + BITS 64 + ASSERT_SIMPLE ax, bx, je, "Wrong SS value for ring-0-32 -> ring-0-64 int3, w/ 16-bit stack." + +%endif ; TMPL_64BIT + + + ; + ; Restore the descriptor and make sure it works. + ; +%ifdef TMPL_LM64 + pop qword [bs2Idt_BP + 8 xWrtRIP] + pop qword [bs2Idt_BP xWrtRIP] +%else + pop dword [bs2Idt_BP + 4 xWrtRIP] + pop dword [bs2Idt_BP xWrtRIP] +%endif + BS2_TRAP_INSTR X86_XCPT_BP, 0, int3 + + ; + ; Done. + ; + call TMPL_NM_CMN(TestSubDone) + + popf + pop xSI + pop xDI + pop xDX + pop xCX + pop xBX + pop sAX + leave + ret + +.s_szSubTestName: + db TMPL_MODE_STR, ', Stack switching', 0 +ENDPROC TMPL_NM(TestStack) + + + +;; +; Loads MY_R0_CS into CS. +; +; @uses stack, cs, flags +; +BEGINPROC TMPL_NM(TestLoadMyCS) + push 0 + push xAX + + ; Make it a far return with MY_R0_CS + CPL. + mov xAX, [xSP + xCB*2] + mov [xSP + xCB*1], xAX + mov xAX, ss +%ifdef TMPL_64BIT + sub xAX, BS2_SEL_GRP_SS64 - BS2_SEL_GRP_CS64 +%elifdef TMPL_32BIT + sub xAX, BS2_SEL_GRP_SS32 - BS2_SEL_GRP_CS32 +%elifdef TMPL_16BIT + sub xAX, BS2_SEL_GRP_SS16 - BS2_SEL_GRP_CS16 +%else + TMPL_xxBIT is not defined +%endif + mov [xSP + xCB*2], xAX + + pop xAX + retf +ENDPROC TMPL_NM(TestLoadMyCS) + + +;; +; Checks our understanding of how conforming segments are handled. +; +; @uses No registers, but BS2_SEL_SPARE0 is trashed. +; +BEGINPROC TMPL_NM(TestConforming) + push xBP + mov xBP, xSP + push sAX + push xBX + push xCX + push xDX + push xDI + push xSI + + mov xAX, .s_szSubTestName + call TMPL_NM_CMN(TestSub) + + ; + ; Check the int3. + ; + BS2_TRAP_INSTR X86_XCPT_BP, 0, int3 ; check that int3 works before we start messing around... + + mov xDI, xSP ; save the stack pointer. + sub xSP, 20h + + ; + ; In this test we will do various experiments with code using a + ; conforming CS. The main purpose is to check that CS.RPL is always the + ; same as CPL, despite earlier beliefs to the contrary. Because if it + ; is different, iret cannot dermine the CPL to return to among other + ; interesting problems. + ; + mov ecx, [bs2Gdt + MY_R0_CS xWrtRIP] + mov [bs2GdtSpare0 xWrtRIP], ecx + mov ecx, [bs2Gdt + MY_R0_CS + 4 xWrtRIP] + mov [bs2GdtSpare0 + 4 xWrtRIP], ecx ; GdtSpare0 is a copy of the CS descriptor now. + and byte [bs2GdtSpare0 + 5], 0x90 ; DPL = 0 + or byte [bs2GdtSpare0 + 5], X86_SEL_TYPE_ER_CONF_ACC + +%assign uCurRing 0 +%rep 4 + ; Far jumps. + %assign uSpecifiedRpl 0 + %rep 4 + call TMPL_NM_CMN(Bs2ToRing %+ uCurRing) + lea xAX, [.far_jmp_target_ %+ uSpecifiedRpl %+ uCurRing] + %ifdef TMPL_64BIT ; AMD doesn't have an jmp far m16:m64 instruction, it ignores REX.W apparently. Intel does though. + ; Tested on: Bulldozer + mov dword [xSP + 4], BS2_SEL_SPARE0 | uSpecifiedRpl + mov [xSP], eax + jmp far dword [xSP] + %else + mov dword [xSP + xCB], BS2_SEL_SPARE0 | uSpecifiedRpl + mov [xSP], xAX + jmp far xPRE [xSP] + %endif +.far_jmp_target_ %+ uSpecifiedRpl %+ uCurRing: + mov bx, cs + call TMPL_NM(TestLoadMyCS) + call TMPL_NM_CMN(Bs2ToRing0) + ASSERT_CUR_CS_VALUE_IN_BX BS2_SEL_SPARE0 | uCurRing + %assign uSpecifiedRpl uSpecifiedRpl + 1 + %endrep + + ; Far calls. + %assign uSpecifiedRpl 0 + %rep 4 + call TMPL_NM_CMN(Bs2ToRing %+ uCurRing) + mov xSI, xSP + lea xAX, [.far_call_target_ %+ uSpecifiedRpl %+ uCurRing] + %ifdef TMPL_64BIT ; AMD doesn't have an call far m16:m64 instruction, it ignores REX.W apparently. Intel does though. + ; Tested on: Bulldozer + mov dword [xSP + 4], BS2_SEL_SPARE0 | uSpecifiedRpl + mov [xSP], eax + call far dword [xSP] + %else + mov dword [xSP + xCB], BS2_SEL_SPARE0 | uSpecifiedRpl + mov [xSP], xAX + call far xPRE [xSP] + %endif +.far_call_target_ %+ uSpecifiedRpl %+ uCurRing: + mov bx, cs + %ifdef TMPL_64BIT + add xSP, 4 * 2 + %else + add xSP, xCB * 2 + %endif + call TMPL_NM(TestLoadMyCS) + call TMPL_NM_CMN(Bs2ToRing0) + ASSERT_CUR_CS_VALUE_IN_BX BS2_SEL_SPARE0 | uCurRing + %assign uSpecifiedRpl uSpecifiedRpl + 1 + %endrep + + %assign uCurRing uCurRing + 1 +%endrep + + ; + ; While at it, lets check something about RPL and non-conforming + ; segments. The check when loading is supposed to be RPL >= DPL, + ; except for when loading SS, where RPL = DPL = CPL. + ; + + ; ring-0 + mov dx, MY_R0_DS | 0 + mov fs, dx + ASSERT_CUR_SREG_VALUE fs, MY_R0_DS | 0 + mov dx, MY_R0_DS | 1 + BS2_TRAP_INSTR X86_XCPT_GP, MY_R0_DS, mov fs, dx + mov dx, MY_R0_DS | 2 + BS2_TRAP_INSTR X86_XCPT_GP, MY_R0_DS, mov fs, dx + mov dx, MY_R0_DS | 3 + BS2_TRAP_INSTR X86_XCPT_GP, MY_R0_DS, mov fs, dx + + ; ring-0 - Lower DPL isn't an issue, only RPL vs DPL. + mov dx, MY_R1_DS | 0 + mov fs, dx + ASSERT_CUR_SREG_VALUE fs, MY_R1_DS | 0 + mov dx, MY_R1_DS | 1 + mov fs, dx + ASSERT_CUR_SREG_VALUE fs, MY_R1_DS | 1 + mov dx, MY_R1_DS | 2 + BS2_TRAP_INSTR X86_XCPT_GP, MY_R1_DS, mov fs, dx + + mov dx, MY_R2_DS | 0 + mov fs, dx + ASSERT_CUR_SREG_VALUE fs, MY_R2_DS | 0 + mov dx, MY_R2_DS | 2 + mov fs, dx + ASSERT_CUR_SREG_VALUE fs, MY_R2_DS | 2 + mov dx, MY_R2_DS | 3 + BS2_TRAP_INSTR X86_XCPT_GP, MY_R2_DS, mov fs, dx + + mov dx, MY_R3_DS | 0 + mov fs, dx + ASSERT_CUR_SREG_VALUE fs, MY_R3_DS | 0 + mov dx, MY_R3_DS | 1 + mov fs, dx + ASSERT_CUR_SREG_VALUE fs, MY_R3_DS | 1 + mov dx, MY_R3_DS | 2 + mov fs, dx + ASSERT_CUR_SREG_VALUE fs, MY_R3_DS | 2 + mov dx, MY_R3_DS | 3 + mov fs, dx + ASSERT_CUR_SREG_VALUE fs, MY_R3_DS | 3 + + ; ring-0 - What works above doesn't work with ss. + mov dx, MY_R1_DS | 0 + BS2_TRAP_INSTR X86_XCPT_GP, MY_R1_DS, mov ss, dx + mov dx, MY_R1_DS | 1 + BS2_TRAP_INSTR X86_XCPT_GP, MY_R1_DS, mov ss, dx + mov dx, MY_R1_DS | 2 + BS2_TRAP_INSTR X86_XCPT_GP, MY_R1_DS, mov ss, dx + mov dx, MY_R2_DS | 0 + BS2_TRAP_INSTR X86_XCPT_GP, MY_R2_DS, mov ss, dx + mov dx, MY_R3_DS | 0 + BS2_TRAP_INSTR X86_XCPT_GP, MY_R3_DS, mov ss, dx + mov dx, MY_R3_DS | 3 + BS2_TRAP_INSTR X86_XCPT_GP, MY_R3_DS, mov ss, dx + + + ; ring-1 + call TMPL_NM_CMN(Bs2ToRing1) + + mov dx, MY_R1_DS | 0 + mov fs, dx + ASSERT_CUR_SREG_VALUE fs, MY_R1_DS | 0 + mov dx, MY_R1_DS | 1 + mov fs, dx + ASSERT_CUR_SREG_VALUE fs, MY_R1_DS | 1 + mov dx, MY_R1_DS | 2 + BS2_TRAP_INSTR X86_XCPT_GP, MY_R1_DS, mov fs, dx + mov dx, MY_R1_DS | 3 + BS2_TRAP_INSTR X86_XCPT_GP, MY_R1_DS, mov fs, dx + + mov dx, MY_R0_DS | 0 + BS2_TRAP_INSTR X86_XCPT_GP, MY_R0_DS, mov fs, dx + mov dx, MY_R0_DS | 1 + BS2_TRAP_INSTR X86_XCPT_GP, MY_R0_DS, mov fs, dx + mov dx, MY_R0_DS | 2 + BS2_TRAP_INSTR X86_XCPT_GP, MY_R0_DS, mov fs, dx + mov dx, MY_R0_DS | 3 + BS2_TRAP_INSTR X86_XCPT_GP, MY_R0_DS, mov fs, dx + + ; ring-1 - Lower DPL isn't an issue, only RPL vs DPL. + mov dx, MY_R2_DS | 0 + mov fs, dx + ASSERT_CUR_SREG_VALUE fs, MY_R2_DS | 0 + mov dx, MY_R2_DS | 1 + mov fs, dx + ASSERT_CUR_SREG_VALUE fs, MY_R2_DS | 1 + mov dx, MY_R2_DS | 2 + mov fs, dx + ASSERT_CUR_SREG_VALUE fs, MY_R2_DS | 2 + mov dx, MY_R2_DS | 3 + BS2_TRAP_INSTR X86_XCPT_GP, MY_R2_DS, mov fs, dx + + mov dx, MY_R3_DS | 0 + mov fs, dx + ASSERT_CUR_SREG_VALUE fs, MY_R3_DS | 0 + mov dx, MY_R3_DS | 1 + mov fs, dx + ASSERT_CUR_SREG_VALUE fs, MY_R3_DS | 1 + mov dx, MY_R3_DS | 2 + mov fs, dx + ASSERT_CUR_SREG_VALUE fs, MY_R3_DS | 2 + mov dx, MY_R3_DS | 3 + mov fs, dx + ASSERT_CUR_SREG_VALUE fs, MY_R3_DS | 3 + + ; ring-1 - What works above doesn't work with ss. + mov dx, MY_R1_DS | 0 + BS2_TRAP_INSTR X86_XCPT_GP, MY_R1_DS, mov ss, dx + mov dx, MY_R1_DS | 2 + BS2_TRAP_INSTR X86_XCPT_GP, MY_R1_DS, mov ss, dx + mov dx, MY_R2_DS | 0 + BS2_TRAP_INSTR X86_XCPT_GP, MY_R2_DS, mov ss, dx + mov dx, MY_R3_DS | 0 + BS2_TRAP_INSTR X86_XCPT_GP, MY_R3_DS, mov ss, dx + mov dx, MY_R3_DS | 3 + BS2_TRAP_INSTR X86_XCPT_GP, MY_R3_DS, mov ss, dx + + + ; ring-2 + call TMPL_NM_CMN(Bs2ToRing2) + + mov dx, MY_R2_DS | 0 + mov fs, dx + ASSERT_CUR_SREG_VALUE fs, MY_R2_DS | 0 + mov dx, MY_R2_DS | 1 + mov fs, dx + ASSERT_CUR_SREG_VALUE fs, MY_R2_DS | 1 + mov dx, MY_R2_DS | 2 + mov fs, dx + ASSERT_CUR_SREG_VALUE fs, MY_R2_DS | 2 + mov dx, MY_R2_DS | 3 + BS2_TRAP_INSTR X86_XCPT_GP, MY_R2_DS, mov fs, dx + + mov dx, MY_R0_DS | 0 + BS2_TRAP_INSTR X86_XCPT_GP, MY_R0_DS, mov fs, dx + mov dx, MY_R0_DS | 1 + BS2_TRAP_INSTR X86_XCPT_GP, MY_R0_DS, mov fs, dx + mov dx, MY_R0_DS | 2 + BS2_TRAP_INSTR X86_XCPT_GP, MY_R0_DS, mov fs, dx + mov dx, MY_R0_DS | 3 + BS2_TRAP_INSTR X86_XCPT_GP, MY_R0_DS, mov fs, dx + mov dx, MY_R1_DS | 1 + BS2_TRAP_INSTR X86_XCPT_GP, MY_R1_DS, mov fs, dx + mov dx, MY_R1_DS | 2 + BS2_TRAP_INSTR X86_XCPT_GP, MY_R1_DS, mov fs, dx + + ; ring-2 - Lower DPL isn't an issue, only RPL vs DPL. + mov dx, MY_R3_DS | 0 + mov fs, dx + ASSERT_CUR_SREG_VALUE fs, MY_R3_DS | 0 + mov dx, MY_R3_DS | 1 + mov fs, dx + ASSERT_CUR_SREG_VALUE fs, MY_R3_DS | 1 + mov dx, MY_R3_DS | 2 + mov fs, dx + ASSERT_CUR_SREG_VALUE fs, MY_R3_DS | 2 + mov dx, MY_R3_DS | 3 + mov fs, dx + ASSERT_CUR_SREG_VALUE fs, MY_R3_DS | 3 + + ; ring-2 - What works above doesn't work with ss. + mov dx, MY_R2_DS | 1 + BS2_TRAP_INSTR X86_XCPT_GP, MY_R2_DS, mov ss, dx + mov dx, MY_R2_DS | 3 + BS2_TRAP_INSTR X86_XCPT_GP, MY_R2_DS, mov ss, dx + mov dx, MY_R3_DS | 0 + BS2_TRAP_INSTR X86_XCPT_GP, MY_R3_DS, mov ss, dx + mov dx, MY_R3_DS | 1 + BS2_TRAP_INSTR X86_XCPT_GP, MY_R3_DS, mov ss, dx + mov dx, MY_R3_DS | 2 + BS2_TRAP_INSTR X86_XCPT_GP, MY_R3_DS, mov ss, dx + mov dx, MY_R3_DS | 3 + BS2_TRAP_INSTR X86_XCPT_GP, MY_R3_DS, mov ss, dx + + + ; ring-3 + call TMPL_NM_CMN(Bs2ToRing3) + + mov dx, MY_R3_DS | 0 + mov fs, dx + ASSERT_CUR_SREG_VALUE fs, MY_R3_DS | 0 + mov dx, MY_R3_DS | 1 + mov fs, dx + ASSERT_CUR_SREG_VALUE fs, MY_R3_DS | 1 + mov dx, MY_R3_DS | 2 + mov fs, dx + ASSERT_CUR_SREG_VALUE fs, MY_R3_DS | 2 + mov dx, MY_R3_DS | 3 + mov fs, dx + ASSERT_CUR_SREG_VALUE fs, MY_R3_DS | 3 + + mov dx, MY_R0_DS | 0 + BS2_TRAP_INSTR X86_XCPT_GP, MY_R0_DS, mov fs, dx + mov dx, MY_R0_DS | 1 + BS2_TRAP_INSTR X86_XCPT_GP, MY_R0_DS, mov fs, dx + mov dx, MY_R0_DS | 2 + BS2_TRAP_INSTR X86_XCPT_GP, MY_R0_DS, mov fs, dx + mov dx, MY_R0_DS | 3 + BS2_TRAP_INSTR X86_XCPT_GP, MY_R0_DS, mov fs, dx + + mov dx, MY_R1_DS | 1 + BS2_TRAP_INSTR X86_XCPT_GP, MY_R1_DS, mov fs, dx + mov dx, MY_R1_DS | 2 + BS2_TRAP_INSTR X86_XCPT_GP, MY_R1_DS, mov fs, dx + + mov dx, MY_R2_DS | 0 + BS2_TRAP_INSTR X86_XCPT_GP, MY_R2_DS, mov fs, dx + mov dx, MY_R2_DS | 1 + BS2_TRAP_INSTR X86_XCPT_GP, MY_R2_DS, mov fs, dx + mov dx, MY_R2_DS | 2 + BS2_TRAP_INSTR X86_XCPT_GP, MY_R2_DS, mov fs, dx + mov dx, MY_R2_DS | 3 + BS2_TRAP_INSTR X86_XCPT_GP, MY_R2_DS, mov fs, dx + + ; ring-0 - What works above doesn't work with ss. + mov dx, MY_R3_DS | 0 + BS2_TRAP_INSTR X86_XCPT_GP, MY_R3_DS, mov ss, dx + mov dx, MY_R3_DS | 1 + BS2_TRAP_INSTR X86_XCPT_GP, MY_R3_DS, mov ss, dx + mov dx, MY_R3_DS | 2 + BS2_TRAP_INSTR X86_XCPT_GP, MY_R3_DS, mov ss, dx + + call TMPL_NM_CMN(Bs2ToRing0) + + + ; + ; One more odd thing, NULL selectors and RPL. + ; + pushf + cli + +%assign uCurRing 0 +%rep 4 + ; Null sectors. + call TMPL_NM_CMN(Bs2ToRing %+ uCurRing) + mov si, ss + + mov dx, 0 + mov fs, dx + ASSERT_CUR_SREG_VALUE fs, 0 + %if MY_IS_64BIT == 0 || uCurRing != 0 + %ifdef TMPL_64BIT ; AMD is doing something inconsistent. + %if uCurRing != 3 + test byte [g_fCpuAmd], 1 + jz .null_0_not_amd_ %+ uCurRing + mov ss, dx + ASSERT_CUR_SREG_VALUE ss, 0 + jmp .null_0_next_ %+ uCurRing +.null_0_not_amd_ %+ uCurRing: + %endif + %endif + BS2_TRAP_INSTR X86_XCPT_GP, 0, mov ss, dx +.null_0_next_ %+ uCurRing: + %else + mov ss, dx + ASSERT_CUR_SREG_VALUE ss, 0 + %endif + mov ss, si + + mov dx, 1 + mov fs, dx + ASSERT_CUR_SREG_VALUE fs, 1 + %if MY_IS_64BIT == 0 || uCurRing != 1 + %ifdef TMPL_64BIT ; AMD is doing something inconsistent. + %if uCurRing != 3 + test byte [g_fCpuAmd], 1 + jz .null_1_not_amd_ %+ uCurRing + mov ss, dx + ASSERT_CUR_SREG_VALUE ss, 1 + jmp .null_1_next_ %+ uCurRing +.null_1_not_amd_ %+ uCurRing: + %endif + %endif + BS2_TRAP_INSTR X86_XCPT_GP, 0, mov ss, dx +.null_1_next_ %+ uCurRing: + %else + mov ss, dx + ASSERT_CUR_SREG_VALUE ss, 1 + %endif + mov ss, si + + mov dx, 2 + mov fs, dx + ASSERT_CUR_SREG_VALUE fs, 2 + %if MY_IS_64BIT == 0 || uCurRing != 2 + %ifdef TMPL_64BIT ; AMD is doing something inconsistent. + %if uCurRing != 3 + test byte [g_fCpuAmd], 1 + jz .null_2_not_amd_ %+ uCurRing + mov ss, dx + ASSERT_CUR_SREG_VALUE ss, 2 + jmp .null_2_next_ %+ uCurRing +.null_2_not_amd_ %+ uCurRing: + %endif + %endif + BS2_TRAP_INSTR X86_XCPT_GP, 0, mov ss, dx +.null_2_next_ %+ uCurRing: + %else + mov ss, dx + ASSERT_CUR_SREG_VALUE ss, 2 + %endif + mov ss, si + + mov dx, 3 + mov fs, dx + ASSERT_CUR_SREG_VALUE fs, 3 + %ifdef TMPL_64BIT ; AMD is doing something inconsistent. + %if uCurRing != 3 + test byte [g_fCpuAmd], 1 + jz .null_3_not_amd_ %+ uCurRing + mov ss, dx + ASSERT_CUR_SREG_VALUE ss, 3 + jmp .null_3_next_ %+ uCurRing +.null_3_not_amd_ %+ uCurRing: + %endif + %endif + BS2_TRAP_INSTR X86_XCPT_GP, 0, mov ss, dx +.null_3_next_ %+ uCurRing: + mov ss, si + + %assign uCurRing uCurRing + 1 +%endrep + call TMPL_NM_CMN(Bs2ToRing0) + + ; Restore the selectors. + mov dx, MY_R0_DS + mov ds, dx + mov es, dx + mov fs, dx + mov gs, dx + popf + + + ; + ; Restore the descriptor and make sure it works. + ; + mov xSP, xDI ; restore the stack pointer. + BS2_TRAP_INSTR X86_XCPT_BP, 0, int3 + + ; + ; Done. + ; + call TMPL_NM_CMN(TestSubDone) + + pop xSI + pop xDI + pop xDX + pop xCX + pop xBX + pop sAX + leave + ret + +.s_szSubTestName: + db TMPL_MODE_STR, ', Conforming CS, ++', 0 +ENDPROC TMPL_NM(TestConforming) + + + +;; +; Returning from interrupt/trap/whatever handlers. +; +; @uses No registers, but BS2_SEL_SPARE0 is trashed. +; +BEGINPROC TMPL_NM(TestReturn) + push xBP + mov xBP, xSP + push sAX + push xBX + push xCX + push xDX + push xDI + push xSI + sub xSP, 80h ; iret stack frame space. + mov xSI, xSP ; Save the stack register. + + mov xAX, .s_szSubTestName + call TMPL_NM_CMN(TestSub) + +%ifdef TMPL_64BIT + pushfq + pop rdi ; rdi contains good flags register value. + + ; + ; 64-bit mode: IRETQ unconditional pop of SS:RSP. + ; + mov qword [rsp + 20h], MY_R0_SS + mov [rsp + 18h], rsp + mov [rsp + 10h], rdi + mov qword [rsp + 08h], MY_R0_CS + lea rax, [.resume1 wrt rip] + mov [rsp + 00h], rax + iretq + +.resume1: + pushfq + pop rbx + ASSERT_SIMPLE rsp, rsi, je, "Wrong RSP after IRETQ." + mov rsp, rsi + ASSERT_SIMPLE rbx, rdi, je, "Wrong flags after IRETQ." + mov ax, ss + ASSERT_SIMPLE ax, MY_R0_SS, je, "Wrong SS after IRETQ." + mov ax, cs + ASSERT_SIMPLE ax, MY_R0_CS, je, "Wrong CS after IRETQ." + + ; 64-bit mode: The NT flag causes #GP(0) + mov qword [rsp + 20h], MY_R0_SS + lea rax, [rsp - 100h] + mov [rsp + 18h], rax + mov [rsp + 10h], rdi + mov qword [rsp + 08h], MY_R0_CS + lea rax, [.resume2 wrt rip] + mov [rsp + 00h], rax + push rdi + or dword [rsp], X86_EFL_NT + popfq + BS2_TRAP_BRANCH_INSTR X86_XCPT_GP, 0, .resume2, iretq + pushfq + pop rbx + push rdi + popfq + ASSERT_SIMPLE rsp, rsi, je, "Wrong RSP after IRETQ." + mov rsp, rsi + mov rax, rdi + or rax, X86_EFL_NT + ASSERT_SIMPLE rbx, rax, je, "Wrong flags after IRETQ GP(0)-NT." + mov ax, ss + ASSERT_SIMPLE ax, MY_R0_SS, je, "Wrong SS after IRETQ." + mov ax, cs + ASSERT_SIMPLE ax, MY_R0_CS, je, "Wrong CS after IRETQ." + + ; 64-bit mode: The VM flag is disregarded. + mov qword [rsp + 20h], MY_R0_SS + lea rax, [rsp - 88h] + mov [rsp + 18h], rax + mov [rsp + 10h], rdi + or dword [rsp + 10h], X86_EFL_VM + mov qword [rsp + 08h], MY_R0_CS + lea rax, [.resume3 wrt rip] + mov [rsp + 00h], rax + iretq +.resume3: + pushfq + pop rbx + add rsp, 88h + ASSERT_SIMPLE rsp, rsi, je, "Wrong RSP after IRETQ." + mov rsp, rsi + mov rax, rdi + ASSERT_SIMPLE rbx, rax, je, "Wrong flags after IRETQ GP(0)-NT." + mov ax, ss + ASSERT_SIMPLE ax, MY_R0_SS, je, "Wrong SS after IRETQ." + mov ax, cs + ASSERT_SIMPLE ax, MY_R0_CS, je, "Wrong CS after IRETQ." + + ; + ; 64-bit mode: IRETD unconditionally pops SS:ESP as well. + ; + mov dword [rsp + 10h], MY_R0_SS + lea eax, [esp - 18h] + mov [rsp + 0ch], eax + mov [rsp + 08h], edi + mov dword [rsp + 04h], MY_R0_CS + lea eax, [.resume20 wrt rip] + mov [rsp + 00h], eax + iretd +.resume20: + pushfq + pop rbx + add rsp, 18h + ASSERT_SIMPLE rsp, rsi, je, "Wrong RSP after IRETD." + mov rsp, rsi + ASSERT_SIMPLE rbx, rdi, je, "Wrong flags after IRETD." + mov ax, ss + ASSERT_SIMPLE ax, MY_R0_SS, je, "Wrong SS after IRETD." + mov ax, cs + ASSERT_SIMPLE ax, MY_R0_CS, je, "Wrong CS after IRETD." + + ; + ; 64-bit mode: IRET unconditionally pops SS:SP as well. + ; + mov word [rsp + 08h], MY_R0_SS + lea eax, [esp - 1ah] + mov [rsp + 06h], ax + mov [rsp + 04h], di + mov word [rsp + 02h], MY_R0_CS + mov word [rsp + 00h], .resume30 + o16 iret +BEGINCODELOW +.resume30: + jmp .high1 +BEGINCODEHIGH +.high1: + pushfq + pop rbx + add rsp, 1ah + ASSERT_SIMPLE rsp, rsi, je, "Wrong RSP after IRET." + mov rsp, rsi + ASSERT_SIMPLE rbx, rdi, je, "Wrong flags after IRET." + mov ax, ss + ASSERT_SIMPLE ax, MY_R0_SS, je, "Wrong SS after IRET." + mov ax, cs + ASSERT_SIMPLE ax, MY_R0_CS, je, "Wrong CS after IRET." + + +%elifdef TMPL_32BIT + ; later... +%endif + + ; + ; Returning to 16-bit code, what happens to upper ESP bits? + ; + cli + mov xBX, xSP ; save the current stack address + + mov sAX, BS2_SEL_R3_SS16 | 3 + push sAX ; Return SS + movzx edi, bx + or edi, 0xdead0000 + push sDI ; Return sSP +%ifdef TMPL_64BIT + pushfq +%else + pushfd +%endif + mov sAX, BS2_SEL_R3_CS16 | 3 + push sAX ; Return CS + lea sAX, [.resume100 xWrtRIP] + push sAX ; Return sIP +%ifdef TMPL_64BIT + iretq +%else + iretd +%endif + +BEGINCODELOW +BITS 16 +.resume100: + xchg ebx, esp + call Bs2ToRing0_p16 + call TMPL_NM(Bs2Thunk_p16) +BITS TMPL_BITS + jmp .high100 +BEGINCODEHIGH +.high100: + and edi, 0ffffh + ASSERT_SIMPLE ebx, edi, je, "IRET to 16-bit didn't restore ESP as expected [#1]." + +%ifndef TMPL_16BIT + ; + ; Take two on 16-bit return, does the high word of ESP leak? + ; + cli + mov sBX, sSP ; save the current stack address + mov xSP, BS2_MUCK_ABOUT_BASE + 1000h + + mov sAX, BS2_SEL_R3_SS16 | 3 + push sAX ; Return SS + mov sDI, sBX + push sDI ; Return sSP + %ifdef TMPL_64BIT + pushfq + %else + pushfd + %endif + mov sAX, BS2_SEL_R3_CS16 | 3 + push sAX ; Return CS + lea sAX, [.resume101 xWrtRIP] + push sAX ; Return sIP + %ifdef TMPL_64BIT + iretq + %else + iretd + %endif + +BEGINCODELOW +BITS 16 +.resume101: + xchg ebx, esp + call Bs2ToRing0_p16 + call TMPL_NM(Bs2Thunk_p16) +BITS TMPL_BITS + jmp .high101 +BEGINCODEHIGH +.high101: + or edi, (BS2_MUCK_ABOUT_BASE + 1000h) & 0ffff0000h + ASSERT_SIMPLE ebx, edi, je, "IRET to 16-bit didn't restore ESP as expected [#2]." +%endif ; Not 16-bit. + + ; + ; Done. + ; + call TMPL_NM_CMN(TestSubDone) + + mov xSP, xSI + add xSP, 80h + pop xSI + pop xDI + pop xDX + pop xCX + pop xBX + pop sAX + leave + ret + +.s_szSubTestName: + db TMPL_MODE_STR, ', IRET', 0 +ENDPROC TMPL_NM(TestReturn) + +;; +; Do the tests for this mode. +; +; @uses nothing +; +BEGINCODELOW +BITS 16 +BEGINPROC TMPL_NM(DoTestsForMode_rm) + push bp + mov bp, sp + push ax + + ; + ; Check if the mode and NX is supported, do the switch. + ; + call TMPL_NM(Bs2IsModeSupported_rm) + jz .done + call TMPL_NM(Bs2EnterMode_rm) +BITS TMPL_BITS + + ; + ; Test exception handler basics using INT3 and #BP. + ; + + call TMPL_NM(TestGateType) + call TMPL_NM(TestCodeSelector) + call TMPL_NM(TestCheckOrderCsTypeVsIdteType) + call TMPL_NM(TestStack) + call TMPL_NM(TestConforming) + call TMPL_NM(TestReturn) + + ; + ; Back to real mode. + ; + call TMPL_NM(Bs2ExitMode) +BITS 16 + call Bs2DisableNX_r86 + +.done: + pop ax + leave + ret +ENDPROC TMPL_NM(DoTestsForMode_rm) +TMPL_BEGINCODE +BITS TMPL_BITS + +%include "bootsector2-template-footer.mac" + diff --git a/src/VBox/ValidationKit/bootsectors/bootsector2-cpu-xcpt-1.asm b/src/VBox/ValidationKit/bootsectors/bootsector2-cpu-xcpt-1.asm new file mode 100644 index 00000000..ecb3269e --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bootsector2-cpu-xcpt-1.asm @@ -0,0 +1,128 @@ +; $Id: bootsector2-cpu-xcpt-1.asm $ +;; @file +; Bootsector test for basic exception stuff. +; +; Recommended (but not necessary): +; VBoxManage setextradata bs-cpu-xcpt-1 VBoxInternal/Devices/VMMDev/0/Config/TestingEnabled 1 +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + + +;******************************************************************************* +;* Header Files * +;******************************************************************************* +%include "iprt/asmdefs.mac" +%include "iprt/x86.mac" +%include "VBox/VMMDevTesting.mac" + + +;******************************************************************************* +;* Defined Constants And Macros * +;******************************************************************************* +;; Base address at which we can start testing page tables and page directories. +%define TST_SCRATCH_PD_BASE BS2_MUCK_ABOUT_BASE +;; Base address at which we can start testing the page pointer table. +%define TST_SCRATCH_PDPT_BASE (1 << X86_PDPT_SHIFT) +;; Base address at which we can start testing the page map level 4. +%define TST_SCRATCH_PML4_BASE ((1 << X86_PML4_SHIFT) + TST_SCRATCH_PD_BASE) + + +; +; Include and execute the init code. +; + %define BS2_INIT_RM + %define BS2_WITH_TRAPS + %define BS2_INC_RM + %define BS2_INC_PE16 + %define BS2_INC_PE32 + %define BS2_INC_PP16 + %define BS2_INC_PP32 + %define BS2_INC_PAE16 + %define BS2_INC_PAE32 + %define BS2_INC_LM16 + %define BS2_INC_LM32 + %define BS2_INC_LM64 + %define BS2_WITH_TRAPRECS + %include "bootsector2-common-init-code.mac" + + +; +; The main() function. +; +BEGINPROC main + BITS 16 + ; + ; Test prologue. + ; + mov ax, .s_szTstName + call TestInit_r86 + call Bs2EnableA20_r86 + + + ; + ; Execute the tests + ; +%if 1 + call NAME(DoTestsForMode_rm_pe32) +%endif +%if 1 + call NAME(DoTestsForMode_rm_pp32) +%endif +%if 1 + call NAME(DoTestsForMode_rm_pae32) +%endif +%if 1 + call NAME(DoTestsForMode_rm_lm64) +%endif + + ; + ; We're done. + ; + call TestTerm_r86 + ret + +.s_szTstName: + db 'tstCpuXcpt1', 0 +ENDPROC main + + +; +; Instantiate the template code. +; +%include "bootsector2-template-footer.mac" ; reset the initial environemnt. + +%define TMPL_PE32 +%include "bootsector2-cpu-xcpt-1-template.mac" +%define TMPL_PP32 +%include "bootsector2-cpu-xcpt-1-template.mac" +%define TMPL_PAE32 +%include "bootsector2-cpu-xcpt-1-template.mac" +%define TMPL_LM64 +%include "bootsector2-cpu-xcpt-1-template.mac" + + +; +; End sections and image. +; +%include "bootsector2-common-end.mac" + diff --git a/src/VBox/ValidationKit/bootsectors/bootsector2-cpu-xcpt-2-template.mac b/src/VBox/ValidationKit/bootsectors/bootsector2-cpu-xcpt-2-template.mac new file mode 100644 index 00000000..46b218d0 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bootsector2-cpu-xcpt-2-template.mac @@ -0,0 +1,501 @@ +; $Id: bootsector2-cpu-xcpt-2-template.mac $ +;; @file +; Bootsector test for debug exceptions - multi mode template. +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + + +%include "bootsector2-template-header.mac" + + +;******************************************************************************* +;* Defined Constants And Macros * +;******************************************************************************* +;; +; Some 32/64 macros. +; +%if TMPL_BITS == 32 + %define bs2Idt_BP bs2Idt32bit_BP + %define MY_R0_CS BS2_SEL_CS32 + %define MY_R1_CS BS2_SEL_R1_CS32 + %define MY_R2_CS BS2_SEL_R2_CS32 + %define MY_R3_CS BS2_SEL_R3_CS32 + + %define MY_R0_DS BS2_SEL_DS32 + %define MY_R1_DS BS2_SEL_R1_DS32 + %define MY_R2_DS BS2_SEL_R2_DS32 + %define MY_R3_DS BS2_SEL_R3_DS32 + + %define MY_R0_SS BS2_SEL_SS32 + %define MY_R1_SS BS2_SEL_R1_SS32 + %define MY_R2_SS BS2_SEL_R2_SS32 + %define MY_R3_SS BS2_SEL_R3_SS32 + +%else + %define bs2Idt_BP bs2Idt64bit_BP + %define MY_R0_CS BS2_SEL_CS64 + %define MY_R1_CS BS2_SEL_R1_CS64 + %define MY_R2_CS BS2_SEL_R2_CS64 + %define MY_R3_CS BS2_SEL_R3_CS64 + + %define MY_R0_DS BS2_SEL_DS64 + %define MY_R1_DS BS2_SEL_R1_DS64 + %define MY_R2_DS BS2_SEL_R2_DS64 + %define MY_R3_DS BS2_SEL_R3_DS64 + + %define MY_R0_SS BS2_SEL_SS64 + %define MY_R1_SS BS2_SEL_R1_SS64 + %define MY_R2_SS BS2_SEL_R2_SS64 + %define MY_R3_SS BS2_SEL_R3_SS64 +%endif + +%ifdef TMPL_64BIT + %assign MY_IS_64BIT 1 +%else + %assign MY_IS_64BIT 0 +%endif + +;; Uncomment this to do lots more iterations (takes time!). +%define QUICK_TEST + + +;******************************************************************************* +;* Global Variables * +;******************************************************************************* +%ifndef CPU_XCPT_1_GLOBALS + %define CPU_XCPT_1_GLOBALS + +;; +; Asserts a test. +; +; @param %1 First cmp operand. +; @param %2 First cmp operand. +; @param %3 Which kind of conditional jump to make +; @param %4 The message to print (format string, no arguments please). +; + %macro ASSERT_SIMPLE 4 + cmp %1, %2 + %3 %%.ok + cli ; raw-mode hack + push dword __LINE__ + %ifdef TMPL_16BIT + push ds + %endif + push %%.s_szMsg + call TMPL_NM_CMN(TestFailedF) + add xSP, sCB*2 + ;hlt + sti + jmp %%.ok + %%.s_szMsg: db %4, " (0x%RX32)", 0 + %%.ok: + %endmacro + +%endif + + +;; +; Disable the breakpoints as well as check RA1 bits. +; +; @changes DRx +; +BEGINPROC TMPL_NM(DisableBps) + push sAX + push sBX + sPUSHF + + xor eax, eax + mov dr7, sAX + mov dr6, sAX + mov dr0, sAX + mov dr1, sAX + mov dr2, sAX + mov dr3, sAX + + mov sAX, dr6 + mov ebx, X86_DR6_RA1_MASK + ASSERT_SIMPLE sAX, xBX, je, "Wrong DR6 value (RA1)." + mov sAX, dr7 + mov ebx, X86_DR7_RA1_MASK + ASSERT_SIMPLE sAX, sBX, je, "Wrong DR7 value (RA1)." + + sPOPF + pop sBX + pop sAX + ret +ENDPROC TMPL_NM(DisableBps) + + +;; +; Checks different gate types. +; +BEGINPROC TMPL_NM(TestStepping) + push xBP + mov xBP, xSP + push sAX + push xBX + push xCX + push xDX + push xDI + push xSI + + mov xAX, .s_szSubTestName + call TMPL_NM_CMN(TestSub) + + + ; + ; Step one instruction a lot of times to catch DR6 mismanagement. + ; +%ifdef QUICK_TEST + mov ecx, 0x1000 +%else + mov ecx, 0x80000 +%endif +.the_1st_loop: + + mov eax, X86_DR6_INIT_VAL + mov dr6, sAX + mov eax, 0x12345678 + mov ebx, 0xaabbccdd + sPUSHF + or word [xSP], X86_EFL_TF + sPOPF + xchg ebx, eax + BS2_TRAP_INSTR X86_XCPT_DB, 0, nop + ASSERT_SIMPLE eax, 0xaabbccdd, je, "xchg wasn't executed (eax)." + ASSERT_SIMPLE ebx, 0x12345678, je, "xchg wasn't executed (ebx)." + mov sAX, dr6 + ASSERT_SIMPLE eax, (X86_DR6_INIT_VAL | X86_DR6_BS), je, "Wrong DR6 value." + + dec ecx + jnz .the_1st_loop + + ; + ; Check that certain bits in DR6 is preserved and others not. + ; +%ifdef QUICK_TEST + mov ecx, 0x200 +%else + mov ecx, 0x20000 +%endif +.the_2nd_loop: + mov eax, X86_DR6_INIT_VAL | X86_DR6_B0 | X86_DR6_B1 | X86_DR6_B2 | X86_DR6_B3 | X86_DR6_BT | X86_DR6_BD + mov dr6, sAX + mov eax, 0x12345678 + mov ebx, 0xaabbccdd + sPUSHF + or word [xSP], X86_EFL_TF + sPOPF + xchg ebx, eax + BS2_TRAP_INSTR X86_XCPT_DB, 0, nop + ASSERT_SIMPLE eax, 0xaabbccdd, je, "xchg wasn't executed (eax)." + ASSERT_SIMPLE ebx, 0x12345678, je, "xchg wasn't executed (ebx)." + mov sAX, dr6 + ASSERT_SIMPLE eax, (X86_DR6_BS | X86_DR6_INIT_VAL | X86_DR6_BT | X86_DR6_BD), je, "Wrong DR6 value." + + dec ecx + jnz .the_2nd_loop + + ; + ; Done. + ; + cli ; raw-mode hack + call TMPL_NM_CMN(TestSubDone) + sti + + pop xSI + pop xDI + pop xDX + pop xCX + pop xBX + pop sAX + leave + ret + +.s_szSubTestName: + db TMPL_MODE_STR, ', EFLAGS.TF stepping', 0 +ENDPROC TMPL_NM(TestGateType) + + +;; +; Check execution breakpoint. +; +BEGINPROC TMPL_NM(TestBpExec) + push xBP + mov xBP, xSP + push sAX + push xBX + push xCX + push xDX + push xDI + push xSI + + mov xAX, .s_szSubTestName + call TMPL_NM_CMN(TestSub) + + + ; + ; Arm all 4 breakpoints and check DR6 management. + ; +%ifdef QUICK_TEST + mov ecx, 0x1000 +%else + mov ecx, 0x80000 +%endif + lea sAX, [.bp_dr0 xWrtRIP] + mov dr0, sAX + lea sAX, [.bp_dr1 xWrtRIP] + mov dr1, sAX + lea sAX, [.bp_dr2 xWrtRIP] + mov dr2, sAX + lea sAX, [.bp_dr3 xWrtRIP] + mov dr3, sAX + mov eax, X86_DR7_RA1_MASK | X86_DR7_G0 | X86_DR7_G1 | X86_DR7_G2 | X86_DR7_G3 | X86_DR7_GE + mov dr7, sAX + +.the_loop: + mov eax, X86_DR6_INIT_VAL | X86_DR6_BS | X86_DR6_BT | X86_DR6_BD + mov dr6, sAX + + mov eax, 0x12345678 + mov ebx, 0xaabbccdd +.bp_dr0: + BS2_TRAP_INSTR X86_XCPT_DB, 0, xchg ebx, eax + ASSERT_SIMPLE eax, 0x12345678, je, "xchg was executed (eax)." + ASSERT_SIMPLE ebx, 0xaabbccdd, je, "xchg was executed (ebx)." + mov sAX, dr6 + ASSERT_SIMPLE eax, (X86_DR6_INIT_VAL | X86_DR6_BS | X86_DR6_BT | X86_DR6_BD | X86_DR6_B0), je, "Wrong DR6 value (dr0)." + + mov eax, 0x12345678 + mov ebx, 0xaabbccdd +.bp_dr1: + BS2_TRAP_INSTR X86_XCPT_DB, 0, xchg ebx, eax + ASSERT_SIMPLE eax, 0x12345678, je, "xchg was executed (eax)." + ASSERT_SIMPLE ebx, 0xaabbccdd, je, "xchg was executed (ebx)." + mov sAX, dr6 + ASSERT_SIMPLE eax, (X86_DR6_INIT_VAL | X86_DR6_BS | X86_DR6_BT | X86_DR6_BD | X86_DR6_B1), je, "Wrong DR6 value (dr1)." + + mov eax, 0x12345678 + mov ebx, 0xaabbccdd +.bp_dr2: + BS2_TRAP_INSTR X86_XCPT_DB, 0, xchg ebx, eax + ASSERT_SIMPLE eax, 0x12345678, je, "xchg was executed (eax)." + ASSERT_SIMPLE ebx, 0xaabbccdd, je, "xchg was executed (ebx)." + mov sAX, dr6 + ASSERT_SIMPLE eax, (X86_DR6_INIT_VAL | X86_DR6_BS | X86_DR6_BT | X86_DR6_BD | X86_DR6_B2), je, "Wrong DR6 value (dr2)." + + mov eax, 0x12345678 + mov ebx, 0xaabbccdd +.bp_dr3: + BS2_TRAP_INSTR X86_XCPT_DB, 0, xchg ebx, eax + ASSERT_SIMPLE eax, 0x12345678, je, "xchg was executed (eax)." + ASSERT_SIMPLE ebx, 0xaabbccdd, je, "xchg was executed (ebx)." + mov sAX, dr6 + ASSERT_SIMPLE eax, (X86_DR6_INIT_VAL | X86_DR6_BS | X86_DR6_BT | X86_DR6_BD | X86_DR6_B3), je, "Wrong DR6 value (dr3)." + + dec ecx + jnz .the_loop + + ; + ; Touch the code, making sure the BPs don't trigger on data access. + ; + mov al, [.bp_dr0 xWrtRIP] + mov [.bp_dr0 xWrtRIP], al + mov al, [.bp_dr1 xWrtRIP] + mov [.bp_dr1 xWrtRIP], al + mov al, [.bp_dr2 xWrtRIP] + mov [.bp_dr2 xWrtRIP], al + mov al, [.bp_dr3 xWrtRIP] + mov [.bp_dr3 xWrtRIP], al + + ; + ; Done. + ; + call TMPL_NM(DisableBps) + cli ; raw-mode hack + call TMPL_NM_CMN(TestSubDone) + sti + + pop xSI + pop xDI + pop xDX + pop xCX + pop xBX + pop sAX + leave + ret + +.s_szSubTestName: + db TMPL_MODE_STR, ', Exec BP', 0 +ENDPROC TMPL_NM(TestBpExec) + + +;; +; Check I/O breakpoints. +; +BEGINPROC TMPL_NM(TestBpIo) + push xBP + mov xBP, xSP + push sAX + push xBX + push xCX + push xDX + push xDI + push xSI + + mov xAX, .s_szSubTestName + call TMPL_NM_CMN(TestSub) + + + ; + ; Arm all 4 breakpoints and check range handling and such. + ; + mov sAX, cr4 + or sAX, X86_CR4_DE + mov cr4, sAX + +%ifdef QUICK_TEST + mov ecx, 1000 +%else + mov ecx, 4096 +%endif + mov sAX, 84h + mov dr0, sAX + mov sAX, 85h + mov dr1, sAX + mov sAX, 86h + mov dr2, sAX + mov sAX, 8ch + mov dr3, sAX + mov eax, X86_DR7_RA1_MASK | X86_DR7_LE | X86_DR7_GE \ + | X86_DR7_L0 | X86_DR7_G0 | X86_DR7_RW(0, X86_DR7_RW_IO) | X86_DR7_LEN(0, X86_DR7_LEN_BYTE) \ + | X86_DR7_L1 | X86_DR7_G1 | X86_DR7_RW(1, X86_DR7_RW_IO) | X86_DR7_LEN(1, X86_DR7_LEN_WORD) \ + | X86_DR7_L2 | X86_DR7_G2 | X86_DR7_RW(2, X86_DR7_RW_IO) | X86_DR7_LEN(2, X86_DR7_LEN_DWORD) \ + | X86_DR7_L3 | X86_DR7_G3 | X86_DR7_RW(3, X86_DR7_RW_IO) | X86_DR7_LEN(3, X86_DR7_LEN_DWORD) + mov dr7, sAX + +.the_loop: + mov eax, X86_DR6_INIT_VAL + mov dr6, sAX + + mov eax, 0x12345678 + in eax, 84h + BS2_TRAP_INSTR X86_XCPT_DB, 0, nop + ASSERT_SIMPLE eax, 0x12345678, jne, "in was not executed." + mov sAX, dr6 + ASSERT_SIMPLE eax, (X86_DR6_INIT_VAL | X86_DR6_B0), je, "Wrong DR6 value (dr0)." + + mov ebx, 0x12345678 + in eax, 85h + BS2_TRAP_INSTR X86_XCPT_DB, 0, nop + ASSERT_SIMPLE eax, 0x12345678, jne, "in was not executed." + mov sAX, dr6 + ASSERT_SIMPLE eax, (X86_DR6_INIT_VAL | X86_DR6_B1), je, "Wrong DR6 value (dr1)." + + mov eax, 0x12345678 + in eax, 86h + BS2_TRAP_INSTR X86_XCPT_DB, 0, nop + ASSERT_SIMPLE eax, 0x12345678, jne, "in was not executed." + mov sAX, dr6 + ASSERT_SIMPLE eax, (X86_DR6_INIT_VAL | X86_DR6_B2), je, "Wrong DR6 value (dr2)." + + mov eax, 0x12345678 + in eax, 8ch + BS2_TRAP_INSTR X86_XCPT_DB, 0, nop + ASSERT_SIMPLE eax, 0x12345678, jne, "in was not executed." + mov sAX, dr6 + ASSERT_SIMPLE eax, (X86_DR6_INIT_VAL | X86_DR6_B3), je, "Wrong DR6 value (dr3)." + + dec ecx + jnz .the_loop + + ; + ; Done. + ; + call TMPL_NM(DisableBps) + cli ; raw-mode hack + call TMPL_NM_CMN(TestSubDone) + sti + + pop xSI + pop xDI + pop xDX + pop xCX + pop xBX + pop sAX + leave + ret + +.s_szSubTestName: + db TMPL_MODE_STR, ', I/O BP', 0 +ENDPROC TMPL_NM(TestBpIo) + + +;; +; Do the tests for this mode. +; +; @uses nothing +; +BEGINCODELOW +BITS 16 +BEGINPROC TMPL_NM(DoTestsForMode_rm) + push bp + mov bp, sp + push ax + + ; + ; Check if the mode and NX is supported, do the switch. + ; + call TMPL_NM(Bs2IsModeSupported_rm) + jz .done + call TMPL_NM(Bs2EnterMode_rm) +BITS TMPL_BITS + pushf + sti ; raw-mode hacks + + ; + ; Do the testing. + ; + + call TMPL_NM(TestStepping) + call TMPL_NM(TestBpExec) + call TMPL_NM(TestBpIo) + + ; + ; Back to real mode. + ; + popf + call TMPL_NM(Bs2ExitMode) +BITS 16 + call Bs2DisableNX_r86 + +.done: + pop ax + leave + ret +ENDPROC TMPL_NM(DoTestsForMode_rm) +TMPL_BEGINCODE +BITS TMPL_BITS + +%include "bootsector2-template-footer.mac" + diff --git a/src/VBox/ValidationKit/bootsectors/bootsector2-cpu-xcpt-2.asm b/src/VBox/ValidationKit/bootsectors/bootsector2-cpu-xcpt-2.asm new file mode 100644 index 00000000..22b0b62a --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bootsector2-cpu-xcpt-2.asm @@ -0,0 +1,119 @@ +; $Id: bootsector2-cpu-xcpt-2.asm $ +;; @file +; Bootsector test for debug exceptions. +; +; Recommended (but not necessary): +; VBoxManage setextradata bs-cpu-xcpt-2 VBoxInternal/Devices/VMMDev/0/Config/TestingEnabled 1 +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + + +;******************************************************************************* +;* Header Files * +;******************************************************************************* +%include "iprt/asmdefs.mac" +%include "iprt/x86.mac" +%include "VBox/VMMDevTesting.mac" + + +; +; Include and execute the init code. +; + %define BS2_INIT_RM + %define BS2_WITH_TRAPS + %define BS2_INC_RM + %define BS2_INC_PE16 + %define BS2_INC_PE32 + %define BS2_INC_PP16 + %define BS2_INC_PP32 + %define BS2_INC_PAE16 + %define BS2_INC_PAE32 + %define BS2_INC_LM16 + %define BS2_INC_LM32 + %define BS2_INC_LM64 + %define BS2_WITH_TRAPRECS + %define BS2_WITH_XCPT_DB_CLEARING_TF + %include "bootsector2-common-init-code.mac" + + +; +; The main() function. +; +BEGINPROC main + BITS 16 + ; + ; Test prologue. + ; + mov ax, .s_szTstName + call TestInit_r86 + call Bs2EnableA20_r86 + cli ; raw-mode hack + + + ; + ; Execute the tests + ; +%if 1 + call NAME(DoTestsForMode_rm_pe32) +%endif +%if 1 + call NAME(DoTestsForMode_rm_pp32) +%endif +%if 1 + call NAME(DoTestsForMode_rm_pae32) +%endif +%if 1 + call NAME(DoTestsForMode_rm_lm64) +%endif + + ; + ; We're done. + ; + call TestTerm_r86 + ret + +.s_szTstName: + db 'tstCpuXcpt2', 0 +ENDPROC main + + +; +; Instantiate the template code. +; +%include "bootsector2-template-footer.mac" ; reset the initial environemnt. + +%define TMPL_PE32 +%include "bootsector2-cpu-xcpt-2-template.mac" +%define TMPL_PP32 +%include "bootsector2-cpu-xcpt-2-template.mac" +%define TMPL_PAE32 +%include "bootsector2-cpu-xcpt-2-template.mac" +%define TMPL_LM64 +%include "bootsector2-cpu-xcpt-2-template.mac" + + +; +; End sections and image. +; +%include "bootsector2-common-end.mac" + diff --git a/src/VBox/ValidationKit/bootsectors/bootsector2-first.mac b/src/VBox/ValidationKit/bootsectors/bootsector2-first.mac new file mode 100644 index 00000000..4a850f07 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bootsector2-first.mac @@ -0,0 +1,74 @@ +; $Id: bootsector2-first.mac $ +;; @file +; bootsector2 first include file - works around YASM / kBuild issues. +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + +%ifndef ___bootsector2_first_mac +%define ___bootsector2_first_mac + +; +; Undefine thing that shouldn't be defined if we're targeting the +; binary format directly. These macros comes from DEFS in Config.kmk. +; +%ifdef ASM_FORMAT_BIN + %undef RT_ARCH_AMD64 + %undef RT_ARCH_X86 + + %undef RT_OS_DARWIN + %undef RT_OS_FREEBSD + %undef RT_OS_HAIKU + %undef RT_OS_LINUX + %undef RT_OS_NETBSD + %undef RT_OS_OPENBSD + %undef RT_OS_OS2 + %undef RT_OS_WINDOWS + + %undef __AMD64__ + %undef __x86_64__ + %undef __i386__ + %undef __I386__ + %undef __x86__ + %undef __X86__ + + %undef __WIN__ + %undef __WIN32__ + %undef __WIN64__ +%endif + + +; +; Include standard includes. +; +%include "iprt/asmdefs.mac" +%include "iprt/x86.mac" +%include "VBox/VMMDevTesting.mac" + + +; +; Open the code segment. +; +BEGINCODE + +%endif + diff --git a/src/VBox/ValidationKit/bootsectors/bootsector2-structures.mac b/src/VBox/ValidationKit/bootsectors/bootsector2-structures.mac new file mode 100644 index 00000000..2d8362c3 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bootsector2-structures.mac @@ -0,0 +1,91 @@ +; $Id: bootsector2-structures.mac $ +;; @file +; Common structures. +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + +%ifndef ___bootsector2_structures_mac___ +%define ___bootsector2_structures_mac___ + + +;; +; Registers. Used by traps and such. +; +struc BS2REGS + .rax resq 1 + .rbx resq 1 + .rcx resq 1 + .rdx resq 1 + .rdi resq 1 + .rsi resq 1 + .rbp resq 1 + .rsp resq 1 + .rip resq 1 + .r8 resq 1 + .r9 resq 1 + .r10 resq 1 + .r11 resq 1 + .r12 resq 1 + .r13 resq 1 + .r14 resq 1 + .r15 resq 1 + .rflags resq 1 + .cs resw 1 + .ds resw 1 + .es resw 1 + .fs resw 1 + .gs resw 1 + .ss resw 1 + .cBits resb 1 + .pad resb 3 + .cr0 resq 1 + .cr2 resq 1 + .cr3 resq 1 + .cr4 resq 1 + .cr8 resq 1 + ;; @todo Add floating point registers when they are active. +endstruc + + + +;; +; Trap record. +; +struc BS2TRAPREC + ;; The trap location relative to the base address given at + ; registration time. + .offWhere resd 1 + ;; What to add to .offWhere to calculate the resume address. + .offResumeAddend resb 1 + ;; The trap number. + .u8TrapNo resb 1 + ;; The error code if the trap takes one. + .u16ErrCd resw 1 +endstruc + +;; The size shift. +%define BS2TRAPREC_SIZE_SHIFT 3 + + +%endif + diff --git a/src/VBox/ValidationKit/bootsectors/bootsector2-template-footer.mac b/src/VBox/ValidationKit/bootsectors/bootsector2-template-footer.mac new file mode 100644 index 00000000..542cfcbb --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bootsector2-template-footer.mac @@ -0,0 +1,106 @@ +; $Id: bootsector2-template-footer.mac $ +;; @file +; bootsector2 footer for multi-mode code templates. +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + + +; +; Undefine macros defined by the header. +; +; Note! The following is useful for verifying that all macros are included here: +; +; for i in `grep "%define" bootsector2-template-header.mac \ +; | sed -e 's/^ *%define *//' -e 's/^\([^() ]*\).*$/\1/' \ +; | sort -u` +; do +; if ! grep -wF "%undef $i" bootsector2-template-footer.mac; then +; echo $i +; fi +; done +; +%undef TMPL_RM +%undef TMPL_PE16 +%undef TMPL_PE32 +%undef TMPL_PEV86 +%undef TMPL_PP16 +%undef TMPL_PP32 +%undef TMPL_PPV86 +%undef TMPL_PAE16 +%undef TMPL_PAE32 +%undef TMPL_PAEV86 +%undef TMPL_LM16 +%undef TMPL_LM32 +%undef TMPL_LM64 + +%undef TMPL_CMN_PE +%undef TMPL_CMN_PP +%undef TMPL_CMN_PAE +%undef TMPL_CMN_LM +%undef TMPL_CMN_V86 + +%undef TMPL_CMN_P16 +%undef TMPL_CMN_P32 +%undef TMPL_CMN_P64 +%undef TMPL_CMN_R16 +%undef TMPL_CMN_R86 + +%undef TMPL_NM +%undef TMPL_NM_CMN +%undef TMPL_MODE +%undef TMPL_MODE_STR +%undef TMPL_16BIT +%undef TMPL_32BIT +%undef TMPL_64BIT +%undef TMPL_BITS +%undef TMPL_PTR_DEF +%undef TMPL_HAVE_BIOS +%undef TMPL_BEGINCODE + +%undef xCB +%undef xDEF +%undef xRES +%undef xPRE +%undef xSP +%undef xBP +%undef xAX +%undef xBX +%undef xCX +%undef xDX +%undef xDI +%undef xSI +%undef xWrtRIP + +%undef sCB +%undef sDEF +%undef sRES +%undef sPRE +%undef sSP +%undef sBP +%undef sAX +%undef sBX +%undef sCX +%undef sDX +%undef sDI +%undef sSI + diff --git a/src/VBox/ValidationKit/bootsectors/bootsector2-template-header.mac b/src/VBox/ValidationKit/bootsectors/bootsector2-template-header.mac new file mode 100644 index 00000000..3ddab0f7 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bootsector2-template-header.mac @@ -0,0 +1,793 @@ +; $Id: bootsector2-template-header.mac $ +;; @file +; bootsector2 header for multi-mode code templates. +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + +; +; Check and expand the mode defines. +; One of the following must be defined: +; - TMPL_RM - real mode. +; - TMPL_PE16 - 16-bit protected mode, unpaged. +; - TMPL_PE32 - 32-bit protected mode, unpaged. +; - TMPL_PEV86 - virtual 8086 mode under protected mode, unpaged. +; - TMPL_PP16 - 16-bit protected mode, paged. +; - TMPL_PP32 - 32-bit protected mode, paged. +; - TMPL_PPV86 - virtual 8086 mode under protected mode, paged. +; - TMPL_PAE16 - 16-bit protected mode with PAE (paged). +; - TMPL_PAE32 - 16-bit protected mode with PAE (paged). +; - TMPL_PAEV86- virtual 8086 mode under protected mode with PAE (paged). +; - TMPL_LM16 - 16-bit long mode (paged). +; - TMPL_LM32 - 32-bit long mode (paged). +; - TMPL_LM64 - 64-bit long mode (paged). +; +; Derived indicators: +; - TMPL_CMN_PE = TMPL_PE16 | TMPL_PE32 | TMPL_PEV86 +; - TMPL_CMN_PP = TMPL_PP16 | TMPL_PP32 | TMPL_PPV86 +; - TMPL_CMN_PAE = TMPL_PAE16 | TMPL_PAE32 | TMPL_PAEV86 +; - TMPL_CMN_LM = TMPL_LM16 | TMPL_LM32 | TMPL_LM64 +; - TMPL_CMN_V86 = TMPL_PEV86 | TMPL_PPV86 | TMPL_PAEV86 +; - TMPL_CMN_R86 = TMPL_CMN_V86 | TMPL_RM +; +%ifdef TMPL_RM + %ifdef TMPL_PE16 + %error "Both 'TMPL_RM' and 'TMPL_PE16' are defined." + %endif + %ifdef TMPL_PE32 + %error "Both 'TMPL_RM' and 'TMPL_PE32' are defined." + %endif + %ifdef TMPL_PEV86 + %error "Both 'TMPL_RM' and 'TMPL_PEV86' are defined." + %endif + %ifdef TMPL_PP16 + %error "Both 'TMPL_RM' and 'TMPL_PP16' are defined." + %endif + %ifdef TMPL_PP32 + %error "Both 'TMPL_RM' and 'TMPL_PP32' are defined." + %endif + %ifdef TMPL_PPV86 + %error "Both 'TMPL_RM' and 'TMPL_PPV86' are defined." + %endif + %ifdef TMPL_PAE16 + %error "Both 'TMPL_RM' and 'TMPL_PAE16' are defined." + %endif + %ifdef TMPL_PAE32 + %error "Both 'TMPL_RM' and 'TMPL_PAE32' are defined." + %endif + %ifdef TMPL_PAEV86 + %error "Both 'TMPL_RM' and 'TMPL_PAEV86' are defined." + %endif + %ifdef TMPL_LM16 + %error "Both 'TMPL_RM' and 'TMPL_LM16' are defined." + %endif + %ifdef TMPL_LM32 + %error "Both 'TMPL_RM' and 'TMPL_LM32' are defined." + %endif + %ifdef TMPL_LM64 + %error "Both 'TMPL_RM' and 'TMPL_LM64' are defined." + %endif + %define TMPL_16BIT + %define TMPL_BITS 16 + %define TMPL_PTR_DEF dw + %define TMPL_NM(Name) Name %+ _rm + %define TMPL_NM_CMN(Name) Name %+ _r86 + %define TMPL_MODE_STR 'real mode' + %define TMPL_HAVE_BIOS + %define TMPL_CMN_R86 +%endif + +%ifdef TMPL_PE16 + %ifdef TMPL_RM + %error "Both 'TMPL_PE16' and 'TMPL_RM' are defined." + %endif + %ifdef TMPL_PE32 + %error "Both 'TMPL_PE16' and 'TMPL_PE32' are defined." + %endif + %ifdef TMPL_PEV86 + %error "Both 'TMPL_RM' and 'TMPL_PEV86' are defined." + %endif + %ifdef TMPL_PP16 + %error "Both 'TMPL_PE16' and 'TMPL_PP16' are defined." + %endif + %ifdef TMPL_PP32 + %error "Both 'TMPL_PE16' and 'TMPL_PP32' are defined." + %endif + %ifdef TMPL_PPV86 + %error "Both 'TMPL_PE16' and 'TMPL_PPV86' are defined." + %endif + %ifdef TMPL_PAE16 + %error "Both 'TMPL_PE16' and 'TMPL_PAE16' are defined." + %endif + %ifdef TMPL_PAE32 + %error "Both 'TMPL_PE16' and 'TMPL_PAE32' are defined." + %endif + %ifdef TMPL_PAEV86 + %error "Both 'TMPL_PE32' and 'TMPL_PAEV86' are defined." + %endif + %ifdef TMPL_LM16 + %error "Both 'TMPL_PE16' and 'TMPL_LM16' are defined." + %endif + %ifdef TMPL_LM32 + %error "Both 'TMPL_PE16' and 'TMPL_LM32' are defined." + %endif + %ifdef TMPL_LM64 + %error "Both 'TMPL_PE16' and 'TMPL_LM64' are defined." + %endif + %define TMPL_CMN_PE + %define TMPL_CMN_P16 + %define TMPL_16BIT + %define TMPL_BITS 16 + %define TMPL_PTR_DEF dw + %define TMPL_NM(Name) Name %+ _pe16 + %define TMPL_NM_CMN(Name) Name %+ _p16 + %define TMPL_MODE_STR '16-bit unpaged protected mode' +%endif + +%ifdef TMPL_PE32 + %ifdef TMPL_RM + %error "Both 'TMPL_PE32' and 'TMPL_RM' are defined." + %endif + %ifdef TMPL_PE16 + %error "Both 'TMPL_PE32' and 'TMPL_PE16' are defined." + %endif + %ifdef TMPL_PEV86 + %error "Both 'TMPL_PE32' and 'TMPL_PEV86' are defined." + %endif + %ifdef TMPL_PP16 + %error "Both 'TMPL_PE32' and 'TMPL_PP16' are defined." + %endif + %ifdef TMPL_PP32 + %error "Both 'TMPL_PE32' and 'TMPL_PP32' are defined." + %endif + %ifdef TMPL_PPV86 + %error "Both 'TMPL_PE32' and 'TMPL_PPV86' are defined." + %endif + %ifdef TMPL_PAE16 + %error "Both 'TMPL_PE32' and 'TMPL_PAE16' are defined." + %endif + %ifdef TMPL_PAE32 + %error "Both 'TMPL_PE32' and 'TMPL_PAE32' are defined." + %endif + %ifdef TMPL_PAE86 + %error "Both 'TMPL_PE32' and 'TMPL_PPV86' are defined." + %endif + %ifdef TMPL_LM16 + %error "Both 'TMPL_PE32' and 'TMPL_LM16' are defined." + %endif + %ifdef TMPL_LM32 + %error "Both 'TMPL_PE32' and 'TMPL_LM32' are defined." + %endif + %ifdef TMPL_LM64 + %error "Both 'TMPL_PE32' and 'TMPL_LM64' are defined." + %endif + %define TMPL_CMN_PE + %define TMPL_CMN_P32 + %define TMPL_32BIT + %define TMPL_BITS 32 + %define TMPL_PTR_DEF dd + %define TMPL_NM(Name) Name %+ _pe32 + %define TMPL_NM_CMN(Name) Name %+ _p32 + %define TMPL_MODE_STR '32-bit unpaged protected mode' +%endif + +%ifdef TMPL_PEV86 + %ifdef TMPL_RM + %error "Both 'TMPL_PEV86' and 'TMPL_RM' are defined." + %endif + %ifdef TMPL_PE16 + %error "Both 'TMPL_PEV86' and 'TMPL_PE16' are defined." + %endif + %ifdef TMPL_PP32 + %error "Both 'TMPL_PEV86' and 'TMPL_PP32' are defined." + %endif + %ifdef TMPL_PP16 + %error "Both 'TMPL_PEV86' and 'TMPL_PP16' are defined." + %endif + %ifdef TMPL_PP32 + %error "Both 'TMPL_PEV86' and 'TMPL_PP32' are defined." + %endif + %ifdef TMPL_PPV86 + %error "Both 'TMPL_PEV86' and 'TMPL_PPV86' are defined." + %endif + %ifdef TMPL_PAE16 + %error "Both 'TMPL_PEV86' and 'TMPL_PAE16' are defined." + %endif + %ifdef TMPL_PAE32 + %error "Both 'TMPL_PEV86' and 'TMPL_PAE32' are defined." + %endif + %ifdef TMPL_PAE86 + %error "Both 'TMPL_PEV86' and 'TMPL_PPV86' are defined." + %endif + %ifdef TMPL_LM16 + %error "Both 'TMPL_PEV86' and 'TMPL_LM16' are defined." + %endif + %ifdef TMPL_LM32 + %error "Both 'TMPL_PEV86' and 'TMPL_LM32' are defined." + %endif + %ifdef TMPL_LM64 + %error "Both 'TMPL_PEV86' and 'TMPL_LM64' are defined." + %endif + %define TMPL_CMN_PE + %define TMPL_CMN_V86 + %define TMPL_CMN_R86 + %define TMPL_16BIT + %define TMPL_BITS 16 + %define TMPL_PTR_DEF dw + %define TMPL_NM(Name) Name %+ _pev86 + %define TMPL_NM_CMN(Name) Name %+ _r86 + %define TMPL_MODE_STR 'v8086 unpaged protected mode' +%endif + +%ifdef TMPL_PP16 + %ifdef TMPL_RM + %error "Both 'TMPL_PP16' and 'TMPL_RM' are defined." + %endif + %ifdef TMPL_PE16 + %error "Both 'TMPL_PP16' and 'TMPL_PE16' are defined." + %endif + %ifdef TMPL_PE32 + %error "Both 'TMPL_PP16' and 'TMPL_PE32' are defined." + %endif + %ifdef TMPL_PEV86 + %error "Both 'TMPL_PP16' and 'TMPL_PEV86' are defined." + %endif + %ifdef TMPL_PP32 + %error "Both 'TMPL_PP16' and 'TMPL_PP32' are defined." + %endif + %ifdef TMPL_PPV86 + %error "Both 'TMPL_PP32' and 'TMPL_PPV86' are defined." + %endif + %ifdef TMPL_PAE16 + %error "Both 'TMPL_PP16' and 'TMPL_PAE16' are defined." + %endif + %ifdef TMPL_PAE32 + %error "Both 'TMPL_PP16' and 'TMPL_PAE32' are defined." + %endif + %ifdef TMPL_PAEV86 + %error "Both 'TMPL_PP16' and 'TMPL_PAEV86' are defined." + %endif + %ifdef TMPL_LM16 + %error "Both 'TMPL_PP16' and 'TMPL_LM16' are defined." + %endif + %ifdef TMPL_LM32 + %error "Both 'TMPL_PP16' and 'TMPL_LM32' are defined." + %endif + %ifdef TMPL_LM64 + %error "Both 'TMPL_PP16' and 'TMPL_LM64' are defined." + %endif + %define TMPL_CMN_PP + %define TMPL_CMN_P16 + %define TMPL_16BIT + %define TMPL_BITS 16 + %define TMPL_PTR_DEF dw + %define TMPL_NM(Name) Name %+ _pp16 + %define TMPL_NM_CMN(Name) Name %+ _p16 + %define TMPL_MODE_STR '16-bit paged protected mode' +%endif + +%ifdef TMPL_PP32 + %ifdef TMPL_RM + %error "Both 'TMPL_PP32' and 'TMPL_RM' are defined." + %endif + %ifdef TMPL_PE16 + %error "Both 'TMPL_PP32' and 'TMPL_PE16' are defined." + %endif + %ifdef TMPL_PE32 + %error "Both 'TMPL_PP32' and 'TMPL_PE32' are defined." + %endif + %ifdef TMPL_PEV86 + %error "Both 'TMPL_PP32' and 'TMPL_PEV86' are defined." + %endif + %ifdef TMPL_PP16 + %error "Both 'TMPL_PP32' and 'TMPL_PP16' are defined." + %endif + %ifdef TMPL_PPV86 + %error "Both 'TMPL_PP32' and 'TMPL_PPV86' are defined." + %endif + %ifdef TMPL_PAE16 + %error "Both 'TMPL_PP32' and 'TMPL_PAE16' are defined." + %endif + %ifdef TMPL_PAE32 + %error "Both 'TMPL_PP32' and 'TMPL_PAE32' are defined." + %endif + %ifdef TMPL_PAEV86 + %error "Both 'TMPL_PP32' and 'TMPL_PAEV86' are defined." + %endif + %ifdef TMPL_LM16 + %error "Both 'TMPL_PP32' and 'TMPL_LM16' are defined." + %endif + %ifdef TMPL_LM32 + %error "Both 'TMPL_PP32' and 'TMPL_LM32' are defined." + %endif + %ifdef TMPL_LM64 + %error "Both 'TMPL_PP32' and 'TMPL_LM64' are defined." + %endif + %define TMPL_CMN_PP + %define TMPL_CMN_P32 + %define TMPL_32BIT + %define TMPL_BITS 32 + %define TMPL_PTR_DEF dd + %define TMPL_NM(Name) Name %+ _pp32 + %define TMPL_NM_CMN(Name) Name %+ _p32 + %define TMPL_MODE_STR '32-bit paged protected mode' +%endif + +%ifdef TMPL_PPV86 + %ifdef TMPL_RM + %error "Both 'TMPL_PPV86' and 'TMPL_RM' are defined." + %endif + %ifdef TMPL_PE16 + %error "Both 'TMPL_PPV86' and 'TMPL_PE16' are defined." + %endif + %ifdef TMPL_PE32 + %error "Both 'TMPL_PPV86' and 'TMPL_PE32' are defined." + %endif + %ifdef TMPL_PEV86 + %error "Both 'TMPL_PPV86' and 'TMPL_PEV86' are defined." + %endif + %ifdef TMPL_PP16 + %error "Both 'TMPL_PPV86' and 'TMPL_PP16' are defined." + %endif + %ifdef TMPL_PP32 + %error "Both 'TMPL_PPV86' and 'TMPL_PP32' are defined." + %endif + %ifdef TMPL_PAE16 + %error "Both 'TMPL_PPV86' and 'TMPL_PAE16' are defined." + %endif + %ifdef TMPL_PAE32 + %error "Both 'TMPL_PPV86' and 'TMPL_PAE32' are defined." + %endif + %ifdef TMPL_PAEV86 + %error "Both 'TMPL_PPV86' and 'TMPL_PAEV86' are defined." + %endif + %ifdef TMPL_LM16 + %error "Both 'TMPL_PPV86' and 'TMPL_LM16' are defined." + %endif + %ifdef TMPL_LM32 + %error "Both 'TMPL_PPV86' and 'TMPL_LM32' are defined." + %endif + %ifdef TMPL_LM64 + %error "Both 'TMPL_PPV86' and 'TMPL_LM64' are defined." + %endif + %define TMPL_CMN_PP + %define TMPL_CMN_V86 + %define TMPL_CMN_R86 + %define TMPL_16BIT + %define TMPL_BITS 16 + %define TMPL_PTR_DEF dw + %define TMPL_NM(Name) Name %+ _ppv86 + %define TMPL_NM_CMN(Name) Name %+ _r86 + %define TMPL_MODE_STR 'v8086 paged protected mode' +%endif + +%ifdef TMPL_PAE16 + %ifdef TMPL_RM + %error "Both 'TMPL_PAE16' and 'TMPL_RM' are defined." + %endif + %ifdef TMPL_PE16 + %error "Both 'TMPL_PAE16' and 'TMPL_PE16' are defined." + %endif + %ifdef TMPL_PE32 + %error "Both 'TMPL_PAE16' and 'TMPL_PE32' are defined." + %endif + %ifdef TMPL_PEV86 + %error "Both 'TMPL_PAE16' and 'TMPL_PEV86' are defined." + %endif + %ifdef TMPL_PP16 + %error "Both 'TMPL_PAE16' and 'TMPL_PP16' are defined." + %endif + %ifdef TMPL_PP32 + %error "Both 'TMPL_PAE16' and 'TMPL_PP32' are defined." + %endif + %ifdef TMPL_PPV86 + %error "Both 'TMPL_PAE16' and 'TMPL_PPV86' are defined." + %endif + %ifdef TMPL_PAE32 + %error "Both 'TMPL_PAE16' and 'TMPL_PAE32' are defined." + %endif + %ifdef TMPL_LM16 + %error "Both 'TMPL_PAE16' and 'TMPL_LM16' are defined." + %endif + %ifdef TMPL_PAEV86 + %error "Both 'TMPL_PAE16' and 'TMPL_PAEV86' are defined." + %endif + %ifdef TMPL_LM32 + %error "Both 'TMPL_PAE16' and 'TMPL_LM32' are defined." + %endif + %ifdef TMPL_LM64 + %error "Both 'TMPL_PAE16' and 'TMPL_LM64' are defined." + %endif + %define TMPL_CMN_PAE + %define TMPL_16BIT + %define TMPL_CMN_P16 + %define TMPL_BITS 16 + %define TMPL_PTR_DEF dw + %define TMPL_NM(Name) Name %+ _pae16 + %define TMPL_NM_CMN(Name) Name %+ _p16 + %define TMPL_MODE_STR '16-bit pae protected mode' +%endif + +%ifdef TMPL_PAE32 + %ifdef TMPL_RM + %error "Both 'TMPL_PAE32' and 'TMPL_RM' are defined." + %endif + %ifdef TMPL_PE16 + %error "Both 'TMPL_PAE32' and 'TMPL_PE16' are defined." + %endif + %ifdef TMPL_PE32 + %error "Both 'TMPL_PAE32' and 'TMPL_PE32' are defined." + %endif + %ifdef TMPL_PEV86 + %error "Both 'TMPL_PAE32' and 'TMPL_PEV86' are defined." + %endif + %ifdef TMPL_PP16 + %error "Both 'TMPL_PAE32' and 'TMPL_PP16' are defined." + %endif + %ifdef TMPL_PP32 + %error "Both 'TMPL_PAE32' and 'TMPL_PP32' are defined." + %endif + %ifdef TMPL_PPV86 + %error "Both 'TMPL_PAE32' and 'TMPL_PPV86' are defined." + %endif + %ifdef TMPL_PAE16 + %error "Both 'TMPL_PAE32' and 'TMPL_PAE16' are defined." + %endif + %ifdef TMPL_PAEV86 + %error "Both 'TMPL_PAE32' and 'TMPL_PAEV86' are defined." + %endif + %ifdef TMPL_LM16 + %error "Both 'TMPL_PAE32' and 'TMPL_LM16' are defined." + %endif + %ifdef TMPL_LM32 + %error "Both 'TMPL_PAE32' and 'TMPL_LM32' are defined." + %endif + %ifdef TMPL_LM64 + %error "Both 'TMPL_PAE32' and 'TMPL_LM64' are defined." + %endif + %define TMPL_CMN_PAE + %define TMPL_CMN_P32 + %define TMPL_32BIT + %define TMPL_BITS 32 + %define TMPL_PTR_DEF dd + %define TMPL_NM(Name) Name %+ _pae32 + %define TMPL_NM_CMN(Name) Name %+ _p32 + %define TMPL_MODE_STR '32-bit pae protected mode' +%endif + +%ifdef TMPL_PAEV86 + %ifdef TMPL_RM + %error "Both 'TMPL_PAEV86' and 'TMPL_RM' are defined." + %endif + %ifdef TMPL_PE16 + %error "Both 'TMPL_PAEV86' and 'TMPL_PE16' are defined." + %endif + %ifdef TMPL_PE32 + %error "Both 'TMPL_PAEV86' and 'TMPL_PE32' are defined." + %endif + %ifdef TMPL_PEV86 + %error "Both 'TMPL_PAEV86' and 'TMPL_PEV86' are defined." + %endif + %ifdef TMPL_PP16 + %error "Both 'TMPL_PAEV86' and 'TMPL_PP16' are defined." + %endif + %ifdef TMPL_PP32 + %error "Both 'TMPL_PAEV86' and 'TMPL_PP32' are defined." + %endif + %ifdef TMPL_PPV86 + %error "Both 'TMPL_PAEV86' and 'TMPL_PPV86' are defined." + %endif + %ifdef TMPL_PAE16 + %error "Both 'TMPL_PAEV86' and 'TMPL_PAE16' are defined." + %endif + %ifdef TMPL_PAEV86 + %error "Both 'TMPL_PAEV86' and 'TMPL_PAEV86' are defined." + %endif + %ifdef TMPL_LM16 + %error "Both 'TMPL_PAEV86' and 'TMPL_LM16' are defined." + %endif + %ifdef TMPL_LM32 + %error "Both 'TMPL_PAEV86' and 'TMPL_LM32' are defined." + %endif + %ifdef TMPL_LM64 + %error "Both 'TMPL_PAEV86' and 'TMPL_LM64' are defined." + %endif + %define TMPL_CMN_PAE + %define TMPL_CMN_V86 + %define TMPL_CMN_R86 + %define TMPL_16BIT + %define TMPL_BITS 16 + %define TMPL_PTR_DEF dw + %define TMPL_NM(Name) Name %+ _paev86 + %define TMPL_NM_CMN(Name) Name %+ _r86 + %define TMPL_MODE_STR 'v8086 pae protected mode' +%endif + +%ifdef TMPL_LM16 + %ifdef TMPL_RM + %error "Both 'TMPL_LM16' and 'TMPL_RM' are defined." + %endif + %ifdef TMPL_PE16 + %error "Both 'TMPL_LM16' and 'TMPL_PE16' are defined." + %endif + %ifdef TMPL_PE32 + %error "Both 'TMPL_LM16' and 'TMPL_PE32' are defined." + %endif + %ifdef TMPL_PEV86 + %error "Both 'TMPL_LM16' and 'TMPL_PEV86' are defined." + %endif + %ifdef TMPL_PP16 + %error "Both 'TMPL_LM16' and 'TMPL_PP16' are defined." + %endif + %ifdef TMPL_PP32 + %error "Both 'TMPL_LM16' and 'TMPL_PP32' are defined." + %endif + %ifdef TMPL_PPV86 + %error "Both 'TMPL_LM16' and 'TMPL_PPV86' are defined." + %endif + %ifdef TMPL_PAE16 + %error "Both 'TMPL_LM16' and 'TMPL_PAE16' are defined." + %endif + %ifdef TMPL_PAE32 + %error "Both 'TMPL_LM16' and 'TMPL_PAE32' are defined." + %endif + %ifdef TMPL_PAEV86 + %error "Both 'TMPL_LM16' and 'TMPL_PAEV86' are defined." + %endif + %ifdef TMPL_LM32 + %error "Both 'TMPL_LM16' and 'TMPL_LM32' are defined." + %endif + %ifdef TMPL_LM64 + %error "Both 'TMPL_LM16' and 'TMPL_LM64' are defined." + %endif + %define TMPL_CMN_LM + %define TMPL_CMN_P16 + %define TMPL_16BIT + %define TMPL_BITS 16 + %define TMPL_PTR_DEF dw + %define TMPL_NM(Name) Name %+ _lm16 + %define TMPL_NM_CMN(Name) Name %+ _p16 + %define TMPL_MODE_STR '16-bit long mode' +%endif + +%ifdef TMPL_LM32 + %ifdef TMPL_RM + %error "Both 'TMPL_LM32' and 'TMPL_RM' are defined." + %endif + %ifdef TMPL_PE16 + %error "Both 'TMPL_LM32' and 'TMPL_PE16' are defined." + %endif + %ifdef TMPL_PE32 + %error "Both 'TMPL_LM32' and 'TMPL_PE32' are defined." + %endif + %ifdef TMPL_PEV86 + %error "Both 'TMPL_LM32' and 'TMPL_PEV86' are defined." + %endif + %ifdef TMPL_PP16 + %error "Both 'TMPL_LM32' and 'TMPL_PP16' are defined." + %endif + %ifdef TMPL_PP32 + %error "Both 'TMPL_LM32' and 'TMPL_PP32' are defined." + %endif + %ifdef TMPL_PPV86 + %error "Both 'TMPL_LM32' and 'TMPL_PPV86' are defined." + %endif + %ifdef TMPL_PAE16 + %error "Both 'TMPL_LM32' and 'TMPL_PAE16' are defined." + %endif + %ifdef TMPL_PAE32 + %error "Both 'TMPL_LM32' and 'TMPL_PAE32' are defined." + %endif + %ifdef TMPL_PAEV86 + %error "Both 'TMPL_LM32' and 'TMPL_PAEV86' are defined." + %endif + %ifdef TMPL_LM16 + %error "Both 'TMPL_LM32' and 'TMPL_LM16' are defined." + %endif + %ifdef TMPL_LM64 + %error "Both 'TMPL_LM32' and 'TMPL_LM64' are defined." + %endif + %define TMPL_CMN_LM + %define TMPL_CMN_P32 + %define TMPL_32BIT + %define TMPL_BITS 32 + %define TMPL_PTR_DEF dd + %define TMPL_NM(Name) Name %+ _lm32 + %define TMPL_NM_CMN(Name) Name %+ _p32 + %define TMPL_MODE_STR '32-bit long mode' +%endif + +%ifdef TMPL_LM64 + %ifdef TMPL_RM + %error ""Both 'TMPL_LM64' and 'TMPL_RM' are defined."" + %endif + %ifdef TMPL_PE16 + %error "Both 'TMPL_LM64' and 'TMPL_PE16' are defined." + %endif + %ifdef TMPL_PE32 + %error "Both 'TMPL_LM64' and 'TMPL_PE32' are defined." + %endif + %ifdef TMPL_PEV86 + %error "Both 'TMPL_LM64' and 'TMPL_PEV86' are defined." + %endif + %ifdef TMPL_PP16 + %error "Both 'TMPL_LM64' and 'TMPL_PP16' are defined." + %endif + %ifdef TMPL_PP32 + %error "Both 'TMPL_LM64' and 'TMPL_PP32' are defined." + %endif + %ifdef TMPL_PPV86 + %error "Both 'TMPL_LM64' and 'TMPL_PPV86' are defined." + %endif + %ifdef TMPL_PAE16 + %error "Both 'TMPL_LM64' and 'TMPL_PAE16' are defined." + %endif + %ifdef TMPL_PAE32 + %error "Both 'TMPL_LM64' and 'TMPL_PAE32' are defined." + %endif + %ifdef TMPL_PAEV86 + %error "Both 'TMPL_LM64' and 'TMPL_PAEV86' are defined." + %endif + %ifdef TMPL_LM16 + %error "Both 'TMPL_LM64' and 'TMPL_LM16' are defined." + %endif + %ifdef TMPL_LM32 + %error "Both 'TMPL_LM64' and 'TMPL_LM32' are defined." + %endif + %define TMPL_CMN_LM + %define TMPL_CMN_P64 + %define TMPL_64BIT + %define TMPL_BITS 64 + %define TMPL_PTR_DEF dq + %define TMPL_NM(Name) Name %+ _lm64 + %define TMPL_NM_CMN(Name) Name %+ _p64 + %define TMPL_MODE_STR '64-bit long mode' +%endif + +%ifndef TMPL_MODE_STR + %error "internal error" +%endif + + +; +; Register aliases. +; +%ifdef TMPL_64BIT + %define xCB 8 + %define xDEF dq + %define xRES resq + %define xPRE qword + %define xSP rsp + %define xBP rbp + %define xAX rax + %define xBX rbx + %define xCX rcx + %define xDX rdx + %define xDI rdi + %define xSI rsi + %define xWrtRIP wrt rip + %define xPUSHF pushq + %define xPOPF popfq +%else + %ifdef TMPL_32BIT + %define xCB 4 + %define xDEF dd + %define xRES resd + %define xPRE dword + %define xSP esp + %define xBP ebp + %define xAX eax + %define xBX ebx + %define xCX ecx + %define xDX edx + %define xDI edi + %define xSI esi + %define xWrtRIP + %define xPUSHF pushfd + %define xPOPF popfd + %else + %ifndef TMPL_16BIT + %error "TMPL_XXBIT is not defined." + %endif + %define xCB 2 + %define xDEF dw + %define xRES resw + %define xPRE word + %define xSP sp + %define xBP bp + %define xAX ax + %define xBX bx + %define xCX cx + %define xDX dx + %define xDI di + %define xSI si + %define xWrtRIP + %define xPUSHF pushf + %define xPOPF popf + %endif +%endif + +; +; Register names corresponding to the max size for pop/push <reg>. +; +; 16-bit can push both 32-bit and 16-bit registers. This 's' prefixed variant +; is used when 16-bit should use the 32-bit register. +; +%ifdef TMPL_64BIT + %define sCB 8 + %define sDEF dq + %define sRES resq + %define sPRE qword + %define sSP rsp + %define sBP rbp + %define sAX rax + %define sBX rbx + %define sCX rcx + %define sDX rdx + %define sDI rdi + %define sSI rsi + %define sPUSHF pushfq + %define sPOPF popfq +%else + %define sCB 4 + %define sDEF dd + %define sRES resd + %define sPRE dword + %define sSP esp + %define sBP ebp + %define sAX eax + %define sBX ebx + %define sCX ecx + %define sDX edx + %define sDI edi + %define sSI esi + %define sPUSHF pushfd + %define sPOPF popfd +%endif + +; +; Default code segment. +; +%ifdef TMPL_64BIT + %define TMPL_BEGINCODE BEGINCODEHIGH +%elifdef TMPL_32BIT + %define TMPL_BEGINCODE BEGINCODEHIGH +%elifdef TMPL_16BIT + %define TMPL_BEGINCODE BEGINCODELOW +%else + %error "Missing TMPL_xxBIT!" +%endif +TMPL_BEGINCODE + +; +; Change the bitness. +; +%ifdef TMPL_64BIT +BITS 64 +%else + %ifdef TMPL_32BIT +BITS 32 + %else +BITS 16 + %endif +%endif + diff --git a/src/VBox/ValidationKit/bootsectors/bootsector2-test1-template.mac b/src/VBox/ValidationKit/bootsectors/bootsector2-test1-template.mac new file mode 100644 index 00000000..c73d8ffe --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bootsector2-test1-template.mac @@ -0,0 +1,756 @@ +; $Id: bootsector2-test1-template.mac $ +;; @file +; bootsector2 test1 - multi mode template. +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + + +%include "bootsector2-template-header.mac" + +;; +; Run the CPUID benchmark for this mode. +; +; @uses nothing +; +BEGINCODELOW +BITS 16 +BEGINPROC TMPL_NM(BenchmarkCpuId_rm) + call TMPL_NM(Bs2IsModeSupported_rm) + jz .done + call TMPL_NM(Bs2EnterMode_rm) +BITS TMPL_BITS + push xBP + mov xBP, xSP + push sAX + push sBX + push sCX + push sDX + push sDI + sub sSP, 20h + + ; Get the current time. + mov xAX, xSP + call TMPL_NM_CMN(GetNanoTS) + + ; Do the test. + mov edi, TEST_INSTRUCTION_COUNT_IO / 4 +.again: + mov eax, 1 + cpuid + mov eax, 1 + cpuid + mov eax, 1 + cpuid + mov eax, 1 + cpuid + dec edi + jnz .again + + ; Calc the elapsed time and report the result. + mov xAX, xSP + call TMPL_NM_CMN(GetElapsedNanoTS) + + mov xCX, .s_szTestName + mov edx, TEST_INSTRUCTION_COUNT_IO + mov xAX, xSP + call TMPL_NM_CMN(ReportResult) + + add sSP, 20h + pop sDI + pop sDX + pop sCX + pop sBX + pop sAX + leave + + call TMPL_NM(Bs2ExitMode) +BITS 16 +.done: + ret + +.s_szTestName: + db TMPL_MODE_STR, ', CPUID', 0 +ENDPROC TMPL_NM(BenchmarkCpuId_rm) + +TMPL_BEGINCODE +BITS TMPL_BITS + + +;; +; Run the RDTSC benchmark for this mode. +; +; @uses nothing +; +BEGINCODELOW +BITS 16 +BEGINPROC TMPL_NM(BenchmarkRdTsc_rm) + call TMPL_NM(Bs2IsModeSupported_rm) + jz .done + call TMPL_NM(Bs2EnterMode_rm) +BITS TMPL_BITS + push xBP + mov xBP, xSP + push sAX + push sBX + push sCX + push sDX + push sDI + sub sSP, 20h + + ; Get the current time. + mov xAX, xSP + call TMPL_NM_CMN(GetNanoTS) + + ; Do the test. + mov edi, TEST_INSTRUCTION_COUNT_RDTSC / 4 +.again: + rdtsc + rdtsc + rdtsc + rdtsc + dec edi + jnz .again + + ; Calc the elapsed time and report the result. + mov xAX, xSP + call TMPL_NM_CMN(GetElapsedNanoTS) + + mov xCX, .s_szTestName + mov edx, TEST_INSTRUCTION_COUNT_RDTSC + mov xAX, xSP + call TMPL_NM_CMN(ReportResult) + + add sSP, 20h + pop sDI + pop sDX + pop sCX + pop sBX + pop sAX + leave + + call TMPL_NM(Bs2ExitMode) +BITS 16 +.done: + ret + +.s_szTestName: + db TMPL_MODE_STR, ', RDTSC', 0 +ENDPROC TMPL_NM(BenchmarkRdTsc_rm) + +TMPL_BEGINCODE +BITS TMPL_BITS + + +;; +; Run the Read CR4 benchmark for this mode. +; +; @uses nothing +; +BEGINCODELOW +BITS 16 +BEGINPROC TMPL_NM(BenchmarkRdCr4_rm) + call TMPL_NM(Bs2IsModeSupported_rm) + jz .done + call TMPL_NM(Bs2EnterMode_rm) +BITS TMPL_BITS + push xBP + mov xBP, xSP + push sAX + push sBX + push sCX + push sDX + push sDI + sub sSP, 20h + + ; Get the current time. + mov xAX, xSP + call TMPL_NM_CMN(GetNanoTS) + + ; Do the test. + mov edi, TEST_INSTRUCTION_COUNT_READCR4 / 4 +.again: + mov sAX, cr4 + mov sAX, cr4 + mov sAX, cr4 + mov sAX, cr4 + dec edi + jnz .again + + ; Calc the elapsed time and report the result. + mov xAX, xSP + call TMPL_NM_CMN(GetElapsedNanoTS) + + mov xCX, .s_szTestName + mov edx, TEST_INSTRUCTION_COUNT_READCR4 + mov xAX, xSP + call TMPL_NM_CMN(ReportResult) + + add sSP, 20h + pop sDI + pop sDX + pop sCX + pop sBX + pop sAX + leave + + call TMPL_NM(Bs2ExitMode) +BITS 16 +.done: + ret + +.s_szTestName: + db TMPL_MODE_STR, ', Read CR4', 0 +ENDPROC TMPL_NM(BenchmarkRdCr4_rm) + +TMPL_BEGINCODE +BITS TMPL_BITS + + +;; +; Prologue for the I/O port tests. +%ifndef HaveIoPortPrologue +%define HaveIoPortPrologue +%macro IoPortPrologue 2 + push xBP + mov xBP, xSP + push sAX + push sDX + push sCX + sub xSP, 20h + + ; Get the current time. + mov xAX, xSP + call TMPL_NM_CMN(GetNanoTS) + + ; Do the test. + mov dx, %2 + mov ecx, (%1) / 5 +%endmacro +%endif + + +;; +; Epilogue for the I/O port tests. +%ifndef HaveIoPortEpilogue +%define HaveIoPortEpilogue +%macro IoPortEpilogue 1 + ; Calc the elapsed time and report the result. + mov xAX, xSP + call TMPL_NM_CMN(GetElapsedNanoTS) + + mov xCX, .s_szTestName + mov edx, (%1) + mov xAX, xSP + call TMPL_NM_CMN(ReportResult) + + add xSP, 20h + pop sCX + pop sDX + pop sAX + leave + ret +%endmacro +%endif + + +;; +; Benchmarks: IN eax, NOP +; +; @uses nothing +; +BEGINPROC TMPL_NM(BenchmarkIoPortNop32In) + IoPortPrologue TEST_INSTRUCTION_COUNT_IO, VMMDEV_TESTING_IOPORT_NOP +.again: + in eax, dx + in eax, dx + in eax, dx + in eax, dx + in eax, dx + dec ecx + jnz .again + IoPortEpilogue TEST_INSTRUCTION_COUNT_IO +.s_szTestName: + db TMPL_MODE_STR, ', 32-bit IN', 0 +ENDPROC TMPL_NM(BenchmarkIoPortNop32In) + + +;; +; Benchmarks: OUT NOP, eax +; +; @uses nothing +; +BEGINPROC TMPL_NM(BenchmarkIoPortNop32Out) + IoPortPrologue TEST_INSTRUCTION_COUNT_IO, VMMDEV_TESTING_IOPORT_NOP +.again: + out dx, eax + out dx, eax + out dx, eax + out dx, eax + out dx, eax + dec ecx + jnz .again + IoPortEpilogue TEST_INSTRUCTION_COUNT_IO +.s_szTestName: + db TMPL_MODE_STR, ', 32-bit OUT', 0 +ENDPROC TMPL_NM(BenchmarkIoPortNop32Out) + + +;; +; Benchmarks: IN ax, NOP +; +; @uses nothing +; +BEGINPROC TMPL_NM(BenchmarkIoPortNop16In) + IoPortPrologue TEST_INSTRUCTION_COUNT_IO, VMMDEV_TESTING_IOPORT_NOP +.again: + in ax, dx + in ax, dx + in ax, dx + in ax, dx + in ax, dx + dec ecx + jnz .again + IoPortEpilogue TEST_INSTRUCTION_COUNT_IO +.s_szTestName: + db TMPL_MODE_STR, ', 16-bit IN', 0 +ENDPROC TMPL_NM(BenchmarkIoPortNop16In) + + +;; +; Benchmarks: OUT NOP, ax +; +; @uses nothing +; +BEGINPROC TMPL_NM(BenchmarkIoPortNop16Out) + IoPortPrologue TEST_INSTRUCTION_COUNT_IO, VMMDEV_TESTING_IOPORT_NOP +.again: + out dx, ax + out dx, ax + out dx, ax + out dx, ax + out dx, ax + dec ecx + jnz .again + IoPortEpilogue TEST_INSTRUCTION_COUNT_IO +.s_szTestName: + db TMPL_MODE_STR, ', 16-bit OUT', 0 +ENDPROC TMPL_NM(BenchmarkIoPortNop16Out) + + +;; +; Benchmarks: IN al, NOP +; +; @uses nothing +; +BEGINPROC TMPL_NM(BenchmarkIoPortNop8In) + IoPortPrologue TEST_INSTRUCTION_COUNT_IO, VMMDEV_TESTING_IOPORT_NOP +.again: + in al, dx + in al, dx + in al, dx + in al, dx + in al, dx + dec ecx + jnz .again + IoPortEpilogue TEST_INSTRUCTION_COUNT_IO +.s_szTestName: + db TMPL_MODE_STR, ', 8-bit IN', 0 +ENDPROC TMPL_NM(BenchmarkIoPortNop8In) + + +;; +; Benchmarks: OUT NOP, al +; +; @uses nothing +; +BEGINPROC TMPL_NM(BenchmarkIoPortNop8Out) + IoPortPrologue TEST_INSTRUCTION_COUNT_IO, VMMDEV_TESTING_IOPORT_NOP +.again: + out dx, al + out dx, al + out dx, al + out dx, al + out dx, al + dec ecx + jnz .again + IoPortEpilogue TEST_INSTRUCTION_COUNT_IO +.s_szTestName: + db TMPL_MODE_STR, ', 8-bit OUT', 0 +ENDPROC TMPL_NM(BenchmarkIoPortNop8Out) + + +;; +; Benchmarks: IN eax, NOP_R3 +; +; @uses nothing +; +BEGINPROC TMPL_NM(BenchmarkIoPortRing3Nop32In) + IoPortPrologue TEST_INSTRUCTION_COUNT_IO, VMMDEV_TESTING_IOPORT_NOP_R3 +.again: + in eax, dx + in eax, dx + in eax, dx + in eax, dx + in eax, dx + dec ecx + jnz .again + IoPortEpilogue TEST_INSTRUCTION_COUNT_IO +.s_szTestName: + db TMPL_MODE_STR, ', 32-bit IN-to-ring-3', 0 +ENDPROC TMPL_NM(BenchmarkIoPortRing3Nop32In) + + +;; +; Benchmarks: OUT NOP_R3, eax +; +; @uses nothing +; +BEGINPROC TMPL_NM(BenchmarkIoPortRing3Nop32Out) + IoPortPrologue TEST_INSTRUCTION_COUNT_IO, VMMDEV_TESTING_IOPORT_NOP_R3 +.again: + out dx, eax + out dx, eax + out dx, eax + out dx, eax + out dx, eax + dec ecx + jnz .again + IoPortEpilogue TEST_INSTRUCTION_COUNT_IO +.s_szTestName: + db TMPL_MODE_STR, ', 32-bit OUT-to-ring-3', 0 +ENDPROC TMPL_NM(BenchmarkIoPortRing3Nop32Out) + + +%undef IoPortPrologue +%undef IoPortEpilogue + + +;; +; Run the I/O benchmarks for this mode. +; +; @uses nothing +; +BEGINCODELOW +BITS 16 +BEGINPROC TMPL_NM(BenchmarkIoPortNop_rm) + call TMPL_NM(Bs2IsModeSupported_rm) + jz .done + call TMPL_NM(Bs2EnterMode_rm) +BITS TMPL_BITS + + call TMPL_NM(BenchmarkIoPortNop32In) + call TMPL_NM(BenchmarkIoPortNop32Out) +%ifndef QUICK_TEST + call TMPL_NM(BenchmarkIoPortNop16In) + call TMPL_NM(BenchmarkIoPortNop16Out) + call TMPL_NM(BenchmarkIoPortNop8In) + call TMPL_NM(BenchmarkIoPortNop8Out) +%endif + call TMPL_NM(BenchmarkIoPortRing3Nop32In) + call TMPL_NM(BenchmarkIoPortRing3Nop32Out) + + call TMPL_NM(Bs2ExitMode) +BITS 16 +.done: + ret +ENDPROC TMPL_NM(BenchmarkIoPortNop_rm) + +TMPL_BEGINCODE +BITS TMPL_BITS + + + + +;; +; Prologue for the MMIO tests. +%ifndef HaveMmioPrologue +%define HaveMmioPrologue +%macro MmioPrologue 2 + push xBP + mov xBP, xSP + push sAX + push sDX + push sCX + push sBX + sub xSP, 20h + + ; Get the current time. + mov xAX, xSP + call TMPL_NM_CMN(GetNanoTS) + + ; Do the test - X million 32-bit IN instructions. +%ifdef TMPL_16BIT + mov dx, ds ; save ds + %ifdef TMPL_RM + mov bx, VMMDEV_TESTING_MMIO_RM_SEL + mov ds, bx + mov ebx, VMMDEV_TESTING_MMIO_RM_OFF(%2) + %else + mov bx, BS2_SEL_MMIO16 + mov ds, bx + mov ebx, %2 - BS2_SEL_MMIO16_BASE + %endif +%else + mov xBX, %2 +%endif + mov ecx, (%1) / 5 +%endmacro +%endif + +;; +; Epilogue for the MMIO tests. +%ifndef HaveMmioEpilogue +%define HaveMmioEpilogue +%macro MmioEpilogue 1 +%ifdef TMPL_16BIT + mov ds, dx ; restore ds +%endif + + ; Calc the elapsed time and report the result. + mov xAX, xSP + call TMPL_NM_CMN(GetElapsedNanoTS) + + mov xCX, .s_szTestName + mov edx, (%1) + mov xAX, xSP + call TMPL_NM_CMN(ReportResult) + + add xSP, 20h + pop sBX + pop sCX + pop sDX + pop sAX + leave + ret +%endmacro +%endif + + +;; +; Benchmarks: MOV eax, [NOP] +; +; @uses nothing +; +BEGINPROC TMPL_NM(BenchmarkMmioNop32Read) + MmioPrologue TEST_INSTRUCTION_COUNT_MMIO, VMMDEV_TESTING_MMIO_NOP +.again: + mov eax, [sBX] + mov eax, [sBX] + mov eax, [sBX] + mov eax, [sBX] + mov eax, [sBX] + dec ecx + jnz .again + MmioEpilogue TEST_INSTRUCTION_COUNT_MMIO +.s_szTestName: + db TMPL_MODE_STR, ', 32-bit read', 0 +ENDPROC TMPL_NM(BenchmarkMmioNop32Read) + + +;; +; Benchmarks: MOV [NOP], eax +; +; @uses nothing +; +BEGINPROC TMPL_NM(BenchmarkMmioNop32Write) + MmioPrologue TEST_INSTRUCTION_COUNT_MMIO, VMMDEV_TESTING_MMIO_NOP +.again: + mov [sBX], eax + mov [sBX], eax + mov [sBX], eax + mov [sBX], eax + mov [sBX], eax + dec ecx + jnz .again + MmioEpilogue TEST_INSTRUCTION_COUNT_MMIO +.s_szTestName: + db TMPL_MODE_STR, ', 32-bit write', 0 +ENDPROC TMPL_NM(BenchmarkMmioNop32Write) + + +;; +; Benchmarks: MOV ax, [NOP] +; +; @uses nothing +; +BEGINPROC TMPL_NM(BenchmarkMmioNop16Read) + MmioPrologue TEST_INSTRUCTION_COUNT_MMIO, VMMDEV_TESTING_MMIO_NOP +.again: + mov ax, [xBX] + mov ax, [xBX] + mov ax, [xBX] + mov ax, [xBX] + mov ax, [xBX] + dec ecx + jnz .again + MmioEpilogue TEST_INSTRUCTION_COUNT_MMIO +.s_szTestName: + db TMPL_MODE_STR, ', 16-bit read', 0 +ENDPROC TMPL_NM(BenchmarkMmioNop16Read) + + +;; +; Benchmarks: MOV [NOP], ax +; +; @uses nothing +; +BEGINPROC TMPL_NM(BenchmarkMmioNop16Write) + MmioPrologue TEST_INSTRUCTION_COUNT_MMIO, VMMDEV_TESTING_MMIO_NOP +.again: + mov [xBX], ax + mov [xBX], ax + mov [xBX], ax + mov [xBX], ax + mov [xBX], ax + dec ecx + jnz .again + MmioEpilogue TEST_INSTRUCTION_COUNT_MMIO +.s_szTestName: + db TMPL_MODE_STR, ', 16-bit write', 0 +ENDPROC TMPL_NM(BenchmarkMmioNop16Write) + + +;; +; Benchmarks: MOV al, [NOP] +; +; @uses nothing +; +BEGINPROC TMPL_NM(BenchmarkMmioNop8Read) + MmioPrologue TEST_INSTRUCTION_COUNT_MMIO, VMMDEV_TESTING_MMIO_NOP +.again: + mov al, [xBX] + mov al, [xBX] + mov al, [xBX] + mov al, [xBX] + mov al, [xBX] + dec ecx + jnz .again + MmioEpilogue TEST_INSTRUCTION_COUNT_MMIO +.s_szTestName: + db TMPL_MODE_STR, ', 8-bit read', 0 +ENDPROC TMPL_NM(BenchmarkMmioNop8Read) + + +;; +; Benchmarks: MOV [NOP], al +; +; @uses nothing +; +BEGINPROC TMPL_NM(BenchmarkMmioNop8Write) + MmioPrologue TEST_INSTRUCTION_COUNT_MMIO, VMMDEV_TESTING_MMIO_NOP +.again: + mov [xBX], al + mov [xBX], al + mov [xBX], al + mov [xBX], al + mov [xBX], al + dec ecx + jnz .again + MmioEpilogue TEST_INSTRUCTION_COUNT_MMIO +.s_szTestName: + db TMPL_MODE_STR, ', 8-bit write', 0 +ENDPROC TMPL_NM(BenchmarkMmioNop8Write) + + +;; +; Benchmarks: MOV eax, [NOP_R3] +; +; @uses nothing +; +BEGINPROC TMPL_NM(BenchmarkMmioRing3Nop32Read) + MmioPrologue TEST_INSTRUCTION_COUNT_MMIO, VMMDEV_TESTING_MMIO_NOP_R3 +.again: + mov eax, [sBX] + mov eax, [sBX] + mov eax, [sBX] + mov eax, [sBX] + mov eax, [sBX] + dec ecx + jnz .again + MmioEpilogue TEST_INSTRUCTION_COUNT_MMIO +.s_szTestName: + db TMPL_MODE_STR, ', 32-bit read-to-ring-3', 0 +ENDPROC TMPL_NM(BenchmarkMmioRing3Nop32Read) + + +;; +; Benchmarks: MOV [NOP_R3], eax +; +; @uses nothing +; +BEGINPROC TMPL_NM(BenchmarkMmioRing3Nop32Write) + MmioPrologue TEST_INSTRUCTION_COUNT_MMIO, VMMDEV_TESTING_MMIO_NOP_R3 +.again: + mov [sBX], eax + mov [sBX], eax + mov [sBX], eax + mov [sBX], eax + mov [sBX], eax + dec ecx + jnz .again + MmioEpilogue TEST_INSTRUCTION_COUNT_MMIO +.s_szTestName: + db TMPL_MODE_STR, ', 32-bit write-to-ring-3', 0 +ENDPROC TMPL_NM(BenchmarkMmioRing3Nop32Write) + + +%undef MmioPrologue +%undef MmioEpilogue + + +;; +; Do the MMIO tests for this mode. +; +; @uses nothing +; +BEGINCODELOW +BITS 16 +BEGINPROC TMPL_NM(BenchmarkMmioNop_rm) + call TMPL_NM(Bs2IsModeSupported_rm) + jz .done + call TMPL_NM(Bs2EnterMode_rm) +BITS TMPL_BITS + + call TMPL_NM(BenchmarkMmioNop32Read) + call TMPL_NM(BenchmarkMmioNop32Write) +%ifndef QUICK_TEST + call TMPL_NM(BenchmarkMmioNop16Read) + call TMPL_NM(BenchmarkMmioNop16Write) + call TMPL_NM(BenchmarkMmioNop8Read) + call TMPL_NM(BenchmarkMmioNop8Write) +%endif + call TMPL_NM(BenchmarkMmioRing3Nop32Read) + call TMPL_NM(BenchmarkMmioRing3Nop32Write) + + call TMPL_NM(Bs2ExitMode) +BITS 16 +.done: + ret +ENDPROC TMPL_NM(BenchmarkMmioNop_rm) + +TMPL_BEGINCODE +BITS TMPL_BITS + + +%include "bootsector2-template-footer.mac" + diff --git a/src/VBox/ValidationKit/bootsectors/bootsector2-test1.asm b/src/VBox/ValidationKit/bootsectors/bootsector2-test1.asm new file mode 100644 index 00000000..88ca7c8c --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bootsector2-test1.asm @@ -0,0 +1,187 @@ +; $Id: bootsector2-test1.asm $ +;; @file +; Bootsector that benchmarks I/O and MMIO roundtrip time. +; VBoxManage setextradata bs-test1 VBoxInternal/Devices/VMMDev/0/Config/TestingEnabled 1 +; VBoxManage setextradata bs-test1 VBoxInternal/Devices/VMMDev/0/Config/TestingMMIO 1 +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + + +%include "iprt/asmdefs.mac" +%include "iprt/x86.mac" +%include "VBox/VMMDevTesting.mac" + +;; The number of instructions to test. +%define TEST_INSTRUCTION_COUNT_IO 2000000 + +;; The number of RDTSC instructions to test. +%define TEST_INSTRUCTION_COUNT_RDTSC 4000000 + +;; The number of RDTSC instructions to test. +%define TEST_INSTRUCTION_COUNT_READCR4 1000000 + +;; The number of instructions to test. +%define TEST_INSTRUCTION_COUNT_MMIO 750000 + +;; Define this to drop unnecessary test variations. +%define QUICK_TEST + +; +; Include and execute the init code. +; + %define BS2_INIT_RM + %define BS2_INC_PE16 + %define BS2_INC_PE32 + %define BS2_INC_PP32 + %define BS2_INC_PAE32 + %define BS2_INC_LM64 + %include "bootsector2-common-init-code.mac" + + +; +; The benchmark driver +; +BEGINPROC main + ; + ; Test prologue. + ; + mov ax, .s_szTstName + call TestInit_r86 + call Bs2EnableA20_r86 + call Bs2PanicIfVMMDevTestingIsMissing_r86 + + ; + ; CPUID. + ; + mov ax, .s_szTstCpuId + call TestSub_r86 + call BenchmarkCpuId_rm_pp32 + call BenchmarkCpuId_rm_pae32 + call BenchmarkCpuId_rm_lm64 + call BenchmarkCpuId_rm_pe16 + call BenchmarkCpuId_rm_pe32 + call BenchmarkCpuId_rm_rm + + ; + ; RDTSC. + ; + mov ax, .s_szTstRdTsc + call TestSub_r86 + call BenchmarkRdTsc_rm_pp32 + call BenchmarkRdTsc_rm_pae32 + call BenchmarkRdTsc_rm_lm64 + call BenchmarkRdTsc_rm_pe16 + call BenchmarkRdTsc_rm_pe32 + call BenchmarkRdTsc_rm_rm + + ; + ; Read CR4 + ; + mov ax, .s_szTstRdCr4 + call TestSub_r86 + call BenchmarkRdCr4_rm_pp32 + call BenchmarkRdCr4_rm_pae32 + call BenchmarkRdCr4_rm_lm64 + call BenchmarkRdCr4_rm_pe16 + call BenchmarkRdCr4_rm_pe32 + call BenchmarkRdCr4_rm_rm + + ; + ; I/O port access. + ; + mov ax, .s_szTstNopIoPort + call TestSub_r86 + call BenchmarkIoPortNop_rm_rm + call BenchmarkIoPortNop_rm_pe16 + call BenchmarkIoPortNop_rm_pe32 + call BenchmarkIoPortNop_rm_pp32 + call BenchmarkIoPortNop_rm_pae32 + call BenchmarkIoPortNop_rm_lm64 + + ; + ; MMIO access. + ; + mov ax, .s_szTstNopMmio + call TestSub_r86 + call BenchmarkMmioNop_rm_pp32 + call BenchmarkMmioNop_rm_pae32 + call BenchmarkMmioNop_rm_lm64 + call BenchmarkMmioNop_rm_pe16 + call BenchmarkMmioNop_rm_pe32 + call BenchmarkMmioNop_rm_rm + + ; + ; We're done. + ; + call TestTerm_r86 + call Bs2Panic + +.s_szTstName: + db 'tstIOIntr', 0 +.s_szTstCpuId: + db 'CPUID EAX=1', 0 +.s_szTstRdTsc: + db 'RDTSC', 0 +.s_szTstRdCr4: + db 'Read CR4', 0 +.s_szTstNopIoPort: + db 'NOP I/O Port Access', 0 +.s_szTstNopMmio: + db 'NOP MMIO Access', 0 +ENDPROC main + + +; +; Instantiate the template code. +; +%include "bootsector2-template-footer.mac" ; reset the initial environemnt. + +%define TMPL_RM +%include "bootsector2-test1-template.mac" +;%define TMPL_CMN_V86 +;%include "bootsector2-test1-template.mac" +%define TMPL_PE16 +%include "bootsector2-test1-template.mac" +%define TMPL_PE32 +%include "bootsector2-test1-template.mac" +;%define TMPL_PP16 +;%include "bootsector2-test1-template.mac" +%define TMPL_PP32 +%include "bootsector2-test1-template.mac" +;%define TMPL_PAE16 +;%include "bootsector2-test1-template.mac" +%define TMPL_PAE32 +%include "bootsector2-test1-template.mac" +;%define TMPL_LM16 +;%include "bootsector2-test1-template.mac" +;%define TMPL_LM32 +;%include "bootsector2-test1-template.mac" +%define TMPL_LM64 +%include "bootsector2-test1-template.mac" + + +; +; End sections and image. +; +%include "bootsector2-common-end.mac" + diff --git a/src/VBox/ValidationKit/bootsectors/bootsector2-triple-fault-1.asm b/src/VBox/ValidationKit/bootsectors/bootsector2-triple-fault-1.asm new file mode 100644 index 00000000..924d5626 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bootsector2-triple-fault-1.asm @@ -0,0 +1,380 @@ +; $Id: bootsector2-triple-fault-1.asm $ +;; @file +; Bootsector for testing triple faults. +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + + +%include "iprt/asmdefs.mac" +%include "iprt/x86.mac" +%include "VBox/VMMDevTesting.mac" + +;; The number of instructions to test. +%define TEST_INSTRUCTION_COUNT_IO 2000000 + +;; The number of instructions to test. +%define TEST_INSTRUCTION_COUNT_MMIO 750000 + +;; Define this to drop unnecessary test variations. +%define QUICK_TEST + +; +; Include and execute the init code. +; + %define BS2_INIT_RM + %define BS2_INC_PE16 + %define BS2_INC_PE32 + %define BS2_INC_PP32 + %define BS2_INC_PAE32 + %define BS2_INC_LM64 + %include "bootsector2-common-init-code.mac" + + +; +; The test driver +; +BEGINPROC main + ; + ; Test prologue. + ; + mov ax, .s_szTstName + call TestInit_r86 + call Bs2EnableA20_r86 + + ; + ; Did we get here from a reboot triggered below? + ; + push ds + mov ax, 2000h ; 128 KB is enough for the test program +.boot_check_loop: + mov ds, ax + cmp dword [0], 064726962h + jne .boot_check_next + cmp dword [4], 062697264h + je .warm_reset_broken + +.boot_check_next: + mov dword [0], 064726962h + mov dword [4], 062697264h + add ax, 1000h + cmp ax, 8000h + jbe .boot_check_loop + pop ds + jmp .fine + +.warm_reset_broken: + pop ds + mov ax, .s_szWarmResetBroken + call NAME(TestFailed_r86) + jmp .done +.s_szWarmResetBroken: + db 'Warm reset vector support is broken', 0dh, 0ah, 0 +.fine: + + ; + ; Test that the warm reset interface works. + ; + mov ax, .s_szPrecondTest5 + call NAME(TestSub_r86) + mov al, 05h + call NAME(SetWarmResetJmp) + cmp ax, 0 + jne .precond_test_A + call NAME(TestReboot_r86) + +.precond_test_A: + mov ax, .s_szPrecondTestA + call NAME(TestSub_r86) + mov al, 0Ah + call NAME(SetWarmResetJmp) + cmp ax, 0 + jne .precond_test_A_passed + call NAME(TestReboot_r86) +.precond_test_A_passed: + call NAME(TestSubDone_r86) + + ; + ; The real tests. + ; + + + ; + ; We're done. + ; +.done: + call NAME(TestTerm_r86) + call Bs2Panic + +.s_szTstName: + db 'tstTriple', 0 +.s_szPrecondTest5: + db 'Shutdown Action 5', 0 +.s_szPrecondTestA: + db 'Shutdown Action A', 0 +ENDPROC main + + + +;; +; Sets up the warm reset vector. +; +; @param ax Where to resume exeuction. +; @param dl Shutdown action command to use, 5h or Fh. +; +; @uses nothing +; +BEGINPROC SetUpWarmReset + push bp + mov bp, sp + push eax + push ebx + push ecx + push edx + push edi + push esi + push es + + ; + ; Set up the warm reboot vector. + ; + mov bx, 40h + mov es, bx + + mov ecx, [es:67h] ; debug + mov word [es:67h], ax + mov bx, cs + mov word [es:67h+2], bx + + mov bx, [es:72h] ; debug + mov word [es:72h], 1234h ; warm reboot + + wbinvd + + mov al, 0fh + out 70h, al ; set register index + in al, 71h + mov ah, al ; debug + mov al, dl ; shutdown action command + out 71h, al ; set cmos[f] = a - invoke testResume as early as possible. + in al, 71h ; debug / paranoia + movzx si, al + + ; Debug print. +%if 1 + mov di, sp ; save sp (lazy bird) + in al, 64h + push ax ; kbd status + push si ; cmos[f] after + mov al, ah ; cmos[f] before + push ax + push word [0472h] ; 40:72 word after + push bx ; 40:72 word before + push word [0467h] ; 40:67 far addr after + push word [0469h] + push cx ; 40:67 far addr before + shr ecx, 16 + push dx + push ds + push .s_szDebugFmt + call NAME(PrintF_r86) + mov sp, di ; restore sp. +;.forever: +; cli +; hlt +; jmp .forever +%endif + + pop es + pop esi + pop edi + pop edx + pop ecx + pop ebx + pop eax + leave + ret + +.s_szDebugFmt: + db 'dbg: 40:67=%RX16:%RX16 (%RX16:%RX16) 40:72=%RX16 (%RX16) cmos[f]=%RX8 (%RX8) kbdsts=%RX8', 0dh, 0ah, 0 +ENDPROC SetUpWarmReset + + +;; +; Sets up the warm reset vector. +; +; @returns ax = 0 on setup call, ax = 1 on resume return. +; @param al Shutdown action command to use, 5h or Fh. +; @uses ax +; +BEGINPROC SetWarmResetJmp + push bp + mov bp, sp + push dx + + mov dl, al + mov ax, .resume + call NAME(SetUpWarmReset) + +%ifdef DEBUG + push cs + push .s_szDbg1 + call NAME(PrintF_r86) + add sp, 4 +%endif + + mov ax, .s_ResumeRegs + call NAME(TestSaveRegisters_r86) + +%ifdef DEBUG + push cs + push .s_szDbg2 + call NAME(PrintF_r86) + add sp, 4 +%endif + + mov dx, [bp - 2] + mov [.s_ResumeRegs + BS2REGS.rdx], dx + mov ax, bp + add ax, 4 + mov [.s_ResumeRegs + BS2REGS.rsp], ax + mov ax, [bp] + mov [.s_ResumeRegs + BS2REGS.rbp], ax + mov ax, [bp + 2] + mov [.s_ResumeRegs + BS2REGS.rip], ax + mov word [.s_ResumeRegs + BS2REGS.rax], 1 + +%ifdef DEBUG + push cs + push .s_szDbg3 + call NAME(PrintF_r86) + add sp, 4 +%endif + + xor ax, ax +.done: + pop dx + leave + ret + +.resume: + cli + xor ax, ax + mov ds, ax + mov es, ax + mov ax, [.s_ResumeRegs + BS2REGS.ss] + mov ss, ax + mov esp, [.s_ResumeRegs + BS2REGS.rsp] + mov ebp, [.s_ResumeRegs + BS2REGS.rbp] + +%ifdef DEBUG + push ds + push .s_szDbg4 + call NAME(PrintF_r86) + add sp, 4 +%endif + + mov ax, .s_ResumeRegs + call NAME(TestRestoreRegisters_r86) + mov ax, [.s_ResumeRegs + BS2REGS.rip] + push ax + mov ax, 1 + ret + ;jmp word [.s_ResumeRegs + BS2REGS.rip] + +.s_ResumeRegs: + times (BS2REGS_size) db 0 +%ifdef DEBUG +.s_szDbg1: + db 'dbg 1', 0dh, 0ah, 0 +.s_szDbg2: + db 'dbg 2', 0dh, 0ah, 0 +.s_szDbg3: + db 'dbg 3', 0dh, 0ah, 0 +.s_szDbg4: + db 'dbg 4', 0dh, 0ah, 0 +%endif +ENDPROC SetWarmResetJmp + + +;; +; Reboot the machine. Will not return. +; +BEGINPROC TestReboot_r86 +%ifdef DEBUG + ; Debug + push ds + push .s_szDbg + call NAME(PrintF_r86) +%endif + ; Via port A + in al, 92h + and al, ~1 + out 92h, al + or al, 1 + out 92h, al + in al, 92h +.forever: + cli + hlt + jmp .forever +%ifdef DEBUG +.s_szDbg: + db 'Rebooting...', 0dh, 0ah, 0 +%endif +ENDPROC TestReboot_r86 + + +; +; Instantiate the template code. +; +%include "bootsector2-template-footer.mac" ; reset the initial environemnt. + +;%define TMPL_RM +;%include "bootsector2-test1-template.mac" +;%define TMPL_CMN_V86 +;%include "bootsector2-test1-template.mac" +;%define TMPL_PE16 +;%include "bootsector2-test1-template.mac" +;%define TMPL_PE32 +;%include "bootsector2-test1-template.mac" +;%define TMPL_PP16 +;%include "bootsector2-test1-template.mac" +;%define TMPL_PP32 +;%include "bootsector2-test1-template.mac" +;%define TMPL_PAE16 +;%include "bootsector2-test1-template.mac" +;%define TMPL_PAE32 +;%include "bootsector2-test1-template.mac" +;%define TMPL_LM16 +;%include "bootsector2-test1-template.mac" +;%define TMPL_LM32 +;%include "bootsector2-test1-template.mac" +;%define TMPL_LM64 +;%include "bootsector2-test1-template.mac" + + +; +; End sections and image. +; +%include "bootsector2-common-end.mac" + diff --git a/src/VBox/ValidationKit/bootsectors/bootsector2-vbinstst-64-1.asm b/src/VBox/ValidationKit/bootsectors/bootsector2-vbinstst-64-1.asm new file mode 100644 index 00000000..c91c933d --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bootsector2-vbinstst-64-1.asm @@ -0,0 +1,111 @@ +; $Id: bootsector2-vbinstst-64-1.asm $ +;; @file +; Bootsector tests instructions in 64-bit mode. +; VBoxManage setextradata bs-vbinstst-64-1 VBoxInternal/Devices/VMMDev/0/Config/TestingEnabled 1 +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + + +%include "iprt/asmdefs.mac" +%include "iprt/x86.mac" +%include "VBox/VMMDevTesting.mac" + +; +; Include and execute the init code. +; + %define BS2_INIT_RM + %define BS2_INC_LM64 + %define BS2_WITH_TRAPS + %include "bootsector2-common-init-code.mac" + + +; +; The benchmark driver +; +BEGINPROC main + ; + ; Test prologue. + ; + cli + mov ax, .s_szTstName + call TestInit_r86 + call Bs2EnableA20_r86 + call Bs2PanicIfVMMDevTestingIsMissing_r86 + lea eax, [dword the_end] + cmp eax, dword 80000h + jae .size_nok + + + ; + ; Do the testing. + ; + call Bs2IsModeSupported_rm_lm64 + jz .done + call Bs2EnterMode_rm_lm64 +BITS 64 + + call TestInstrMain_lm64 + + call TestSubDone_p64 + call Bs2ExitMode_lm64 +BITS 16 +.done: + + ; + ; We're done. + ; + call TestTerm_r86 + call Bs2Panic + jmp .done + +.size_nok: + push eax + push word ds + push .s_szSizeNok + call TestFailedF_r86 + jmp .done + +.s_szSizeNok: + db 'Test is too big (%RX32)', 0 +.s_szTstName: + db 'VBInsTst-64-1', 0 +ENDPROC main + + +; +; Instantiate the template code. +; +%include "bootsector2-template-footer.mac" ; reset the initial environemnt. + +%define TMPL_LM64 +%include "bootsector2-template-header.mac" +BITS 64 +%include "VBInsTst-64.asm" +%include "bootsector2-template-footer.mac" + + +; +; End sections and image. +; +%include "bootsector2-common-end.mac" + diff --git a/src/VBox/ValidationKit/bootsectors/bootsector2-vbinstst-big-template.asm b/src/VBox/ValidationKit/bootsectors/bootsector2-vbinstst-big-template.asm new file mode 100644 index 00000000..6fae40b0 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bootsector2-vbinstst-big-template.asm @@ -0,0 +1,81 @@ +; $Id: bootsector2-vbinstst-big-template.asm $ +;; @file +; Boot Sector 2 with big instruction test image template. For use with +; bootsector2-vbinstst-kernel.asm. Requires: +; VBoxManage setextradata bs-vbinstst-64-1 VBoxInternal/Devices/VMMDev/0/Config/TestingEnabled 1 +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + + +; +; Set up the assembler environment. +; +%include "bootsector2-first.mac" +%include "bootsector2-api.mac" + +%include "bootsector2-template-footer.mac" +%ifdef BS2_BIG_IMAGE_LM64 + %define TMPL_LM64 + %include "bootsector2-template-header.mac" + BITS 64 + +%elifdef BS2_BIG_IMAGE_PAE32 + %define TMPL_PAE32 + %include "bootsector2-template-header.mac" + BITS 32 + +%elifdef BS2_BIG_IMAGE_PP32 + %define TMPL_PP32 + %include "bootsector2-template-header.mac" + BITS 32 + +%else + %error Do not know which mode to run in. + mov bad,instr +%endif + + + ORG BS2_BIG_LOAD_ADDR + +; +; The entry point is the first byte in the image. +; +bs2_big_image_start: +entrypoint: + mov xAX, .s_szTestName + call [TMPL_NM_CMN(g_pfnTestInit) xWrtRIP] + call TMPL_NM(TestInstrMain) + call [TMPL_NM_CMN(g_pfnTestTerm) xWrtRIP] +.hltloop: + hlt + jmp .hltloop + +.s_szTestName: + db BS2_BIG_IMAGE_GEN_TEST_NAME, 0 + + +; +; Instantiate the template code. +; +%include "BS2_BIG_IMAGE_GEN_SOURCE_FILE" + diff --git a/src/VBox/ValidationKit/bootsectors/bootsector2-vbinstst-kernel.asm b/src/VBox/ValidationKit/bootsectors/bootsector2-vbinstst-kernel.asm new file mode 100644 index 00000000..eed8cd0e --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bootsector2-vbinstst-kernel.asm @@ -0,0 +1,517 @@ +; $Id: bootsector2-vbinstst-kernel.asm $ +;; @file +; bootsector #2 kernel for big instruction testcases. +; VBoxManage setextradata bs-vbinstst-64-1 VBoxInternal/Devices/VMMDev/0/Config/TestingEnabled 1 +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + + +; +; This is always the first include file. +; +%include "bootsector2-first.mac" + +; +; Include and execute the init code. +; + %define BS2_INIT_RM + %define BS2_WITH_TRAPS + %define BS2_WITHOUT_RAW_MODE ; causes troubles with PIC/floppy. + + %define BS2_INC_RM + %define BS2_INC_PE16 + %define BS2_INC_PE32 + %define BS2_INC_PP16 + %define BS2_INC_PP32 + %define BS2_INC_PAE16 + %define BS2_INC_PAE32 + %define BS2_INC_LM16 + %define BS2_INC_LM32 + %define BS2_INC_LM64 + %include "bootsector2-common-init-code.mac" + %include "bootsector2-api.mac" + %include "iprt/formats/pe.mac" + %include "iprt/formats/mz.mac" + + +BEGINCODE +BEGINPROC main +; +; Set up the runtime environment. +; + call Bs2EnableA20_r86 + + ; 16-bit real mode. +%undef BS2_API_TEMPLATE_ACTION +%define BS2_API_TEMPLATE_ACTION(a_Name) mov dword [NAME(g_pfn %+ a_Name %+ _r86)], dword NAME(a_Name %+ _r86) + BS2_API_TEMPLATE + + ; 16-bit protected mode. +%undef BS2_API_TEMPLATE_ACTION +%define BS2_API_TEMPLATE_ACTION(a_Name) mov word [NAME(g_pfn %+ a_Name %+ _p16)], word NAME(a_Name %+ _p16) + BS2_API_TEMPLATE + mov eax, BS2_SEL_CS16 +%undef BS2_API_TEMPLATE_ACTION +%define BS2_API_TEMPLATE_ACTION(a_Name) mov [NAME(g_pfn %+ a_Name %+ _p16) + 2], ax + BS2_API_TEMPLATE + + ; 32-bit +%undef BS2_API_TEMPLATE_ACTION +%define BS2_API_TEMPLATE_ACTION(a_Name) mov dword [NAME(g_pfn %+ a_Name %+ _p32)], dword NAME(a_Name %+ _p32) + BS2_API_TEMPLATE + + ; 64-bit +%undef BS2_API_TEMPLATE_ACTION +%define BS2_API_TEMPLATE_ACTION(a_Name) mov dword [NAME(g_pfn %+ a_Name %+ _p64)], dword NAME(a_Name %+ _p64) + BS2_API_TEMPLATE + xor eax, eax +%undef BS2_API_TEMPLATE_ACTION +%define BS2_API_TEMPLATE_ACTION(a_Name) mov dword [NAME(g_pfn %+ a_Name %+ _p64) + 4], eax + BS2_API_TEMPLATE + + ; The magic markers and version number. + mov dword [g_u32Bs2ApiMagic], BS2_API_MAGIC + mov dword [g_u32Bs2ApiEndMagic], BS2_API_MAGIC + mov dword [g_u32Bs2ApiVersion], BS2_API_VERSION + +; +; Load the extended image into high memory. +; + mov dl, [g_bBootDrv] + call NAME(bs2LoadBigImage) + +; +; Hand control over to the extended image. +; +%ifdef BS2_BIG_IMAGE_LM64 + call Bs2EnterMode_rm_lm64 +BITS 64 + mov eax, BS2_BIG_LOAD_ADDR + call rax + call Bs2ExitMode_lm64 +BITS 16 + +%elifdef BS2_BIG_IMAGE_PP32 + call Bs2EnterMode_rm_pp32 +BITS 32 + mov eax, BS2_BIG_LOAD_ADDR + call eax + call Bs2ExitMode_pp32 +BITS 16 + +%elifdef BS2_BIG_IMAGE_PAE32 + call Bs2EnterMode_rm_pae32 +BITS 32 + mov eax, BS2_BIG_LOAD_ADDR + call eax + call Bs2ExitMode_pae32 +BITS 16 + +%else + ; + ; Probe the image, looking for an executable format we can deal with. + ; Not doing a lot of checking here, but who cares right now... + ; + call Bs2EnterMode_rm_pp32 +BITS 32 + mov eax, BS2_BIG_LOAD_ADDR + cmp word [eax], IMAGE_DOS_SIGNATURE + jne .not_dos + add eax, [eax + IMAGE_DOS_HEADER.e_lfanew] +.not_dos: + cmp dword [eax], IMAGE_NT_SIGNATURE + je .is_pe + mov eax, BS2_BIG_LOAD_ADDR + jmp .start_32 + +.is_pe: + lea edx, [eax + IMAGE_NT_HEADERS32.FileHeader] + cmp word [edx + IMAGE_FILE_HEADER.Machine], IMAGE_FILE_MACHINE_I386 + je .is_pe32 + cmp word [edx + IMAGE_FILE_HEADER.Machine], IMAGE_FILE_MACHINE_AMD64 + je .is_pe64 + jmp .panic_32 + +.is_pe32: + add edx, IMAGE_FILE_HEADER_size + mov eax, [edx + IMAGE_OPTIONAL_HEADER32.AddressOfEntryPoint] + add eax, BS2_BIG_LOAD_ADDR + jmp .start_32 + +.is_pe64: + add edx, IMAGE_FILE_HEADER_size + mov eax, [edx + IMAGE_OPTIONAL_HEADER64.AddressOfEntryPoint] + add eax, BS2_BIG_LOAD_ADDR + jmp .start_64 + + ; Start executing at eax in 32-bit mode (current). +.start_32: + call eax +.panic_32: + call Bs2ExitMode_pp32 +BITS 16 + jmp .panic + + ; Start executing at eax in 64-bit mode. +BITS 32 +.start_64: + call Bs2ExitMode_pp32 +BITS 16 + call Bs2EnterMode_rm_lm64 +BITS 64 + mov eax, eax + call rax + call Bs2ExitMode_lm64 +BITS 16 + jmp .panic + +.panic: +%endif + call Bs2Panic +ENDPROC main + + + + +;; +; Loads the big image off the floppy. +; +; This uses the the_end label to figure out the starting offset. +; The length is assumed to be the whole floppy. +; +; Clobbers nothing, except for 68KB of memory beyond the_end. +; +; @param dl The boot drive number (from BIOS). +; +BITS 16 +BEGINPROC bs2LoadBigImage + push ebp + movzx ebp, sp + +%define bSavedDiskNo byte [bp - 02h] + push dx +%define bMaxSector byte [bp - 04h] + push 0 +%define bMaxHead byte [bp - 06h] + push 0 +%define bMaxCylinder byte [bp - 08h] + push 0 +%define pbHighDst dword [bp - 0ch] + push dword BS2_BIG_LOAD_ADDR +%define SegTemp word [bp - 0eh] + push 0 +%define fStatus byte [bp - 10h] + push 0 + + push es + push ds + push eax + push edx + push ecx + push ebx + push edi + push esi + push ebp + + ; Display message. + push cs + push .s_szLoadingBigImage + call PrintF_r86 + add sp, 4 + + + ; + ; Try figure the geometry. This defines how much we'll read. + ; + mov ah, 08h + xor di, di ; (es:di = 0000:0000 works around some buggy bioses, says wikipedia.) + mov es, di + int 13h + jc .param_error + mov bMaxSector, cl ; Do the cl[7:6]+ch stuff so we can address 255 sectors on the fake 63MB floppy. + mov bMaxHead, dh + mov bMaxCylinder, ch ; See above. + mov dl, bSavedDiskNo +%if 0 + movzx ax, bMaxCylinder + push ax + movzx cx, bMaxHead + push cx + movzx ax, bMaxSector + push ax + push ds + push .s_szDbgParam + call PrintF_r86 + jmp .dprintf_param_done +.s_szDbgParam: + db 13, 10, 'Floppy params max: sectors=%RX16 heads=%RX16 cylinders=%RX16', 13, 10, 0 +.dprintf_param_done: +%endif + + ; + ; Skip the kernel image (this could be done more efficiently, but this + ; also does the trick). + ; + lea eax, [dword the_end] + sub eax, start + shr eax, 9 ; sectors to skip + mov cx, 0001h ; sector (1-based), cylinder (0-based). + xor dh, dh ; head (0-based). +.skip_one_more: + inc cl + cmp cl, bMaxSector + jbe .decrement_sector_count + + mov cl, 1 + inc dh + cmp dh, bMaxHead ; ASSUMES bMaxHead < 255. + jbe .decrement_sector_count + + mov dh, 0 + inc ch + +.decrement_sector_count: + dec ax + jnz .skip_one_more + + + + ; + ; Load loop. We load and copy 64 KB at the time into the high location. + ; Fixed registers (above): dl=drive, cl[7:6]:ch=cylinder, dh=head, cl[5:0]=sector. + ; + lea eax, [dword the_end + 0ffffh] + and eax, 0ffff0000h + shr eax, 4 + mov SegTemp, ax ; the 64KB segment we use for temporary storage. + +.the_load_loop: + mov al, '.' + call PrintChr_r86 + + ; Fill the segment with int3s (in case we don't read a full 64KB). + mov eax, 0cccccccch + mov di, SegTemp + mov es, di + xor edi, edi + push ecx + cld + mov cx, 4000h + rep stosd + pop ecx + + ; + ; Load a bunch of sectors into the temp segment. + ; + xor ebx, ebx +.the_sector_load_loop: + ; Figure how many sectors we can read without switching track or side. + movzx ax, bMaxSector + sub al, cl + inc al ; al = sectors left to read in the current track on the current side. + mov di, bx + shr di, 9 ; bx/512 = current sector offset. + neg di + add di, 10000h / 512 ; di = sectors left to read in the 64KB buffer. + cmp ax, di ; ax = min(ax, di) + jbe .use_ax_sector_count1 + mov ax, di +.use_ax_sector_count1: + cmp ax, 64 ; ax = min(ax,64) - Our BIOS limitation is 72, play safe. + jbe .use_ax_sector_count2 + mov ax, 64 +.use_ax_sector_count2: + mov di, ax ; save the number of sectors we read + + ; Do the reading. +%if 0 + push bx + push ax + push dx + push cx + push cs + push .s_szDbgRead + call PrintF_r86 + jmp .after_read_dprintf +.s_szDbgRead: db 'Reading CX=%RX16 DX=%RX16 AX=%RX16 BX=%RX16', 13, 10, 0 +.after_read_dprintf: +%endif + push bx + mov ah, 02h ; ah=read function + int 13h + pop bx + jc .read_error + + ; advance to the next sector/head/cylinder and address (lazy impl). +.advance_another_sector: + cmp cl, bMaxSector + je .next_head + inc cl + jmp .adv_addr + +.next_head: + mov cl, 1 + cmp dh, bMaxHead + je .next_cylinder + inc dh + jmp .adv_addr + +.next_cylinder: + mov dh, 0 + cmp ch, bMaxCylinder ; No the cl[7:6]+ch stuff so we can address 255 sectors on the fake 63MB floppy. + jb .update_ch + mov fStatus, 1 + jmp .move_block +.update_ch: + inc ch + +.adv_addr: + add bx, 512 + dec di + jnz .advance_another_sector + + test bx, bx + jnz .the_sector_load_loop + +.move_block: + ; + ; Copy the memory into high mem. + ; +%if 0 + mov edi, pbHighDst + push edi + push cs + push .s_szDbgMove + call PrintF_r86 + jmp .after_move_dprintf +.s_szDbgMove: db 'Moving memory to EDI=%RX32', 13, 10, 0 +.after_move_dprintf: +%endif + + push ecx + push edx + push ds + push es + call Bs2EnterMode_rm_pp32 +BITS 32 + ; Copy + mov edi, pbHighDst + movzx esi, SegTemp + shl esi, 4 + mov ecx, 10000h / 4 + cld + rep movsd + + ; Verify + mov edi, pbHighDst + movzx esi, SegTemp + shl esi, 4 + mov ecx, 10000h / 4 + cld + repe cmpsd + je .mem_verified_ok + mov fStatus, 2 + +.mem_verified_ok: + mov pbHighDst, edi + + call Bs2ExitMode_pp32 +BITS 16 + pop es + pop ds + pop edx + pop ecx + + ; Continue reading and copying? + cmp fStatus, 0 + je .the_load_loop + + ; Do we quit the loop on a failure? + cmp fStatus, 2 + je .verify_failed_msg + + ; + ; Done, so end the current message line. + ; + mov al, 13 + call PrintChr_r86 + mov al, 10 + call PrintChr_r86 + + + pop esi + pop edi + pop ebx + pop ecx + pop edx + pop eax + pop ds + pop es + mov sp, bp + pop ebp + ret + + + ; + ; Something went wrong, display a message. + ; +.verify_failed_msg: + mov edi, pbHighDst + push edi + push cs + push .s_szVerifyFailed + jmp .print_message_and_panic + +.param_error: + push ax + push cs + push .s_szParamError + jmp .print_message_and_panic + +.read_error: + push ax + push cs + push .s_szReadError + jmp .print_message_and_panic + +.print_message_and_panic: + call PrintF_r86 + call Bs2Panic + jmp .print_message_and_panic + +.s_szReadError: + db 13, 10, 'Error reading: %RX8', 13, 10, 0 +.s_szParamError: + db 13, 10, 'Error getting params: %RX8', 13, 10, 0 +.s_szVerifyFailed: + db 13, 10, 'Failed to move block high... (%RX32) Got enough memory configured?', 13, 10, 0 +.s_szLoadingBigImage: + db 'Loading 2nd image.', 0 +ENDPROC bs2LoadBigImage + + +; +; End sections and image. +; +%include "bootsector2-common-end.mac" + diff --git a/src/VBox/ValidationKit/bootsectors/bs3-cpu-basic-2-32.c32 b/src/VBox/ValidationKit/bootsectors/bs3-cpu-basic-2-32.c32 new file mode 100644 index 00000000..35194e42 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3-cpu-basic-2-32.c32 @@ -0,0 +1,56 @@ +/* $Id: bs3-cpu-basic-2-32.c32 $ */ +/** @file + * BS3Kit - bs3-cpu-basic-2, 32-bit C code. + */ + +/* + * Copyright (C) 2007-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include <bs3kit.h> +#include <iprt/asm-amd64-x86.h> + + +/********************************************************************************************************************************* +* Internal Functions * +*********************************************************************************************************************************/ +FNBS3TESTDOMODE bs3CpuBasic2_RaiseXcpt0e_c32; + + +/********************************************************************************************************************************* +* Global Variables * +*********************************************************************************************************************************/ +static const BS3TESTMODEBYONEENTRY g_aModeByOne32Tests[] = +{ + { "#PF", bs3CpuBasic2_RaiseXcpt0e_c32, BS3TESTMODEBYONEENTRY_F_ONLY_PAGING }, +}; + + +BS3_DECL(void) bs3CpuBasic2_Do32BitTests_pe32(void) +{ + Bs3TestPrintf("bs3CpuBasic2_Do32BitTests=%#x\n", g_uBs3CpuDetected); + + Bs3TestDoModesByOne_pe32(g_aModeByOne32Tests, RT_ELEMENTS(g_aModeByOne32Tests), 0); +} + diff --git a/src/VBox/ValidationKit/bootsectors/bs3-cpu-basic-2-asm.asm b/src/VBox/ValidationKit/bootsectors/bs3-cpu-basic-2-asm.asm new file mode 100644 index 00000000..25931ac7 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3-cpu-basic-2-asm.asm @@ -0,0 +1,159 @@ +; $Id: bs3-cpu-basic-2-asm.asm $ +;; @file +; BS3Kit - bs3-cpu-basic-2 +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + + +;********************************************************************************************************************************* +;* Header Files * +;********************************************************************************************************************************* +%include "bs3kit.mac" + + +;********************************************************************************************************************************* +;* Global Variables * +;********************************************************************************************************************************* +BS3_BEGIN_DATA16 +BS3_GLOBAL_DATA g_bs3CpuBasic2_ud2_FlatAddr, 4 + dd _bs3CpuBasic2_ud2 wrt FLAT + + + +; +; CPU mode agnostic test code snippets. +; +BS3_BEGIN_TEXT16 + +BS3_PROC_BEGIN _bs3CpuBasic2_ud2 +.again: + ud2 + jmp .again +BS3_PROC_END _bs3CpuBasic2_ud2 + + +BS3_PROC_BEGIN _bs3CpuBasic2_Int80 + int 80h +.again: ud2 + jmp .again +BS3_PROC_END _bs3CpuBasic2_Int80 + + +BS3_PROC_BEGIN _bs3CpuBasic2_Int81 + int 81h +.again: ud2 + jmp .again +BS3_PROC_END _bs3CpuBasic2_Int81 + + +BS3_PROC_BEGIN _bs3CpuBasic2_Int82 + int 82h +.again: ud2 + jmp .again +BS3_PROC_END _bs3CpuBasic2_Int82 + + +BS3_PROC_BEGIN _bs3CpuBasic2_Int83 + int 83h +.again: ud2 + jmp .again +BS3_PROC_END _bs3CpuBasic2_Int83 + + +BS3_PROC_BEGIN _bs3CpuBasic2_iret + iret +BS3_PROC_END _bs3CpuBasic2_iret +AssertCompile(_bs3CpuBasic2_iret_EndProc - _bs3CpuBasic2_iret == 1) + + +BS3_PROC_BEGIN _bs3CpuBasic2_iret_opsize + iretd +BS3_PROC_END _bs3CpuBasic2_iret_opsize +AssertCompile(_bs3CpuBasic2_iret_opsize_EndProc - _bs3CpuBasic2_iret_opsize == 2) + + +BS3_PROC_BEGIN _bs3CpuBasic2_iret_rexw + BS3_SET_BITS 64 + iretq + BS3_SET_BITS 16 +BS3_PROC_END _bs3CpuBasic2_iret_rexw +AssertCompile(_bs3CpuBasic2_iret_rexw_EndProc - _bs3CpuBasic2_iret_rexw == 2) + + +; +; CPU mode agnostic test code snippets. +; +BS3_BEGIN_TEXT32 + +;; +; @param [xBP + xCB*2] puDst +; @param [xBP + xCB*3] uNewValue +BS3_PROC_BEGIN_CMN bs3CpuBasic2_Store_mov, BS3_PBC_NEAR + push xBP + mov xBP, xSP + mov xCX, [xBP + xCB*2] + mov xAX, [xBP + xCB*3] + mov [xCX], xAX + leave + ret +BS3_PROC_END_CMN bs3CpuBasic2_Store_mov + +;; +; @param [xBP + xCB*2] puDst +; @param [xBP + xCB*3] uNewValue +BS3_PROC_BEGIN_CMN bs3CpuBasic2_Store_xchg, BS3_PBC_NEAR + push xBP + mov xBP, xSP + mov xCX, [xBP + xCB*2] + mov xAX, [xBP + xCB*3] + xchg [xCX], xAX + leave + ret +BS3_PROC_END_CMN bs3CpuBasic2_Store_xchg + +;; +; @param [xBP + xCB*2] puDst +; @param [xBP + xCB*3] uNewValue +; @param [xBP + xCB*4] uOldValue +BS3_PROC_BEGIN_CMN bs3CpuBasic2_Store_cmpxchg, BS3_PBC_NEAR + push xBP + mov xBP, xSP + mov xCX, [xBP + xCB*2] + mov xDX, [xBP + xCB*3] + mov xAX, [xBP + xCB*4] +.again: + cmpxchg [xCX], xDX + jnz .again + leave + ret +BS3_PROC_END_CMN bs3CpuBasic2_Store_cmpxchg + + +BS3_BEGIN_TEXT16 + +; +; Instantiate code templates. +; +BS3_INSTANTIATE_COMMON_TEMPLATE "bs3-cpu-basic-2-template.mac" +BS3_INSTANTIATE_TEMPLATE_WITH_WEIRD_ONES "bs3-cpu-basic-2-template.mac" + diff --git a/src/VBox/ValidationKit/bootsectors/bs3-cpu-basic-2-pf.c32 b/src/VBox/ValidationKit/bootsectors/bs3-cpu-basic-2-pf.c32 new file mode 100644 index 00000000..03ad3d99 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3-cpu-basic-2-pf.c32 @@ -0,0 +1,1880 @@ +/* $Id: bs3-cpu-basic-2-pf.c32 $ */ +/** @file + * BS3Kit - bs3-cpu-basic-2, 32-bit C code. + */ + +/* + * Copyright (C) 2007-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include <bs3kit.h> +#include <iprt/asm-amd64-x86.h> + + +/********************************************************************************************************************************* +* Defined Constants And Macros * +*********************************************************************************************************************************/ +#define CHECK_MEMBER(a_pszMode, a_szName, a_szFmt, a_Actual, a_Expected) \ + do { \ + if ((a_Actual) == (a_Expected)) { /* likely */ } \ + else Bs3TestFailedF("%u - %s: " a_szName "=" a_szFmt " expected " a_szFmt, \ + g_usBs3TestStep, (a_pszMode), (a_Actual), (a_Expected)); \ + } while (0) + +#define BS3CPUBASIC2PF_HALT(pThis) \ + do { \ + Bs3TestPrintf("Halting: pteworker=%s store=%s accessor=%s\n", \ + pThis->pszPteWorker, pThis->pszStore, pThis->pszAccessor); \ + ASMHalt(); \ + } while (0) + + +/** @def BS3CPUBASIC2PF_FASTER + * This is useful for IEM execution. */ +#define BS3CPUBASIC2PF_FASTER + + +/********************************************************************************************************************************* +* Structures and Typedefs * +*********************************************************************************************************************************/ +typedef void BS3_CALL FNBS3CPUBASIC2PFSNIPPET(void); + +typedef struct FNBS3CPUBASIC2PFTSTCODE +{ + FNBS3CPUBASIC2PFSNIPPET *pfn; + uint8_t offUd2; + +} FNBS3CPUBASIC2PFTSTCODE; +typedef FNBS3CPUBASIC2PFTSTCODE const *PCFNBS3CPUBASIC2PFTSTCODE; + +typedef struct BS3CPUBASIC2PFTTSTCMNMODE +{ + uint8_t bMode; + FNBS3CPUBASIC2PFTSTCODE MovLoad; + FNBS3CPUBASIC2PFTSTCODE MovStore; + FNBS3CPUBASIC2PFTSTCODE Xchg; + FNBS3CPUBASIC2PFTSTCODE CmpXchg; + FNBS3CPUBASIC2PFTSTCODE DivMem; +} BS3CPUBASIC2PFTTSTCMNMODE; +typedef BS3CPUBASIC2PFTTSTCMNMODE const *PCBS3CPUBASIC2PFTTSTCMNMODE; + + +typedef struct BS3CPUBASIC2PFSTATE +{ + /** The mode we're currently testing. */ + uint8_t bMode; + /** The size of a natural access. */ + uint8_t cbAccess; + /** The common mode functions. */ + PCBS3CPUBASIC2PFTTSTCMNMODE pCmnMode; + /** Address of the test area (alias). */ + union + { + uint64_t u; + uint32_t u32; + uint16_t u16; + } uTestAddr; + /** Pointer to the orignal test area mapping. */ + uint8_t *pbOrgTest; + /** The size of the test area (at least two pages). */ + uint32_t cbTest; + /** cbTest expressed as a page count. */ + uint16_t cTestPages; + /** The number of PTEs in the first PTE, i.e. what we can + * safely access via PgInfo.u.Pae.pPte/PgInfo.u.Legacy.pPte. */ + uint16_t cTest1stPtes; + /** The number of PDEs for cTestPages. */ + uint16_t cTestPdes; + /** 16-bit data selector for uTestAddr.u32. */ + uint16_t uSel16TestData; + /** 16-bit code selector for uTestAddr.u32. */ + uint16_t uSel16TestCode; + /** The size of the PDE backup. */ + uint16_t cbPdeBackup; + /** The size of the PTE backup. */ + uint16_t cbPteBackup; + /** Test paging information for uTestAddr.u. */ + BS3PAGINGINFO4ADDR PgInfo; + + /** Set if we can use the INVLPG instruction. */ + bool fUseInvlPg; + /** Physical addressing width. */ + uint8_t cBitsPhysWidth; + + /** Reflects CR0.WP. */ + bool fWp; + /** Reflects EFER.NXE & CR4.PAE. */ + bool fNxe; + + const char *pszAccessor; + const char *pszPteWorker; + const char *pszStore; + + /** Trap context frame. */ + BS3TRAPFRAME TrapCtx; + /** Expected result context. */ + BS3REGCTX ExpectCtx; + + /** The PML4E backup. */ + uint64_t u64Pml4eBackup; + /** The PDPTE backup. */ + uint64_t u64PdpteBackup; + /** The PDE backup. */ + uint64_t au64PdeBackup[16]; + /** The PTE backup. */ + union + { + uint32_t Legacy[X86_PG_ENTRIES]; + uint64_t Pae[X86_PG_PAE_ENTRIES]; + } PteBackup; + +} BS3CPUBASIC2PFSTATE; +/** Pointer to state for the \#PF test. */ +typedef BS3CPUBASIC2PFSTATE *PBS3CPUBASIC2PFSTATE; + + +/** + * Paging modification worker. + */ +typedef struct BS3CPUBASIC2PFMODPT +{ + const char *pszName; + uint32_t fPresent : 1; + uint32_t fUser : 1; + uint32_t fWriteable : 1; + uint32_t fNoExecute : 1; + uint32_t fReserved : 1; + uint32_t uModifyArg : 24; + void (*pfnModify)(PBS3CPUBASIC2PFSTATE pThis, unsigned iStore, struct BS3CPUBASIC2PFMODPT const *pEntry, + uint32_t fClearMask, uint32_t fSetMask); + bool (*pfnApplicable)(PBS3CPUBASIC2PFSTATE pThis, struct BS3CPUBASIC2PFMODPT const *pEntry); +} BS3CPUBASIC2PFMODPT; +typedef BS3CPUBASIC2PFMODPT const *PCBS3CPUBASIC2PFMODPT; + +/** Page level protection. Alternative is page directory or higher level. */ +#define BS3CB2PFACC_F_PAGE_LEVEL RT_BIT(0) +/** Directly access the boobytrapped page, no edging on or off it. */ +#define BS3CB2PFACC_F_DIRECT RT_BIT(1) + +/** + * Memory accessor. + */ +typedef struct BS3CPUBASIC2PFACCESSOR +{ + /** Accessor name. */ + const char *pszName; + /** The accessor. */ + void (*pfnAccessor)(PBS3CPUBASIC2PFSTATE pThis, PBS3REGCTX pCtx, uint32_t fFlags, uint8_t bXcpt, uint8_t uPfErrCd); + /** The X86_TRAP_PF_XXX access flags this access sets. */ + uint32_t fAccess; + /** The exception when things are fine. */ + uint8_t bOkayXcpt; +} BS3CPUBASIC2PFACCESSOR; +typedef const BS3CPUBASIC2PFACCESSOR *PCBS3CPUBASIC2PFACCESSOR; + + +/********************************************************************************************************************************* +* Internal Functions * +*********************************************************************************************************************************/ +FNBS3TESTDOMODE bs3CpuBasic2_RaiseXcpt0e_c32; + +/* bs3-cpu-basic-2-asm.asm: */ +void BS3_CALL bs3CpuBasic2_Store_mov_c32(void *pvDst, uint32_t uValue, uint32_t uOld); +void BS3_CALL bs3CpuBasic2_Store_xchg_c32(void *pvDst, uint32_t uValue, uint32_t uOld); +void BS3_CALL bs3CpuBasic2_Store_cmpxchg_c32(void *pvDst, uint32_t uValue, uint32_t uOld); + + +/* bs3-cpu-basic-2-template.mac: */ +FNBS3CPUBASIC2PFSNIPPET bs3CpuBasic2_mov_ax_ds_bx__ud2_c16; +FNBS3CPUBASIC2PFSNIPPET bs3CpuBasic2_mov_ds_bx_ax__ud2_c16; +FNBS3CPUBASIC2PFSNIPPET bs3CpuBasic2_xchg_ds_bx_ax__ud2_c16; +FNBS3CPUBASIC2PFSNIPPET bs3CpuBasic2_cmpxchg_ds_bx_cx__ud2_c16; +FNBS3CPUBASIC2PFSNIPPET bs3CpuBasic2_div_ds_bx__ud2_c16; + +FNBS3CPUBASIC2PFSNIPPET bs3CpuBasic2_mov_ax_ds_bx__ud2_c32; +FNBS3CPUBASIC2PFSNIPPET bs3CpuBasic2_mov_ds_bx_ax__ud2_c32; +FNBS3CPUBASIC2PFSNIPPET bs3CpuBasic2_xchg_ds_bx_ax__ud2_c32; +FNBS3CPUBASIC2PFSNIPPET bs3CpuBasic2_cmpxchg_ds_bx_cx__ud2_c32; +FNBS3CPUBASIC2PFSNIPPET bs3CpuBasic2_div_ds_bx__ud2_c32; + +FNBS3CPUBASIC2PFSNIPPET bs3CpuBasic2_mov_ax_ds_bx__ud2_c64; +FNBS3CPUBASIC2PFSNIPPET bs3CpuBasic2_mov_ds_bx_ax__ud2_c64; +FNBS3CPUBASIC2PFSNIPPET bs3CpuBasic2_xchg_ds_bx_ax__ud2_c64; +FNBS3CPUBASIC2PFSNIPPET bs3CpuBasic2_cmpxchg_ds_bx_cx__ud2_c64; +FNBS3CPUBASIC2PFSNIPPET bs3CpuBasic2_div_ds_bx__ud2_c64; + + +/********************************************************************************************************************************* +* Global Variables * +*********************************************************************************************************************************/ +/** Page table access functions. */ +static const struct +{ + const char *pszName; + void (BS3_CALL *pfnStore)(void *pvDst, uint32_t uValue, uint32_t uOld); +} g_aStoreMethods[] = +{ + { "mov", bs3CpuBasic2_Store_mov_c32 }, + { "xchg", bs3CpuBasic2_Store_xchg_c32 }, + { "cmpxchg", bs3CpuBasic2_Store_cmpxchg_c32 }, +}; + + +static const BS3CPUBASIC2PFTTSTCMNMODE g_aCmnModes[] = +{ + { + BS3_MODE_CODE_16, + { bs3CpuBasic2_mov_ax_ds_bx__ud2_c16, 2 }, + { bs3CpuBasic2_mov_ds_bx_ax__ud2_c16, 2 }, + { bs3CpuBasic2_xchg_ds_bx_ax__ud2_c16, 2 }, + { bs3CpuBasic2_cmpxchg_ds_bx_cx__ud2_c16, 3 }, + { bs3CpuBasic2_div_ds_bx__ud2_c16, 2 }, + }, + { + BS3_MODE_CODE_32, + { bs3CpuBasic2_mov_ax_ds_bx__ud2_c32, 2 }, + { bs3CpuBasic2_mov_ds_bx_ax__ud2_c32, 2 }, + { bs3CpuBasic2_xchg_ds_bx_ax__ud2_c32, 2 }, + { bs3CpuBasic2_cmpxchg_ds_bx_cx__ud2_c32, 3 }, + { bs3CpuBasic2_div_ds_bx__ud2_c32, 2 }, + }, + { + BS3_MODE_CODE_64, + { bs3CpuBasic2_mov_ax_ds_bx__ud2_c64, 2 + 1 }, + { bs3CpuBasic2_mov_ds_bx_ax__ud2_c64, 2 + 1 }, + { bs3CpuBasic2_xchg_ds_bx_ax__ud2_c64, 2 + 1 }, + { bs3CpuBasic2_cmpxchg_ds_bx_cx__ud2_c64, 3 + 1 }, + { bs3CpuBasic2_div_ds_bx__ud2_c64, 2 + 1 }, + }, + { + BS3_MODE_CODE_V86, + { bs3CpuBasic2_mov_ax_ds_bx__ud2_c16, 2 }, + { bs3CpuBasic2_mov_ds_bx_ax__ud2_c16, 2 }, + { bs3CpuBasic2_xchg_ds_bx_ax__ud2_c16, 2 }, + { bs3CpuBasic2_cmpxchg_ds_bx_cx__ud2_c16, 3 }, + { bs3CpuBasic2_div_ds_bx__ud2_c16, 2 }, + }, +}; + + +/** + * Compares a CPU trap. + */ +static void bs3CpuBasic2Pf_CompareCtx(PBS3CPUBASIC2PFSTATE pThis, PBS3REGCTX pExpectCtx, int cbPcAdjust, + uint8_t bXcpt, unsigned uErrCd) +{ + const char *pszHint = "xxxx"; + uint16_t const cErrorsBefore = Bs3TestSubErrorCount(); + uint32_t fExtraEfl; + + CHECK_MEMBER(pszHint, "bXcpt", "%#04x", pThis->TrapCtx.bXcpt, bXcpt); + CHECK_MEMBER(pszHint, "uErrCd", "%#06RX16", (uint16_t)pThis->TrapCtx.uErrCd, (uint16_t)uErrCd); /* 486 only writes a word */ + + fExtraEfl = X86_EFL_RF; + if (BS3_MODE_IS_16BIT_SYS(g_bBs3CurrentMode)) + fExtraEfl = 0; + else + fExtraEfl = X86_EFL_RF; + Bs3TestCheckRegCtxEx(&pThis->TrapCtx.Ctx, pExpectCtx, cbPcAdjust, 0 /*cbSpAdjust*/, fExtraEfl, pszHint, g_usBs3TestStep); + if (Bs3TestSubErrorCount() != cErrorsBefore) + { + Bs3TrapPrintFrame(&pThis->TrapCtx); +#if 1 + Bs3TestPrintf("Halting: g_uBs3CpuDetected=%#x\n", g_uBs3CpuDetected); + Bs3TestPrintf("Halting: bXcpt=%#x uErrCd=%#x\n", bXcpt, uErrCd); + BS3CPUBASIC2PF_HALT(pThis); +#endif + } +} + + +/** + * Compares a CPU trap. + */ +static void bs3CpuBasic2Pf_CompareSimpleCtx(PBS3CPUBASIC2PFSTATE pThis, PBS3REGCTX pStartCtx, int offAddPC, + uint8_t bXcpt, unsigned uErrCd, uint64_t uCr2) +{ + const char *pszHint = "xxxx"; + uint16_t const cErrorsBefore = Bs3TestSubErrorCount(); + uint64_t const uSavedCr2 = pStartCtx->cr2.u; + uint32_t fExtraEfl; + + CHECK_MEMBER(pszHint, "bXcpt", "%#04x", pThis->TrapCtx.bXcpt, bXcpt); + CHECK_MEMBER(pszHint, "uErrCd", "%#06RX16", (uint16_t)pThis->TrapCtx.uErrCd, (uint16_t)uErrCd); /* 486 only writes a word */ + + fExtraEfl = X86_EFL_RF; + if (BS3_MODE_IS_16BIT_SYS(g_bBs3CurrentMode)) + fExtraEfl = 0; + else + fExtraEfl = X86_EFL_RF; + pStartCtx->cr2.u = uCr2; + Bs3TestCheckRegCtxEx(&pThis->TrapCtx.Ctx, pStartCtx, offAddPC, 0 /*cbSpAdjust*/, fExtraEfl, pszHint, g_usBs3TestStep); + pStartCtx->cr2.u = uSavedCr2; + if (Bs3TestSubErrorCount() != cErrorsBefore) + { + Bs3TrapPrintFrame(&pThis->TrapCtx); +#if 1 + Bs3TestPrintf("Halting: g_uBs3CpuDetected=%#x\n", g_uBs3CpuDetected); + Bs3TestPrintf("Halting: bXcpt=%#x uErrCd=%#x\n", bXcpt, uErrCd); + BS3CPUBASIC2PF_HALT(pThis); +#endif + } +} + + +/** + * Checks the trap context for a simple \#PF trap. + */ +static void bs3CpuBasic2Pf_CompareSimplePf(PBS3CPUBASIC2PFSTATE pThis, PCBS3REGCTX pStartCtx, int offAddPC, + unsigned uErrCd, uint64_t uCr2) +{ + bs3CpuBasic2Pf_CompareSimpleCtx(pThis, (PBS3REGCTX)pStartCtx, offAddPC, X86_XCPT_PF, uErrCd, uCr2); +} + +/** + * Checks the trap context for a simple \#UD trap. + */ +static void bs3CpuBasic2Pf_CompareSimpleUd(PBS3CPUBASIC2PFSTATE pThis, PCBS3REGCTX pStartCtx, int offAddPC) +{ + bs3CpuBasic2Pf_CompareSimpleCtx(pThis, (PBS3REGCTX)pStartCtx, offAddPC, X86_XCPT_UD, 0, pStartCtx->cr2.u); +} + + +/** + * Restores all the paging entries from backup and flushes everything. + */ +static void bs3CpuBasic2Pf_FlushAll(void) +{ + if ((g_uBs3CpuDetected & BS3CPU_TYPE_MASK) >= BS3CPU_80486) + { + uint32_t uCr4 = ASMGetCR4(); + if (uCr4 & (X86_CR4_PGE | X86_CR4_PCIDE)) + { + ASMSetCR4(uCr4 & ~(X86_CR4_PGE | X86_CR4_PCIDE)); + ASMSetCR4(uCr4); + return; + } + } + + ASMReloadCR3(); +} + + +/** + * Restores all the paging entries from backup and flushes everything. + * + * @param pThis Test state data. + */ +static void bs3CpuBasic2Pf_RestoreFromBackups(PBS3CPUBASIC2PFSTATE pThis) +{ + Bs3MemCpy(pThis->PgInfo.u.Legacy.pPte, &pThis->PteBackup, pThis->cbPteBackup); + Bs3MemCpy(pThis->PgInfo.u.Legacy.pPde, pThis->au64PdeBackup, pThis->cbPdeBackup); + if (pThis->PgInfo.cEntries > 2) + pThis->PgInfo.u.Pae.pPdpe->u = pThis->u64PdpteBackup; + if (pThis->PgInfo.cEntries > 3) + pThis->PgInfo.u.Pae.pPml4e->u = pThis->u64Pml4eBackup; + bs3CpuBasic2Pf_FlushAll(); +} + + +/** @name BS3CPUBASIC2PFACCESSOR::pfnAccessor Implementations + * @{ */ + +static void bs3CpuBasic2Pf_DoExec(PBS3CPUBASIC2PFSTATE pThis, PBS3REGCTX pCtx, uint32_t fFlags, uint8_t bXcpt, uint8_t uPfErrCd) +{ + uint8_t *pbOrgTest = pThis->pbOrgTest; + unsigned offEnd = fFlags & BS3CB2PFACC_F_DIRECT ? X86_PAGE_SIZE + 1 : X86_PAGE_SIZE + 2; + unsigned off = fFlags & BS3CB2PFACC_F_DIRECT ? offEnd - 1 : X86_PAGE_SIZE - 5; + + for (; off < offEnd; off++) + { + /* Emit a little bit of code (using the original allocation mapping) and point pCtx to it. */ + pbOrgTest[off + 0] = X86_OP_PRF_SIZE_ADDR; + pbOrgTest[off + 1] = X86_OP_PRF_SIZE_OP; + pbOrgTest[off + 2] = 0x90; /* NOP */ + pbOrgTest[off + 3] = 0x0f; /* UD2 */ + pbOrgTest[off + 4] = 0x0b; + pbOrgTest[off + 5] = 0xeb; /* JMP $-4 */ + pbOrgTest[off + 6] = 0xfc; + switch (pThis->bMode & BS3_MODE_CODE_MASK) + { + default: + pCtx->rip.u = pThis->uTestAddr.u + off; + break; + case BS3_MODE_CODE_16: + Bs3SelSetup16BitCode(&Bs3GdteSpare01, pThis->uTestAddr.u32, pCtx->bCpl); + pCtx->rip.u = off; + pCtx->cs = BS3_SEL_SPARE_01 | pCtx->bCpl; + break; + case BS3_MODE_CODE_V86: + /** @todo fix me. */ + return; + } + //Bs3TestPrintf("cs:rip=%04x:%010RX64 iRing=%d\n", pCtx->cs, pCtx->rip.u, pCtx->bCpl); + + Bs3TrapSetJmpAndRestore(pCtx, &pThis->TrapCtx); + //Bs3TestPrintf("off=%#06x bXcpt=%#x uErrCd=%#RX64\n", off, pThis->TrapCtx.bXcpt, pThis->TrapCtx.uErrCd); + if ( bXcpt != X86_XCPT_PF + || ((fFlags & BS3CB2PFACC_F_PAGE_LEVEL) && off < X86_PAGE_SIZE - 4)) + bs3CpuBasic2Pf_CompareSimpleUd(pThis, pCtx, 3); + else if (!(fFlags & BS3CB2PFACC_F_PAGE_LEVEL) || off >= X86_PAGE_SIZE) + bs3CpuBasic2Pf_CompareSimplePf(pThis, pCtx, 0, uPfErrCd, pThis->uTestAddr.u + off); + else + bs3CpuBasic2Pf_CompareSimplePf(pThis, pCtx, + off + 3 == X86_PAGE_SIZE || off + 4 == X86_PAGE_SIZE + ? RT_MIN(X86_PAGE_SIZE, off + 3) - off : 0, + uPfErrCd, pThis->uTestAddr.u + RT_MIN(X86_PAGE_SIZE, off + 4)); + } +} + + +static void bs3CpuBasic2Pf_SetCsEip(PBS3CPUBASIC2PFSTATE pThis, PBS3REGCTX pCtx, PCFNBS3CPUBASIC2PFTSTCODE pCode) +{ + switch (pThis->bMode & BS3_MODE_CODE_MASK) + { + default: + pCtx->rip.u = (uintptr_t)pCode->pfn; + break; + + case BS3_MODE_CODE_16: + { + uint32_t uFar16 = Bs3SelFlatCodeToProtFar16((uintptr_t)pCode->pfn); + pCtx->rip.u = (uint16_t)uFar16; + pCtx->cs = (uint16_t)(uFar16 >> 16) | pCtx->bCpl; + pCtx->cs += (uint16_t)pCtx->bCpl << BS3_SEL_RING_SHIFT; + break; + } + + case BS3_MODE_CODE_V86: + { + uint32_t uFar16 = Bs3SelFlatCodeToRealMode((uintptr_t)pCode->pfn); + pCtx->rip.u = (uint16_t)uFar16; + pCtx->cs = (uint16_t)(uFar16 >> 16); + break; + } + } +} + + +/** + * Test a simple load instruction around the edges of page two. + * + * @param pThis The test stat data. + * @param pCtx The test context. + * @param fFlags BS3CB2PFACC_F_XXX. + * @param bXcpt X86_XCPT_PF if this can cause \#PFs, otherwise + * X86_XCPT_UD. + * @param uPfErrCd The error code for \#PFs. + */ +static void bs3CpuBasic2Pf_DoMovLoad(PBS3CPUBASIC2PFSTATE pThis, PBS3REGCTX pCtx, uint32_t fFlags, uint8_t bXcpt, uint8_t uPfErrCd) +{ + static uint64_t const s_uValue = UINT64_C(0x7c4d0114428d); + uint64_t uExpectRax; + unsigned i; + + /* + * Adjust the incoming context and calculate our expections. + */ + bs3CpuBasic2Pf_SetCsEip(pThis, pCtx, &pThis->pCmnMode->MovLoad); + Bs3MemCpy(&pThis->ExpectCtx, pCtx, sizeof(pThis->ExpectCtx)); + switch (pThis->bMode & BS3_MODE_CODE_MASK) + { + case BS3_MODE_CODE_16: + case BS3_MODE_CODE_V86: + uExpectRax = (uint16_t)s_uValue | (pCtx->rax.u & UINT64_C(0xffffffffffff0000)); + break; + case BS3_MODE_CODE_32: + uExpectRax = (uint32_t)s_uValue | (pCtx->rax.u & UINT64_C(0xffffffff00000000)); + break; + case BS3_MODE_CODE_64: + uExpectRax = s_uValue; + break; + } + if (uExpectRax == pCtx->rax.u) + pCtx->rax.u = ~pCtx->rax.u; + + /* + * Make two approaches to the test page (the 2nd one): + * - i=0: Start on the 1st page and edge into the 2nd. + * - i=1: Start at the end of the 2nd page and edge off it and into the 3rd. + */ + for (i = 0; i < 2; i++) + { + unsigned off = fFlags & BS3CB2PFACC_F_DIRECT ? X86_PAGE_SIZE : X86_PAGE_SIZE * (i + 1) - pThis->cbAccess; + unsigned offEnd = fFlags & BS3CB2PFACC_F_DIRECT ? off + 1 : X86_PAGE_SIZE * (i + 1) + (i == 0 ? 8 : 7); + + for (; off < offEnd; off++) + { + *(uint64_t *)&pThis->pbOrgTest[off] = s_uValue; + if (BS3_MODE_IS_16BIT_CODE(pThis->bMode)) + pThis->ExpectCtx.rbx.u = pCtx->rbx.u = off; + else + pThis->ExpectCtx.rbx.u = pCtx->rbx.u = pThis->uTestAddr.u + off; + + Bs3TrapSetJmpAndRestore(pCtx, &pThis->TrapCtx); + //Bs3TestPrintf("off=%#06x bXcpt=%#x uErrCd=%#RX64\n", off, pThis->TrapCtx.bXcpt, pThis->TrapCtx.uErrCd); + + if ( bXcpt != X86_XCPT_PF + || ((fFlags & BS3CB2PFACC_F_PAGE_LEVEL) && off >= X86_PAGE_SIZE * 2) + || ((fFlags & BS3CB2PFACC_F_PAGE_LEVEL) && off <= X86_PAGE_SIZE - pThis->cbAccess) ) + { + pThis->ExpectCtx.rax.u = uExpectRax; + bs3CpuBasic2Pf_CompareCtx(pThis, &pThis->ExpectCtx, pThis->pCmnMode->MovLoad.offUd2, X86_XCPT_UD, 0 /*uErrCd*/); + pThis->ExpectCtx.rax = pCtx->rax; + } + else + { + if (off < X86_PAGE_SIZE) + pThis->ExpectCtx.cr2.u = pThis->uTestAddr.u + X86_PAGE_SIZE; + else + pThis->ExpectCtx.cr2.u = pThis->uTestAddr.u + off; + bs3CpuBasic2Pf_CompareCtx(pThis, &pThis->ExpectCtx, 0 /*cbPcAdjust*/, bXcpt, uPfErrCd); + pThis->ExpectCtx.cr2 = pCtx->cr2; + } + } + + if (fFlags & BS3CB2PFACC_F_DIRECT) + break; + } +} + + +/** + * Test a simple store instruction around the edges of page two. + * + * @param pThis The test stat data. + * @param pCtx The test context. + * @param fFlags BS3CB2PFACC_F_XXX. + * @param bXcpt X86_XCPT_PF if this can cause \#PFs, otherwise + * X86_XCPT_UD. + * @param uPfErrCd The error code for \#PFs. + */ +static void bs3CpuBasic2Pf_DoMovStore(PBS3CPUBASIC2PFSTATE pThis, PBS3REGCTX pCtx, uint32_t fFlags, + uint8_t bXcpt, uint8_t uPfErrCd) +{ + static uint64_t const s_uValue = UINT64_C(0x3af45ead86a34a26); + static uint64_t const s_uValueFlipped = UINT64_C(0xc50ba152795cb5d9); + uint64_t const uRaxSaved = pCtx->rax.u; + uint64_t uExpectStored; + unsigned i; + + /* + * Adjust the incoming context and calculate our expections. + */ + bs3CpuBasic2Pf_SetCsEip(pThis, pCtx, &pThis->pCmnMode->MovStore); + if ((pThis->bMode & BS3_MODE_CODE_MASK) != BS3_MODE_CODE_64) + pCtx->rax.u = (uint32_t)s_uValue; /* leave the upper part zero */ + else + pCtx->rax.u = s_uValue; + + Bs3MemCpy(&pThis->ExpectCtx, pCtx, sizeof(pThis->ExpectCtx)); + switch (pThis->bMode & BS3_MODE_CODE_MASK) + { + case BS3_MODE_CODE_16: + case BS3_MODE_CODE_V86: + uExpectStored = (uint16_t)s_uValue | (s_uValueFlipped & UINT64_C(0xffffffffffff0000)); + break; + case BS3_MODE_CODE_32: + uExpectStored = (uint32_t)s_uValue | (s_uValueFlipped & UINT64_C(0xffffffff00000000)); + break; + case BS3_MODE_CODE_64: + uExpectStored = s_uValue; + break; + } + + /* + * Make two approaches to the test page (the 2nd one): + * - i=0: Start on the 1st page and edge into the 2nd. + * - i=1: Start at the end of the 2nd page and edge off it and into the 3rd. + */ + for (i = 0; i < 2; i++) + { + unsigned off = fFlags & BS3CB2PFACC_F_DIRECT ? X86_PAGE_SIZE : X86_PAGE_SIZE * (i + 1) - pThis->cbAccess; + unsigned offEnd = fFlags & BS3CB2PFACC_F_DIRECT ? off + 1 : X86_PAGE_SIZE * (i + 1) + (i == 0 ? 8 : 7); + for (; off < offEnd; off++) + { + *(uint64_t *)&pThis->pbOrgTest[off] = s_uValueFlipped; + if (BS3_MODE_IS_16BIT_CODE(pThis->bMode)) + pThis->ExpectCtx.rbx.u = pCtx->rbx.u = off; + else + pThis->ExpectCtx.rbx.u = pCtx->rbx.u = pThis->uTestAddr.u + off; + + Bs3TrapSetJmpAndRestore(pCtx, &pThis->TrapCtx); + //Bs3TestPrintf("off=%#06x bXcpt=%#x uErrCd=%#RX64\n", off, pThis->TrapCtx.bXcpt, pThis->TrapCtx.uErrCd); + + if ( bXcpt != X86_XCPT_PF + || ((fFlags & BS3CB2PFACC_F_PAGE_LEVEL) && off >= X86_PAGE_SIZE * 2) + || ((fFlags & BS3CB2PFACC_F_PAGE_LEVEL) && off <= X86_PAGE_SIZE - pThis->cbAccess) ) + { + bs3CpuBasic2Pf_CompareCtx(pThis, &pThis->ExpectCtx, pThis->pCmnMode->MovStore.offUd2, X86_XCPT_UD, 0 /*uErrCd*/); + if (*(uint64_t *)&pThis->pbOrgTest[off] != uExpectStored) + Bs3TestFailedF("%u - %s: Stored %#RX64, expected %#RX64", + g_usBs3TestStep, "xxxx", *(uint64_t *)&pThis->pbOrgTest[off], uExpectStored); + } + else + { + if (off < X86_PAGE_SIZE) + pThis->ExpectCtx.cr2.u = pThis->uTestAddr.u + X86_PAGE_SIZE; + else + pThis->ExpectCtx.cr2.u = pThis->uTestAddr.u + off; + bs3CpuBasic2Pf_CompareCtx(pThis, &pThis->ExpectCtx, 0 /*cbPcAdjust*/, bXcpt, uPfErrCd); + pThis->ExpectCtx.cr2 = pCtx->cr2; + if (*(uint64_t *)&pThis->pbOrgTest[off] != s_uValueFlipped) + Bs3TestFailedF("%u - %s: #PF'ed store modified memory: %#RX64, expected %#RX64", + g_usBs3TestStep, "xxxx", *(uint64_t *)&pThis->pbOrgTest[off], s_uValueFlipped); + + } + } + + if (fFlags & BS3CB2PFACC_F_DIRECT) + break; + } + + pCtx->rax.u = uRaxSaved; +} + + +/** + * Test a xchg instruction around the edges of page two. + * + * @param pThis The test stat data. + * @param pCtx The test context. + * @param fFlags BS3CB2PFACC_F_XXX. + * @param bXcpt X86_XCPT_PF if this can cause \#PFs, otherwise + * X86_XCPT_UD. + * @param uPfErrCd The error code for \#PFs. + */ +static void bs3CpuBasic2Pf_DoXchg(PBS3CPUBASIC2PFSTATE pThis, PBS3REGCTX pCtx, uint32_t fFlags, uint8_t bXcpt, uint8_t uPfErrCd) +{ + static uint64_t const s_uValue = UINT64_C(0xea58699648e2f32c); + static uint64_t const s_uValueFlipped = UINT64_C(0x15a79669b71d0cd3); + uint64_t const uRaxSaved = pCtx->rax.u; + uint64_t uRaxIn; + uint64_t uExpectedRax; + uint64_t uExpectStored; + unsigned i; + + /* + * Adjust the incoming context and calculate our expections. + */ + bs3CpuBasic2Pf_SetCsEip(pThis, pCtx, &pThis->pCmnMode->Xchg); + if ((pThis->bMode & BS3_MODE_CODE_MASK) != BS3_MODE_CODE_64) + uRaxIn = (uint32_t)s_uValue; /* leave the upper part zero */ + else + uRaxIn = s_uValue; + + Bs3MemCpy(&pThis->ExpectCtx, pCtx, sizeof(pThis->ExpectCtx)); + switch (pThis->bMode & BS3_MODE_CODE_MASK) + { + case BS3_MODE_CODE_16: + case BS3_MODE_CODE_V86: + uExpectedRax = (uint16_t)s_uValueFlipped | (uRaxIn & UINT64_C(0xffffffffffff0000)); + uExpectStored = (uint16_t)s_uValue | (s_uValueFlipped & UINT64_C(0xffffffffffff0000)); + break; + case BS3_MODE_CODE_32: + uExpectedRax = (uint32_t)s_uValueFlipped | (uRaxIn & UINT64_C(0xffffffff00000000)); + uExpectStored = (uint32_t)s_uValue | (s_uValueFlipped & UINT64_C(0xffffffff00000000)); + break; + case BS3_MODE_CODE_64: + uExpectedRax = s_uValueFlipped; + uExpectStored = s_uValue; + break; + } + + /* + * Make two approaches to the test page (the 2nd one): + * - i=0: Start on the 1st page and edge into the 2nd. + * - i=1: Start at the end of the 2nd page and edge off it and into the 3rd. + */ + for (i = 0; i < 2; i++) + { + unsigned off = fFlags & BS3CB2PFACC_F_DIRECT ? X86_PAGE_SIZE : X86_PAGE_SIZE * (i + 1) - pThis->cbAccess; + unsigned offEnd = fFlags & BS3CB2PFACC_F_DIRECT ? off + 1 : X86_PAGE_SIZE * (i + 1) + (i == 0 ? 8 : 7); + for (; off < offEnd; off++) + { + *(uint64_t *)&pThis->pbOrgTest[off] = s_uValueFlipped; + pCtx->rax.u = uRaxIn; + if (BS3_MODE_IS_16BIT_CODE(pThis->bMode)) + pThis->ExpectCtx.rbx.u = pCtx->rbx.u = off; + else + pThis->ExpectCtx.rbx.u = pCtx->rbx.u = pThis->uTestAddr.u + off; + + Bs3TrapSetJmpAndRestore(pCtx, &pThis->TrapCtx); + //Bs3TestPrintf("off=%#06x bXcpt=%#x uErrCd=%#RX64\n", off, pThis->TrapCtx.bXcpt, pThis->TrapCtx.uErrCd); + + if ( bXcpt != X86_XCPT_PF + || ((fFlags & BS3CB2PFACC_F_PAGE_LEVEL) && off >= X86_PAGE_SIZE * 2) + || ((fFlags & BS3CB2PFACC_F_PAGE_LEVEL) && off <= X86_PAGE_SIZE - pThis->cbAccess) ) + { + pThis->ExpectCtx.rax.u = uExpectedRax; + bs3CpuBasic2Pf_CompareCtx(pThis, &pThis->ExpectCtx, pThis->pCmnMode->Xchg.offUd2, X86_XCPT_UD, 0 /*uErrCd*/); + if (*(uint64_t *)&pThis->pbOrgTest[off] != uExpectStored) + Bs3TestFailedF("%u - %s: Stored %#RX64, expected %#RX64", + g_usBs3TestStep, "xxxx", *(uint64_t *)&pThis->pbOrgTest[off], uExpectStored); + } + else + { + pThis->ExpectCtx.rax.u = uRaxIn; + if (off < X86_PAGE_SIZE) + pThis->ExpectCtx.cr2.u = pThis->uTestAddr.u + X86_PAGE_SIZE; + else + pThis->ExpectCtx.cr2.u = pThis->uTestAddr.u + off; + bs3CpuBasic2Pf_CompareCtx(pThis, &pThis->ExpectCtx, 0 /*cbPcAdjust*/, bXcpt, uPfErrCd); + pThis->ExpectCtx.cr2 = pCtx->cr2; + if (*(uint64_t *)&pThis->pbOrgTest[off] != s_uValueFlipped) + Bs3TestFailedF("%u - %s: #PF'ed store modified memory: %#RX64, expected %#RX64", + g_usBs3TestStep, "xxxx", *(uint64_t *)&pThis->pbOrgTest[off], s_uValueFlipped); + } + } + + if (fFlags & BS3CB2PFACC_F_DIRECT) + break; + } + + pCtx->rax.u = uRaxSaved; +} + + +/** + * Test a cmpxchg instruction around the edges of page two. + * + * @param pThis The test stat data. + * @param pCtx The test context. + * @param fFlags BS3CB2PFACC_F_XXX. + * @param bXcpt X86_XCPT_PF if this can cause \#PFs, otherwise + * X86_XCPT_UD. + * @param uPfErrCd The error code for \#PFs. + * @param fMissmatch Whether to fail and not store (@c true), or succeed + * and do the store. + */ +static void bs3CpuBasic2Pf_DoCmpXchg(PBS3CPUBASIC2PFSTATE pThis, PBS3REGCTX pCtx, uint32_t fFlags, + uint8_t bXcpt, uint8_t uPfErrCd, bool fMissmatch) +{ + static uint64_t const s_uValue = UINT64_C(0xea58699648e2f32c); + static uint64_t const s_uValueFlipped = UINT64_C(0x15a79669b71d0cd3); + static uint64_t const s_uValueOther = UINT64_C(0x2171239bcb044c81); + uint64_t const uRaxSaved = pCtx->rax.u; + uint64_t const uRcxSaved = pCtx->rcx.u; + uint64_t uRaxIn; + uint64_t uExpectedRax; + uint32_t uExpectedFlags; + uint64_t uExpectStored; + unsigned i; + + /* + * Adjust the incoming context and calculate our expections. + * Hint: CMPXCHG [xBX],xCX ; xAX compare and update implicit, ZF set to !fMissmatch. + */ + bs3CpuBasic2Pf_SetCsEip(pThis, pCtx, &pThis->pCmnMode->CmpXchg); + if ((pThis->bMode & BS3_MODE_CODE_MASK) != BS3_MODE_CODE_64) + { + uRaxIn = (uint32_t)(fMissmatch ? s_uValueOther : s_uValueFlipped); /* leave the upper part zero */ + pCtx->rcx.u = (uint32_t)s_uValue; /* ditto */ + } + else + { + uRaxIn = fMissmatch ? s_uValueOther : s_uValueFlipped; + pCtx->rcx.u = s_uValue; + } + if (fMissmatch) + pCtx->rflags.u32 |= X86_EFL_ZF; + else + pCtx->rflags.u32 &= ~X86_EFL_ZF; + + Bs3MemCpy(&pThis->ExpectCtx, pCtx, sizeof(pThis->ExpectCtx)); + uExpectedFlags = pCtx->rflags.u32 & ~(X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_SF | X86_EFL_OF | X86_EFL_ZF); + switch (pThis->bMode & BS3_MODE_CODE_MASK) + { + case BS3_MODE_CODE_16: + case BS3_MODE_CODE_V86: + uExpectedRax = (uint16_t)s_uValueFlipped | (uRaxIn & UINT64_C(0xffffffffffff0000)); + uExpectStored = (uint16_t)s_uValue | (s_uValueFlipped & UINT64_C(0xffffffffffff0000)); + uExpectedFlags |= !fMissmatch ? X86_EFL_ZF | X86_EFL_PF : X86_EFL_AF; + break; + case BS3_MODE_CODE_32: + uExpectedRax = (uint32_t)s_uValueFlipped | (uRaxIn & UINT64_C(0xffffffff00000000)); + uExpectStored = (uint32_t)s_uValue | (s_uValueFlipped & UINT64_C(0xffffffff00000000)); + uExpectedFlags |= !fMissmatch ? X86_EFL_ZF | X86_EFL_PF : X86_EFL_AF; + break; + case BS3_MODE_CODE_64: + uExpectedRax = s_uValueFlipped; + uExpectStored = s_uValue; + uExpectedFlags |= !fMissmatch ? X86_EFL_ZF | X86_EFL_PF : X86_EFL_AF; + break; + } + if (fMissmatch) + uExpectStored = s_uValueFlipped; + + /* + * Make two approaches to the test page (the 2nd one): + * - i=0: Start on the 1st page and edge into the 2nd. + * - i=1: Start at the end of the 2nd page and edge off it and into the 3rd. + */ + for (i = 0; i < 2; i++) + { + unsigned off = fFlags & BS3CB2PFACC_F_DIRECT ? X86_PAGE_SIZE : X86_PAGE_SIZE * (i + 1) - pThis->cbAccess; + unsigned offEnd = fFlags & BS3CB2PFACC_F_DIRECT ? off + 1 : X86_PAGE_SIZE * (i + 1) + (i == 0 ? 8 : 7); + for (; off < offEnd; off++) + { + *(uint64_t *)&pThis->pbOrgTest[off] = s_uValueFlipped; + pCtx->rax.u = uRaxIn; + if (BS3_MODE_IS_16BIT_CODE(pThis->bMode)) + pThis->ExpectCtx.rbx.u = pCtx->rbx.u = off; + else + pThis->ExpectCtx.rbx.u = pCtx->rbx.u = pThis->uTestAddr.u + off; + + Bs3TrapSetJmpAndRestore(pCtx, &pThis->TrapCtx); + //Bs3TestPrintf("off=%#06x bXcpt=%#x uErrCd=%#RX64\n", off, pThis->TrapCtx.bXcpt, pThis->TrapCtx.uErrCd); + + if ( bXcpt != X86_XCPT_PF + || ((fFlags & BS3CB2PFACC_F_PAGE_LEVEL) && off >= X86_PAGE_SIZE * 2) + || ((fFlags & BS3CB2PFACC_F_PAGE_LEVEL) && off <= X86_PAGE_SIZE - pThis->cbAccess) ) + { + pThis->ExpectCtx.rax.u = uExpectedRax; + pThis->ExpectCtx.rflags.u32 = uExpectedFlags; + bs3CpuBasic2Pf_CompareCtx(pThis, &pThis->ExpectCtx, pThis->pCmnMode->CmpXchg.offUd2, X86_XCPT_UD, 0 /*uErrCd*/); + if (*(uint64_t *)&pThis->pbOrgTest[off] != uExpectStored) + Bs3TestFailedF("%u - %s: Stored %#RX64, expected %#RX64", + g_usBs3TestStep, "xxxx", *(uint64_t *)&pThis->pbOrgTest[off], uExpectStored); + } + else + { + pThis->ExpectCtx.rax.u = uRaxIn; + pThis->ExpectCtx.rflags = pCtx->rflags; + if (off < X86_PAGE_SIZE) + pThis->ExpectCtx.cr2.u = pThis->uTestAddr.u + X86_PAGE_SIZE; + else + pThis->ExpectCtx.cr2.u = pThis->uTestAddr.u + off; + bs3CpuBasic2Pf_CompareCtx(pThis, &pThis->ExpectCtx, 0 /*cbPcAdjust*/, bXcpt, uPfErrCd); + pThis->ExpectCtx.cr2 = pCtx->cr2; + if (*(uint64_t *)&pThis->pbOrgTest[off] != s_uValueFlipped) + Bs3TestFailedF("%u - %s: #PF'ed store modified memory: %#RX64, expected %#RX64", + g_usBs3TestStep, "xxxx", *(uint64_t *)&pThis->pbOrgTest[off], s_uValueFlipped); + } + } + + if (fFlags & BS3CB2PFACC_F_DIRECT) + break; + } + + pCtx->rax.u = uRaxSaved; + pCtx->rcx.u = uRcxSaved; +} + + +static void bs3CpuBasic2Pf_DoCmpXchgMiss(PBS3CPUBASIC2PFSTATE pThis, PBS3REGCTX pCtx, uint32_t fFlags, + uint8_t bXcpt, uint8_t uPfErrCd) +{ + bs3CpuBasic2Pf_DoCmpXchg(pThis, pCtx, fFlags, bXcpt, uPfErrCd, true /*fMissmatch*/ ); +} + + +static void bs3CpuBasic2Pf_DoCmpXchgMatch(PBS3CPUBASIC2PFSTATE pThis, PBS3REGCTX pCtx, uint32_t fFlags, + uint8_t bXcpt, uint8_t uPfErrCd) +{ + bs3CpuBasic2Pf_DoCmpXchg(pThis, pCtx, fFlags, bXcpt, uPfErrCd , false /*fMissmatch*/ ); +} + + +/** + * @interface_method_impl{BS3CPUBASIC2PFACCESSOR,pfnAccessor, + * DIV [MEM=0] for checking the accessed bit} + */ +static void bs3CpuBasic2Pf_DoDivByZero(PBS3CPUBASIC2PFSTATE pThis, PBS3REGCTX pCtx, uint32_t fFlags, + uint8_t bXcpt, uint8_t uPfErrCd) +{ + static uint64_t const s_uFiller = UINT64_C(0x9856703711f4069e); + uint64_t uZeroAndFill; + unsigned i; + + /* + * Adjust the incoming context and calculate our expections. + */ + bs3CpuBasic2Pf_SetCsEip(pThis, pCtx, &pThis->pCmnMode->DivMem); + + Bs3MemCpy(&pThis->ExpectCtx, pCtx, sizeof(pThis->ExpectCtx)); + switch (pThis->bMode & BS3_MODE_CODE_MASK) + { + case BS3_MODE_CODE_16: + case BS3_MODE_CODE_V86: + uZeroAndFill = s_uFiller & UINT64_C(0xffffffffffff0000); + break; + case BS3_MODE_CODE_32: + uZeroAndFill = s_uFiller & UINT64_C(0xffffffff00000000); + break; + case BS3_MODE_CODE_64: + uZeroAndFill = 0; + break; + } + + /* + * Make two approaches to the test page (the 2nd one): + * - i=0: Start on the 1st page and edge into the 2nd. + * - i=1: Start at the end of the 2nd page and edge off it and into the 3rd. + */ + for (i = 0; i < 2; i++) + { + unsigned off = fFlags & BS3CB2PFACC_F_DIRECT ? X86_PAGE_SIZE : X86_PAGE_SIZE * (i + 1) - pThis->cbAccess; + unsigned offEnd = fFlags & BS3CB2PFACC_F_DIRECT ? off + 1 : X86_PAGE_SIZE * (i + 1) + (i == 0 ? 8 : 7); + for (; off < offEnd; off++) + { + *(uint64_t *)&pThis->pbOrgTest[off] = uZeroAndFill; + if (BS3_MODE_IS_16BIT_CODE(pThis->bMode)) + pThis->ExpectCtx.rbx.u = pCtx->rbx.u = off; + else + pThis->ExpectCtx.rbx.u = pCtx->rbx.u = pThis->uTestAddr.u + off; + + Bs3TrapSetJmpAndRestore(pCtx, &pThis->TrapCtx); + //if (pThis->bMode == BS3_MODE_PP16_32) Bs3TestPrintf("off=%#06x bXcpt=%#x uErrCd=%#RX64\n", off, pThis->TrapCtx.bXcpt, pThis->TrapCtx.uErrCd); + + if ( bXcpt != X86_XCPT_PF + || ((fFlags & BS3CB2PFACC_F_PAGE_LEVEL) && off >= X86_PAGE_SIZE * 2) + || ((fFlags & BS3CB2PFACC_F_PAGE_LEVEL) && off <= X86_PAGE_SIZE - pThis->cbAccess) ) + { + bs3CpuBasic2Pf_CompareCtx(pThis, &pThis->ExpectCtx, 0 /*cbPcAdjust*/, X86_XCPT_DE, 0 /*uErrCd*/); + if (*(uint64_t *)&pThis->pbOrgTest[off] != uZeroAndFill) + Bs3TestFailedF("%u - %s: Modified source op: %#RX64, expected %#RX64", + g_usBs3TestStep, "xxxx", *(uint64_t *)&pThis->pbOrgTest[off], uZeroAndFill); + } + else + { + if (off < X86_PAGE_SIZE) + pThis->ExpectCtx.cr2.u = pThis->uTestAddr.u + X86_PAGE_SIZE; + else + pThis->ExpectCtx.cr2.u = pThis->uTestAddr.u + off; + bs3CpuBasic2Pf_CompareCtx(pThis, &pThis->ExpectCtx, 0 /*cbPcAdjust*/, bXcpt, uPfErrCd); + pThis->ExpectCtx.cr2 = pCtx->cr2; + if (*(uint64_t *)&pThis->pbOrgTest[off] != uZeroAndFill) + Bs3TestFailedF("%u - %s: Modified source op: %#RX64, expected %#RX64", + g_usBs3TestStep, "xxxx", *(uint64_t *)&pThis->pbOrgTest[off], uZeroAndFill); + } + } + + if (fFlags & BS3CB2PFACC_F_DIRECT) + break; + } +} + + +static BS3CPUBASIC2PFACCESSOR const g_aAccessors[] = +{ + { "DoExec", bs3CpuBasic2Pf_DoExec, X86_TRAP_PF_ID, X86_XCPT_UD }, + { "DoMovLoad", bs3CpuBasic2Pf_DoMovLoad, 0, X86_XCPT_UD }, + { "DoMovStore", bs3CpuBasic2Pf_DoMovStore, X86_TRAP_PF_RW, X86_XCPT_UD }, + { "DoXchg", bs3CpuBasic2Pf_DoXchg, X86_TRAP_PF_RW, X86_XCPT_UD }, + { "DoCmpXchgMiss", bs3CpuBasic2Pf_DoCmpXchgMiss, X86_TRAP_PF_RW, X86_XCPT_UD }, + { "DoCmpXhcgMatch", bs3CpuBasic2Pf_DoCmpXchgMatch, X86_TRAP_PF_RW, X86_XCPT_UD }, + { "DoDivByZero", bs3CpuBasic2Pf_DoDivByZero, 0, X86_XCPT_DE }, +}; + +/** @} */ + + +/** @name BS3CPUBASIC2PFMODPT::pfnModify implementations. + * @{ */ + + +static void bs3CpuBasic2Pf_ClearMask(PBS3CPUBASIC2PFSTATE pThis, unsigned iStore, PCBS3CPUBASIC2PFMODPT pEntry, + uint32_t fClearMask, uint32_t fSetMask) +{ + if (pThis->PgInfo.cbEntry == 4) + { + uint32_t const uOrg = pThis->PteBackup.Legacy[1]; + uint32_t uNew = ((uOrg & ~fClearMask) | fSetMask) & ~(uint32_t)pEntry->uModifyArg; + uint32_t const uOld = pThis->PgInfo.u.Legacy.pPte[1].u; + g_aStoreMethods[iStore].pfnStore(pThis->PgInfo.u.Legacy.pPte + 1, uNew, uOld); + } + else + { + uint64_t const uOrg = pThis->PteBackup.Pae[1]; + uint64_t uNew = ((uOrg & ~(uint64_t)fClearMask) | fSetMask) & ~(uint64_t)pEntry->uModifyArg; + uint64_t const uOld = pThis->PgInfo.u.Pae.pPte[1].u; + + g_aStoreMethods[iStore].pfnStore(&pThis->PgInfo.u.Pae.pPte[1].au32[0], (uint32_t)uNew, (uint32_t)uOld); + if ((uint32_t)(uNew >> 32) != (uint32_t)(uOld >> 32)) + g_aStoreMethods[iStore].pfnStore(&pThis->PgInfo.u.Pae.pPte[1].au32[1], + (uint32_t)(uNew >> 32), (uint32_t)(uOld >> 32)); + } +} + +static void bs3CpuBasic2Pf_SetBit(PBS3CPUBASIC2PFSTATE pThis, unsigned iStore, PCBS3CPUBASIC2PFMODPT pEntry, + uint32_t fClearMask, uint32_t fSetMask) +{ + if (pThis->PgInfo.cbEntry == 4) + { + uint32_t const uOrg = pThis->PteBackup.Legacy[1]; + uint32_t uNew = (uOrg & ~fClearMask) | fSetMask | RT_BIT_32(pEntry->uModifyArg); + uint32_t const uOld = pThis->PgInfo.u.Legacy.pPte[1].u; + g_aStoreMethods[iStore].pfnStore(pThis->PgInfo.u.Legacy.pPte + 1, uNew, uOld); + } + else + { + uint64_t const uOrg = pThis->PteBackup.Pae[1]; + uint64_t uNew = ((uOrg & ~(uint64_t)fClearMask) | fSetMask) | RT_BIT_64(pEntry->uModifyArg); + uint64_t const uOld = pThis->PgInfo.u.Pae.pPte[1].u; + + if (pEntry->uModifyArg < 32 || (uint32_t)uNew != (uint32_t)uOld) + g_aStoreMethods[iStore].pfnStore(&pThis->PgInfo.u.Pae.pPte[1].au32[0], (uint32_t)uNew, (uint32_t)uOld); + if (pEntry->uModifyArg >= 32 || (uint32_t)(uNew >> 32) != (uint32_t)(uOld >> 32)) + g_aStoreMethods[iStore].pfnStore(&pThis->PgInfo.u.Pae.pPte[1].au32[1], + (uint32_t)(uNew >> 32), (uint32_t)(uOld >> 32)); + } +} + +static void bs3CpuBasic2Pf_NoChange(PBS3CPUBASIC2PFSTATE pThis, unsigned iStore, PCBS3CPUBASIC2PFMODPT pEntry, + uint32_t fClearMask, uint32_t fSetMask) +{ + if (pThis->PgInfo.cbEntry == 4) + { + uint32_t const uOrg = pThis->PteBackup.Legacy[1]; + uint32_t uNew = (uOrg & ~fClearMask) | fSetMask; + uint32_t const uOld = pThis->PgInfo.u.Legacy.pPte[1].u; + if (uNew != uOld) + g_aStoreMethods[iStore].pfnStore(&pThis->PgInfo.u.Legacy.pPte[1], uNew, uOld); + } + else + { + uint64_t const uOrg = pThis->PteBackup.Pae[1]; + uint64_t uNew = (uOrg & ~(uint64_t)fClearMask) | fSetMask; + uint64_t const uOld = pThis->PgInfo.u.Pae.pPte[1].u; + if (uNew != uOld) + { + if ((uint32_t)uNew != (uint32_t)uOld) + g_aStoreMethods[iStore].pfnStore(&pThis->PgInfo.u.Pae.pPte[1].au32[0], (uint32_t)uNew, (uint32_t)uOld); + if ((uint32_t)(uNew >> 32) != (uint32_t)(uOld >> 32)) + g_aStoreMethods[iStore].pfnStore(&pThis->PgInfo.u.Pae.pPte[1].au32[1], + (uint32_t)(uNew >> 32), (uint32_t)(uOld >> 32)); + } + } +} + +/** @} */ + + +/** @name BS3CPUBASIC2PFMODPT::pfnApplicable implementations. + * @{ */ + +static bool bs3CpuBasic2Pf_IsPteBitReserved(PBS3CPUBASIC2PFSTATE pThis, PCBS3CPUBASIC2PFMODPT pEntry) +{ + if (pThis->PgInfo.cbEntry == 8) + { + /* Bits 52..63 or 62 (NXE=1). */ + if (pThis->PgInfo.cEntries == 3) + { + if ((uint32_t)(pEntry->uModifyArg - 52U) < (uint32_t)(12 - pThis->fNxe)) + return true; + } + else if (pEntry->uModifyArg == 63 && !pThis->fNxe) + return true; + + /* Reserved physical address bits. */ + if (pEntry->uModifyArg < 52) + { + if ((uint32_t)pEntry->uModifyArg >= (uint32_t)pThis->cBitsPhysWidth) + return true; + } + } + return false; +} + +static bool bs3CpuBasic2Pf_IsPteBitSoftwareUsable(PBS3CPUBASIC2PFSTATE pThis, PCBS3CPUBASIC2PFMODPT pEntry) +{ + if (pThis->PgInfo.cbEntry == 8) + { + if (pThis->PgInfo.cEntries != 3) + { + if ((uint32_t)(pEntry->uModifyArg - 52U) < (uint32_t)11) + return true; + } + } + return false; +} + + +static bool bs3CpuBasic2Pf_IsNxe(PBS3CPUBASIC2PFSTATE pThis, PCBS3CPUBASIC2PFMODPT pEntry) +{ + return pThis->fNxe && pThis->PgInfo.cbEntry == 8; +} + +/** @} */ + + +static const BS3CPUBASIC2PFMODPT g_aPteWorkers[] = +{ +/* { pszName, P U W NX RSV ModiyfArg pfnModify, pfnApplicable }, */ + { "org", 1, 1, 1, 0, 0, 0, bs3CpuBasic2Pf_NoChange, NULL }, + { "!US", 1, 0, 1, 0, 0, X86_PTE_US, bs3CpuBasic2Pf_ClearMask, NULL }, + { "!RW", 1, 1, 0, 0, 0, X86_PTE_RW, bs3CpuBasic2Pf_ClearMask, NULL }, + { "!RW+!US", 1, 0, 0, 0, 0, X86_PTE_RW | X86_PTE_US, bs3CpuBasic2Pf_ClearMask, NULL }, + { "!P", 0, 0, 0, 0, 0, X86_PTE_P, bs3CpuBasic2Pf_ClearMask, NULL }, + { "NX", 1, 1, 1, 1, 0, 63, bs3CpuBasic2Pf_SetBit, bs3CpuBasic2Pf_IsNxe }, + { "RSVPH[32]", 0, 0, 0, 0, 1, 32, bs3CpuBasic2Pf_SetBit, bs3CpuBasic2Pf_IsPteBitReserved }, + { "RSVPH[33]", 0, 0, 0, 0, 1, 33, bs3CpuBasic2Pf_SetBit, bs3CpuBasic2Pf_IsPteBitReserved }, + { "RSVPH[34]", 0, 0, 0, 0, 1, 34, bs3CpuBasic2Pf_SetBit, bs3CpuBasic2Pf_IsPteBitReserved }, + { "RSVPH[35]", 0, 0, 0, 0, 1, 35, bs3CpuBasic2Pf_SetBit, bs3CpuBasic2Pf_IsPteBitReserved }, + { "RSVPH[36]", 0, 0, 0, 0, 1, 36, bs3CpuBasic2Pf_SetBit, bs3CpuBasic2Pf_IsPteBitReserved }, + { "RSVPH[37]", 0, 0, 0, 0, 1, 37, bs3CpuBasic2Pf_SetBit, bs3CpuBasic2Pf_IsPteBitReserved }, + { "RSVPH[38]", 0, 0, 0, 0, 1, 38, bs3CpuBasic2Pf_SetBit, bs3CpuBasic2Pf_IsPteBitReserved }, + { "RSVPH[39]", 0, 0, 0, 0, 1, 39, bs3CpuBasic2Pf_SetBit, bs3CpuBasic2Pf_IsPteBitReserved }, + { "RSVPH[40]", 0, 0, 0, 0, 1, 40, bs3CpuBasic2Pf_SetBit, bs3CpuBasic2Pf_IsPteBitReserved }, + { "RSVPH[41]", 0, 0, 0, 0, 1, 41, bs3CpuBasic2Pf_SetBit, bs3CpuBasic2Pf_IsPteBitReserved }, + { "RSVPH[42]", 0, 0, 0, 0, 1, 42, bs3CpuBasic2Pf_SetBit, bs3CpuBasic2Pf_IsPteBitReserved }, + { "RSVPH[43]", 0, 0, 0, 0, 1, 43, bs3CpuBasic2Pf_SetBit, bs3CpuBasic2Pf_IsPteBitReserved }, + { "RSVPH[44]", 0, 0, 0, 0, 1, 44, bs3CpuBasic2Pf_SetBit, bs3CpuBasic2Pf_IsPteBitReserved }, + { "RSVPH[45]", 0, 0, 0, 0, 1, 45, bs3CpuBasic2Pf_SetBit, bs3CpuBasic2Pf_IsPteBitReserved }, + { "RSVPH[46]", 0, 0, 0, 0, 1, 46, bs3CpuBasic2Pf_SetBit, bs3CpuBasic2Pf_IsPteBitReserved }, + { "RSVPH[47]", 0, 0, 0, 0, 1, 47, bs3CpuBasic2Pf_SetBit, bs3CpuBasic2Pf_IsPteBitReserved }, + { "RSVPH[48]", 0, 0, 0, 0, 1, 48, bs3CpuBasic2Pf_SetBit, bs3CpuBasic2Pf_IsPteBitReserved }, + { "RSVPH[49]", 0, 0, 0, 0, 1, 49, bs3CpuBasic2Pf_SetBit, bs3CpuBasic2Pf_IsPteBitReserved }, + { "RSVPH[50]", 0, 0, 0, 0, 1, 50, bs3CpuBasic2Pf_SetBit, bs3CpuBasic2Pf_IsPteBitReserved }, + { "RSVPH[51]", 0, 0, 0, 0, 1, 51, bs3CpuBasic2Pf_SetBit, bs3CpuBasic2Pf_IsPteBitReserved }, + { "RSV[52]", 0, 0, 0, 0, 1, 52, bs3CpuBasic2Pf_SetBit, bs3CpuBasic2Pf_IsPteBitReserved }, + { "RSV[53]", 0, 0, 0, 0, 1, 53, bs3CpuBasic2Pf_SetBit, bs3CpuBasic2Pf_IsPteBitReserved }, + { "RSV[54]", 0, 0, 0, 0, 1, 54, bs3CpuBasic2Pf_SetBit, bs3CpuBasic2Pf_IsPteBitReserved }, + { "RSV[55]", 0, 0, 0, 0, 1, 55, bs3CpuBasic2Pf_SetBit, bs3CpuBasic2Pf_IsPteBitReserved }, + { "RSV[56]", 0, 0, 0, 0, 1, 56, bs3CpuBasic2Pf_SetBit, bs3CpuBasic2Pf_IsPteBitReserved }, + { "RSV[57]", 0, 0, 0, 0, 1, 57, bs3CpuBasic2Pf_SetBit, bs3CpuBasic2Pf_IsPteBitReserved }, + { "RSV[58]", 0, 0, 0, 0, 1, 58, bs3CpuBasic2Pf_SetBit, bs3CpuBasic2Pf_IsPteBitReserved }, + { "RSV[59]", 0, 0, 0, 0, 1, 59, bs3CpuBasic2Pf_SetBit, bs3CpuBasic2Pf_IsPteBitReserved }, + { "RSV[60]", 0, 0, 0, 0, 1, 60, bs3CpuBasic2Pf_SetBit, bs3CpuBasic2Pf_IsPteBitReserved }, + { "RSV[61]", 0, 0, 0, 0, 1, 61, bs3CpuBasic2Pf_SetBit, bs3CpuBasic2Pf_IsPteBitReserved }, + { "RSV[62]", 0, 0, 0, 0, 1, 62, bs3CpuBasic2Pf_SetBit, bs3CpuBasic2Pf_IsPteBitReserved }, + { "RSV[62]", 0, 0, 0, 0, 1, 62, bs3CpuBasic2Pf_SetBit, bs3CpuBasic2Pf_IsPteBitReserved }, + { "RSV[63]", 0, 0, 0, 0, 1, 63, bs3CpuBasic2Pf_SetBit, bs3CpuBasic2Pf_IsPteBitReserved }, + { "!RSV[52]", 1, 1, 1, 0, 0, 52, bs3CpuBasic2Pf_SetBit, bs3CpuBasic2Pf_IsPteBitSoftwareUsable }, + { "!RSV[53]", 1, 1, 1, 0, 0, 53, bs3CpuBasic2Pf_SetBit, bs3CpuBasic2Pf_IsPteBitSoftwareUsable }, + { "!RSV[54]", 1, 1, 1, 0, 0, 54, bs3CpuBasic2Pf_SetBit, bs3CpuBasic2Pf_IsPteBitSoftwareUsable }, + { "!RSV[55]", 1, 1, 1, 0, 0, 55, bs3CpuBasic2Pf_SetBit, bs3CpuBasic2Pf_IsPteBitSoftwareUsable }, + { "!RSV[56]", 1, 1, 1, 0, 0, 56, bs3CpuBasic2Pf_SetBit, bs3CpuBasic2Pf_IsPteBitSoftwareUsable }, + { "!RSV[57]", 1, 1, 1, 0, 0, 57, bs3CpuBasic2Pf_SetBit, bs3CpuBasic2Pf_IsPteBitSoftwareUsable }, + { "!RSV[58]", 1, 1, 1, 0, 0, 58, bs3CpuBasic2Pf_SetBit, bs3CpuBasic2Pf_IsPteBitSoftwareUsable }, + { "!RSV[59]", 1, 1, 1, 0, 0, 59, bs3CpuBasic2Pf_SetBit, bs3CpuBasic2Pf_IsPteBitSoftwareUsable }, + { "!RSV[60]", 1, 1, 1, 0, 0, 60, bs3CpuBasic2Pf_SetBit, bs3CpuBasic2Pf_IsPteBitSoftwareUsable }, + { "!RSV[61]", 1, 1, 1, 0, 0, 61, bs3CpuBasic2Pf_SetBit, bs3CpuBasic2Pf_IsPteBitSoftwareUsable }, + { "!RSV[62]", 1, 1, 1, 0, 0, 62, bs3CpuBasic2Pf_SetBit, bs3CpuBasic2Pf_IsPteBitSoftwareUsable }, + +}; + + +/** + * Worker for bs3CpuBasic2_RaiseXcpt0e_c32 that does the actual testing. + * + * Caller does all the cleaning up. + * + * @returns Error count. + * @param pThis Test state data. + * @param fNxe Whether NX is enabled. + */ +static uint8_t bs3CpuBasic2_RaiseXcpt0eWorker(PBS3CPUBASIC2PFSTATE register pThis, bool const fWp, bool const fNxe) +{ + unsigned iLevel; + unsigned iRing; + unsigned iStore; + unsigned iAccessor; + unsigned iOuter; + unsigned cPml4Tests; + unsigned cPdPtrTests; + uint32_t const fPfIdMask = fNxe ? UINT32_MAX : ~X86_TRAP_PF_ID; + BS3REGCTX aCtxts[4]; + + pThis->fWp = fWp; + pThis->fNxe = fNxe; + + /** @todo figure out V8086 testing. */ + if ((pThis->bMode & BS3_MODE_CODE_MASK) == BS3_MODE_CODE_V86) + return BS3TESTDOMODE_SKIPPED; + + + /* paranoia: Touch the various big stack structures to ensure the compiler has allocated stack for them. */ + for (iRing = 0; iRing < RT_ELEMENTS(aCtxts); iRing++) + Bs3MemZero(&aCtxts[iRing], sizeof(aCtxts[iRing])); + + /* + * Set up a few contexts for testing this stuff. + */ + Bs3RegCtxSaveEx(&aCtxts[0], pThis->bMode, 2048); + for (iRing = 1; iRing < 4; iRing++) + { + aCtxts[iRing] = aCtxts[0]; + Bs3RegCtxConvertToRingX(&aCtxts[iRing], iRing); + } + + if (!BS3_MODE_IS_16BIT_CODE(pThis->bMode)) + { + for (iRing = 0; iRing < 4; iRing++) + aCtxts[iRing].rbx.u = pThis->uTestAddr.u; + } + else + { + for (iRing = 0; iRing < 4; iRing++) + { + aCtxts[iRing].ds = pThis->uSel16TestData; + aCtxts[iRing].rbx.u = 0; + } + } + + /* + * Check basic operation: + */ + for (iRing = 0; iRing < 4; iRing++) + for (iAccessor = 0; iAccessor < RT_ELEMENTS(g_aAccessors); iAccessor++) + g_aAccessors[iAccessor].pfnAccessor(pThis, &aCtxts[iRing], BS3CB2PFACC_F_PAGE_LEVEL, X86_XCPT_UD, UINT8_MAX); + + /* + * Some PTE checks. We only mess with the 2nd page. + */ + for (iOuter = 0; iOuter < 2; iOuter++) + { + uint32_t const fAccessor = (iOuter == 0 ? BS3CB2PFACC_F_DIRECT : 0) | BS3CB2PFACC_F_PAGE_LEVEL; + unsigned iPteWrk; + + bs3CpuBasic2Pf_FlushAll(); + for (iPteWrk = 0; iPteWrk < RT_ELEMENTS(g_aPteWorkers); iPteWrk++) + { + BS3CPUBASIC2PFMODPT EffWrk; + const BS3CPUBASIC2PFMODPT *pPteWrk = &g_aPteWorkers[iPteWrk]; + if (pPteWrk->pfnApplicable && !pPteWrk->pfnApplicable(pThis, pPteWrk)) + continue; + + pThis->pszPteWorker = pPteWrk->pszName; + + EffWrk = *pPteWrk; + +#if 1 + /* + * Do the modification once, then test all different accesses + * without flushing the TLB or anything in-between. + */ + for (iStore = 0; iStore < RT_ELEMENTS(g_aStoreMethods); iStore++) + { + pThis->pszStore = g_aStoreMethods[iStore].pszName; + pPteWrk->pfnModify(pThis, iStore, pPteWrk, 0, 0); + + for (iRing = 0; iRing < 4; iRing++) + { + PBS3REGCTX const pCtx = &aCtxts[iRing]; + if ( EffWrk.fReserved + || !EffWrk.fPresent + || (!EffWrk.fUser && iRing == 3)) + { + uint32_t const fPfBase = ( EffWrk.fReserved ? X86_TRAP_PF_P | X86_TRAP_PF_RSVD + : EffWrk.fPresent ? X86_TRAP_PF_P : 0) + | (iRing == 3 ? X86_TRAP_PF_US : 0); + for (iAccessor = 0; iAccessor < RT_ELEMENTS(g_aAccessors); iAccessor++) + { + pThis->pszAccessor = g_aAccessors[iAccessor].pszName; + g_aAccessors[iAccessor].pfnAccessor(pThis, pCtx, fAccessor, X86_XCPT_PF, + fPfBase | (g_aAccessors[iAccessor].fAccess & fPfIdMask)); + } + } + else + { + uint32_t const fPfBase = X86_TRAP_PF_P | (iRing == 3 ? X86_TRAP_PF_US : 0); + for (iAccessor = 0; iAccessor < RT_ELEMENTS(g_aAccessors); iAccessor++) + { + pThis->pszAccessor = g_aAccessors[iAccessor].pszName; + if ( ( (g_aAccessors[iAccessor].fAccess & X86_TRAP_PF_ID) + && EffWrk.fNoExecute) + || ( (g_aAccessors[iAccessor].fAccess & X86_TRAP_PF_RW) + && !EffWrk.fWriteable + && (fWp || iRing == 3)) ) + g_aAccessors[iAccessor].pfnAccessor(pThis, pCtx, fAccessor, X86_XCPT_PF, + fPfBase | (g_aAccessors[iAccessor].fAccess & fPfIdMask)); + else + g_aAccessors[iAccessor].pfnAccessor(pThis, pCtx, fAccessor, X86_XCPT_UD, UINT8_MAX); + } + } + } + + /* Reset the paging + full flush. */ + bs3CpuBasic2Pf_RestoreFromBackups(pThis); + } +#endif + +#define CHECK_AD_BITS(a_fExpectedAD) \ + do { \ + uint32_t fActualAD = ( pThis->PgInfo.cbEntry == 8 \ + ? pThis->PgInfo.u.Pae.pPte[1].au32[0] : pThis->PgInfo.u.Legacy.pPte[1].au32[0]) \ + & (X86_PTE_A | X86_PTE_D); \ + if (fActualAD != (a_fExpectedAD)) \ + { \ + Bs3TestFailedF("%u - %s/%u: unexpected A/D bits: %#x, expected %#x\n", \ + g_usBs3TestStep, "xxxx", __LINE__, fActualAD, a_fExpectedAD); \ + BS3CPUBASIC2PF_HALT(pThis); \ + } \ + } while (0) + + /* + * Again, but redoing everything for each accessor. + */ + for (iStore = 0; iStore < RT_ELEMENTS(g_aStoreMethods); iStore++) + { + pThis->pszStore = g_aStoreMethods[iStore].pszName; + + for (iRing = 0; iRing < 4; iRing++) + { + PBS3REGCTX const pCtx = &aCtxts[iRing]; + + if ( EffWrk.fReserved + || !EffWrk.fPresent + || (!EffWrk.fUser && iRing == 3)) + { + uint32_t const fPfBase = ( EffWrk.fReserved ? X86_TRAP_PF_P | X86_TRAP_PF_RSVD + : EffWrk.fPresent ? X86_TRAP_PF_P : 0) + | (iRing == 3 ? X86_TRAP_PF_US : 0); + for (iAccessor = 0; iAccessor < RT_ELEMENTS(g_aAccessors); iAccessor++) + { + pThis->pszAccessor = g_aAccessors[iAccessor].pszName; + + pPteWrk->pfnModify(pThis, iStore, pPteWrk, 0, 0); + g_aAccessors[iAccessor].pfnAccessor(pThis, pCtx, fAccessor, X86_XCPT_PF, + fPfBase | (g_aAccessors[iAccessor].fAccess & fPfIdMask)); + CHECK_AD_BITS(0); + bs3CpuBasic2Pf_RestoreFromBackups(pThis); + + pPteWrk->pfnModify(pThis, iStore, pPteWrk, X86_PTE_A | X86_PTE_D, 0); + g_aAccessors[iAccessor].pfnAccessor(pThis, pCtx, fAccessor, X86_XCPT_PF, + fPfBase | (g_aAccessors[iAccessor].fAccess & fPfIdMask)); + CHECK_AD_BITS(0); + bs3CpuBasic2Pf_RestoreFromBackups(pThis); + } + } + else + { + uint32_t const fPfBase = X86_TRAP_PF_P | (iRing == 3 ? X86_TRAP_PF_US : 0); + for (iAccessor = 0; iAccessor < RT_ELEMENTS(g_aAccessors); iAccessor++) + { + pThis->pszAccessor = g_aAccessors[iAccessor].pszName; + if ( ( (g_aAccessors[iAccessor].fAccess & X86_TRAP_PF_ID) + && EffWrk.fNoExecute) + || ( (g_aAccessors[iAccessor].fAccess & X86_TRAP_PF_RW) + && !EffWrk.fWriteable + && (fWp || iRing == 3)) ) + { + uint32_t const fErrCd = fPfBase | (g_aAccessors[iAccessor].fAccess & fPfIdMask); + + pPteWrk->pfnModify(pThis, iStore, pPteWrk, X86_PTE_A | X86_PTE_D, 0); + g_aAccessors[iAccessor].pfnAccessor(pThis, pCtx, fAccessor, X86_XCPT_PF, fErrCd); + CHECK_AD_BITS(0); + bs3CpuBasic2Pf_RestoreFromBackups(pThis); + + pPteWrk->pfnModify(pThis, iStore, pPteWrk, 0, X86_PTE_A | X86_PTE_D); + g_aAccessors[iAccessor].pfnAccessor(pThis, pCtx, fAccessor, X86_XCPT_PF, fErrCd); + CHECK_AD_BITS(X86_PTE_A | X86_PTE_D); + bs3CpuBasic2Pf_RestoreFromBackups(pThis); + + pPteWrk->pfnModify(pThis, iStore, pPteWrk, X86_PTE_A, X86_PTE_D); + g_aAccessors[iAccessor].pfnAccessor(pThis, pCtx, fAccessor, X86_XCPT_PF, fErrCd); + CHECK_AD_BITS(X86_PTE_D); + bs3CpuBasic2Pf_RestoreFromBackups(pThis); + + pPteWrk->pfnModify(pThis, iStore, pPteWrk, X86_PTE_D, X86_PTE_A); + g_aAccessors[iAccessor].pfnAccessor(pThis, pCtx, fAccessor, X86_XCPT_PF, fErrCd); + CHECK_AD_BITS(X86_PTE_A); + bs3CpuBasic2Pf_RestoreFromBackups(pThis); + } + else + { + uint32_t const fExpectedAD = (g_aAccessors[iAccessor].fAccess & X86_TRAP_PF_RW) + ? X86_PTE_A | X86_PTE_D : X86_PTE_A; + + pPteWrk->pfnModify(pThis, iStore, pPteWrk, X86_PTE_A | X86_PTE_D, 0); + g_aAccessors[iAccessor].pfnAccessor(pThis, pCtx, fAccessor, X86_XCPT_UD, UINT8_MAX); + CHECK_AD_BITS(fExpectedAD); + bs3CpuBasic2Pf_RestoreFromBackups(pThis); + + pPteWrk->pfnModify(pThis, iStore, pPteWrk, 0, X86_PTE_A | X86_PTE_D); + g_aAccessors[iAccessor].pfnAccessor(pThis, pCtx, fAccessor, X86_XCPT_UD, UINT8_MAX); + CHECK_AD_BITS(X86_PTE_A | X86_PTE_D); + bs3CpuBasic2Pf_RestoreFromBackups(pThis); + + pPteWrk->pfnModify(pThis, iStore, pPteWrk, X86_PTE_A, X86_PTE_D); + g_aAccessors[iAccessor].pfnAccessor(pThis, pCtx, fAccessor, X86_XCPT_UD, UINT8_MAX); + CHECK_AD_BITS(fExpectedAD | X86_PTE_D); + bs3CpuBasic2Pf_RestoreFromBackups(pThis); + + pPteWrk->pfnModify(pThis, iStore, pPteWrk, X86_PTE_D, X86_PTE_A); + g_aAccessors[iAccessor].pfnAccessor(pThis, pCtx, fAccessor, X86_XCPT_UD, UINT8_MAX); + CHECK_AD_BITS(fExpectedAD | X86_PTE_A); + bs3CpuBasic2Pf_RestoreFromBackups(pThis); + } + } + } + } + } + + /* + * Again, but using invalidate page. + */ + if (pThis->fUseInvlPg) + { + bs3CpuBasic2Pf_RestoreFromBackups(pThis); + + for (iStore = 0; iStore < RT_ELEMENTS(g_aStoreMethods); iStore++) + { + pThis->pszStore = g_aStoreMethods[iStore].pszName; + + for (iRing = 0; iRing < 4; iRing++) + { + PBS3REGCTX const pCtx = &aCtxts[iRing]; + + if ( EffWrk.fReserved + || !EffWrk.fPresent + || (!EffWrk.fUser && iRing == 3)) + { + uint32_t const fPfBase = ( EffWrk.fReserved ? X86_TRAP_PF_P | X86_TRAP_PF_RSVD + : EffWrk.fPresent ? X86_TRAP_PF_P : 0) + | (iRing == 3 ? X86_TRAP_PF_US : 0); + for (iAccessor = 0; iAccessor < RT_ELEMENTS(g_aAccessors); iAccessor++) + { + pThis->pszAccessor = g_aAccessors[iAccessor].pszName; + + pPteWrk->pfnModify(pThis, iStore, pPteWrk, 0, 0); + ASMInvalidatePage(pThis->uTestAddr.u + X86_PAGE_SIZE); + g_aAccessors[iAccessor].pfnAccessor(pThis, pCtx, fAccessor, X86_XCPT_PF, + fPfBase | (g_aAccessors[iAccessor].fAccess & fPfIdMask)); + CHECK_AD_BITS(0); + + pPteWrk->pfnModify(pThis, iStore, pPteWrk, X86_PTE_A | X86_PTE_D, 0); + ASMInvalidatePage(pThis->uTestAddr.u + X86_PAGE_SIZE); + g_aAccessors[iAccessor].pfnAccessor(pThis, pCtx, fAccessor, X86_XCPT_PF, + fPfBase | (g_aAccessors[iAccessor].fAccess & fPfIdMask)); + CHECK_AD_BITS(0); + } + } + else + { + uint32_t const fPfBase = X86_TRAP_PF_P | (iRing == 3 ? X86_TRAP_PF_US : 0); + for (iAccessor = 0; iAccessor < RT_ELEMENTS(g_aAccessors); iAccessor++) + { + pThis->pszAccessor = g_aAccessors[iAccessor].pszName; + if ( ( (g_aAccessors[iAccessor].fAccess & X86_TRAP_PF_ID) + && EffWrk.fNoExecute) + || ( (g_aAccessors[iAccessor].fAccess & X86_TRAP_PF_RW) + && !EffWrk.fWriteable + && (fWp || iRing == 3)) ) + { + uint32_t const fErrCd = fPfBase | (g_aAccessors[iAccessor].fAccess & fPfIdMask); + + pPteWrk->pfnModify(pThis, iStore, pPteWrk, X86_PTE_A | X86_PTE_D, 0); + ASMInvalidatePage(pThis->uTestAddr.u + X86_PAGE_SIZE); + g_aAccessors[iAccessor].pfnAccessor(pThis, pCtx, fAccessor, X86_XCPT_PF, fErrCd); + CHECK_AD_BITS(0); + + pPteWrk->pfnModify(pThis, iStore, pPteWrk, 0, X86_PTE_A | X86_PTE_D); + ASMInvalidatePage(pThis->uTestAddr.u + X86_PAGE_SIZE); + g_aAccessors[iAccessor].pfnAccessor(pThis, pCtx, fAccessor, X86_XCPT_PF, fErrCd); + CHECK_AD_BITS(X86_PTE_A | X86_PTE_D); + + pPteWrk->pfnModify(pThis, iStore, pPteWrk, X86_PTE_A, X86_PTE_D); + ASMInvalidatePage(pThis->uTestAddr.u + X86_PAGE_SIZE); + g_aAccessors[iAccessor].pfnAccessor(pThis, pCtx, fAccessor, X86_XCPT_PF, fErrCd); + CHECK_AD_BITS(X86_PTE_D); + + pPteWrk->pfnModify(pThis, iStore, pPteWrk, X86_PTE_D, X86_PTE_A); + ASMInvalidatePage(pThis->uTestAddr.u + X86_PAGE_SIZE); + g_aAccessors[iAccessor].pfnAccessor(pThis, pCtx, fAccessor, X86_XCPT_PF, fErrCd); + CHECK_AD_BITS(X86_PTE_A); + } + else + { + uint32_t const fExpectedAD = (g_aAccessors[iAccessor].fAccess & X86_TRAP_PF_RW) + ? X86_PTE_A | X86_PTE_D : X86_PTE_A; + + pPteWrk->pfnModify(pThis, iStore, pPteWrk, X86_PTE_A | X86_PTE_D, 0); + ASMInvalidatePage(pThis->uTestAddr.u + X86_PAGE_SIZE); + g_aAccessors[iAccessor].pfnAccessor(pThis, pCtx, fAccessor, X86_XCPT_UD, UINT8_MAX); + CHECK_AD_BITS(fExpectedAD); + + pPteWrk->pfnModify(pThis, iStore, pPteWrk, 0, X86_PTE_A | X86_PTE_D); + ASMInvalidatePage(pThis->uTestAddr.u + X86_PAGE_SIZE); + g_aAccessors[iAccessor].pfnAccessor(pThis, pCtx, fAccessor, X86_XCPT_UD, UINT8_MAX); + CHECK_AD_BITS(X86_PTE_A | X86_PTE_D); + + pPteWrk->pfnModify(pThis, iStore, pPteWrk, X86_PTE_A, X86_PTE_D); + ASMInvalidatePage(pThis->uTestAddr.u + X86_PAGE_SIZE); + g_aAccessors[iAccessor].pfnAccessor(pThis, pCtx, fAccessor, X86_XCPT_UD, UINT8_MAX); + CHECK_AD_BITS(fExpectedAD | X86_PTE_D); + + pPteWrk->pfnModify(pThis, iStore, pPteWrk, X86_PTE_D, X86_PTE_A); + ASMInvalidatePage(pThis->uTestAddr.u + X86_PAGE_SIZE); + g_aAccessors[iAccessor].pfnAccessor(pThis, pCtx, fAccessor, X86_XCPT_UD, UINT8_MAX); + CHECK_AD_BITS(fExpectedAD | X86_PTE_A); + } + } + } + } + } + + bs3CpuBasic2Pf_RestoreFromBackups(pThis); + } + } + } + + + /* + * Do all 4 paging levels. We start out with full access to the page and + * restrict it in various ways. + * + * (On the final level we only mess with the 2nd page for now.) + */ + cPdPtrTests = 1; + cPml4Tests = 1; + if (pThis->uTestAddr.u >= UINT64_C(0x8000000000)) + { + cPml4Tests = 2; + cPdPtrTests = 2; + } + else if (pThis->PgInfo.cEntries == 3) + cPdPtrTests = 2; + +#if 0 + /* Loop 1: Accessor flags. */ + for (iOuter = 0; iOuter < 2; iOuter++) + { + uint32_t const fAccessor = (iOuter == 0 ? BS3CB2PFACC_F_DIRECT : 0) | BS3CB2PFACC_F_PAGE_LEVEL; + + /* Loop 2: Paging store method. */ + for (iStore = 0; iStore < RT_ELEMENTS(g_aStoreMethods); iStore++) + { + unsigned iPml4Test; + int8_t cReserved = 0; + int8_t cNotPresent = 0; + int8_t cNotWrite = 0; + int8_t cNotUser = 0; + int8_t cExecute = 0; + + /* Loop 3: Page map level 4 */ + for (iPml4Test = 0; iPml4Test < cPml4Tests; iPml4Test++) + { + unsigned iPdPtrTest; + + /* Loop 4: Page directory pointer table. */ + for (iPdPtrTest = 0; iPdPtrTest < cPdPtrTests; iPdPtrTest++) + { + unsigned iPdTest; + + /* Loop 5: Page directory. */ + for (iPdTest = 0; iPdTest < 2; iPdTest++) + { + unsigned iPtTest; + + /* Loop 6: Page table. */ + for (iPtTest = 0; iPtTest < 2; iPtTest++) + { + /* Loop 7: Accessor ring. */ + for (iRing = 0; iRing < 4; iRing++) + { + PBS3REGCTX const pCtx = &aCtxts[iRing]; + + if ( EffWrk.fReserved + || !EffWrk.fPresent + || (!EffWrk.fUser && iRing == 3)) + { + uint32_t const fPfBase = ( EffWrk.fReserved ? X86_TRAP_PF_P | X86_TRAP_PF_RSVD + : EffWrk.fPresent ? X86_TRAP_PF_P : 0) + | (iRing == 3 ? X86_TRAP_PF_US : 0); + for (iAccessor = 0; iAccessor < RT_ELEMENTS(g_aAccessors); iAccessor++) + { + pThis->pszAccessor = g_aAccessors[iAccessor].pszName; + + pPteWrk->pfnModify(pThis, iStore, pPteWrk, 0, 0); + ASMInvalidatePage(pThis->uTestAddr.u + X86_PAGE_SIZE); + g_aAccessors[iAccessor].pfnAccessor(pThis, pCtx, fAccessor, X86_XCPT_PF, + fPfBase | (g_aAccessors[iAccessor].fAccess & fPfIdMask)); + CHECK_AD_BITS(0); + + pPteWrk->pfnModify(pThis, iStore, pPteWrk, X86_PTE_A | X86_PTE_D, 0); + ASMInvalidatePage(pThis->uTestAddr.u + X86_PAGE_SIZE); + g_aAccessors[iAccessor].pfnAccessor(pThis, pCtx, fAccessor, X86_XCPT_PF, + fPfBase | (g_aAccessors[iAccessor].fAccess & fPfIdMask)); + CHECK_AD_BITS(0); + } + } + else + { + uint32_t const fPfBase = X86_TRAP_PF_P | (iRing == 3 ? X86_TRAP_PF_US : 0); + for (iAccessor = 0; iAccessor < RT_ELEMENTS(g_aAccessors); iAccessor++) + { + pThis->pszAccessor = g_aAccessors[iAccessor].pszName; + if ( ( (g_aAccessors[iAccessor].fAccess & X86_TRAP_PF_ID) + && EffWrk.fNoExecute) + || ( (g_aAccessors[iAccessor].fAccess & X86_TRAP_PF_RW) + && !EffWrk.fWriteable + && (fWp || iRing == 3)) ) + { + uint32_t const fErrCd = fPfBase | (g_aAccessors[iAccessor].fAccess & fPfIdMask); + + pPteWrk->pfnModify(pThis, iStore, pPteWrk, X86_PTE_A | X86_PTE_D, 0); + ASMInvalidatePage(pThis->uTestAddr.u + X86_PAGE_SIZE); + g_aAccessors[iAccessor].pfnAccessor(pThis, pCtx, fAccessor, X86_XCPT_PF, fErrCd); + CHECK_AD_BITS(0); + + pPteWrk->pfnModify(pThis, iStore, pPteWrk, 0, X86_PTE_A | X86_PTE_D); + ASMInvalidatePage(pThis->uTestAddr.u + X86_PAGE_SIZE); + g_aAccessors[iAccessor].pfnAccessor(pThis, pCtx, fAccessor, X86_XCPT_PF, fErrCd); + CHECK_AD_BITS(X86_PTE_A | X86_PTE_D); + + pPteWrk->pfnModify(pThis, iStore, pPteWrk, X86_PTE_A, X86_PTE_D); + ASMInvalidatePage(pThis->uTestAddr.u + X86_PAGE_SIZE); + g_aAccessors[iAccessor].pfnAccessor(pThis, pCtx, fAccessor, X86_XCPT_PF, fErrCd); + CHECK_AD_BITS(X86_PTE_D); + + pPteWrk->pfnModify(pThis, iStore, pPteWrk, X86_PTE_D, X86_PTE_A); + ASMInvalidatePage(pThis->uTestAddr.u + X86_PAGE_SIZE); + g_aAccessors[iAccessor].pfnAccessor(pThis, pCtx, fAccessor, X86_XCPT_PF, fErrCd); + CHECK_AD_BITS(X86_PTE_A); + } + else + { + uint32_t const fExpectedAD = (g_aAccessors[iAccessor].fAccess & X86_TRAP_PF_RW) + ? X86_PTE_A | X86_PTE_D : X86_PTE_A; + + pPteWrk->pfnModify(pThis, iStore, pPteWrk, X86_PTE_A | X86_PTE_D, 0); + ASMInvalidatePage(pThis->uTestAddr.u + X86_PAGE_SIZE); + g_aAccessors[iAccessor].pfnAccessor(pThis, pCtx, fAccessor, X86_XCPT_UD, UINT8_MAX); + CHECK_AD_BITS(fExpectedAD); + + pPteWrk->pfnModify(pThis, iStore, pPteWrk, 0, X86_PTE_A | X86_PTE_D); + ASMInvalidatePage(pThis->uTestAddr.u + X86_PAGE_SIZE); + g_aAccessors[iAccessor].pfnAccessor(pThis, pCtx, fAccessor, X86_XCPT_UD, UINT8_MAX); + CHECK_AD_BITS(X86_PTE_A | X86_PTE_D); + + pPteWrk->pfnModify(pThis, iStore, pPteWrk, X86_PTE_A, X86_PTE_D); + ASMInvalidatePage(pThis->uTestAddr.u + X86_PAGE_SIZE); + g_aAccessors[iAccessor].pfnAccessor(pThis, pCtx, fAccessor, X86_XCPT_UD, UINT8_MAX); + CHECK_AD_BITS(fExpectedAD | X86_PTE_D); + + pPteWrk->pfnModify(pThis, iStore, pPteWrk, X86_PTE_D, X86_PTE_A); + ASMInvalidatePage(pThis->uTestAddr.u + X86_PAGE_SIZE); + g_aAccessors[iAccessor].pfnAccessor(pThis, pCtx, fAccessor, X86_XCPT_UD, UINT8_MAX); + CHECK_AD_BITS(fExpectedAD | X86_PTE_A); + } + } + } + } + + } + } + } + } + + } + } +#endif + + /* + * Check reserved bits on each paging level. + */ + + /* Loop 1: Accessor flags (only direct for now). */ + for (iOuter = 0; iOuter < 1; iOuter++) + { + uint32_t const fAccessor = BS3CB2PFACC_F_DIRECT; + + /* Loop 2: Paging store method. */ + for (iStore = 0; iStore < RT_ELEMENTS(g_aStoreMethods); iStore++) + { + /* Loop 3: Accessor ring. */ + for (iRing = 0; iRing < 4; iRing++) + { + /* Loop 4: Which level we mess up. */ + for (iLevel = 0; iLevel < pThis->PgInfo.cEntries; iLevel++) + { +#if 0 + const BS3CPUBASIC2PFMODPT *pPteWrk = &g_aPteWorkers[iPteWrk]; + if (pThis->PgInfo.) + { + } +#endif + + + } + } + } + } + + + + return 0; +} + + +BS3_DECL_CALLBACK(uint8_t) bs3CpuBasic2_RaiseXcpt0e_c32(uint8_t bMode) +{ + void *pvTestUnaligned; + uint32_t cbTestUnaligned = _8M; + uint8_t bRet = 1; + int rc; + BS3CPUBASIC2PFSTATE State; + + /* + * Initalize the state data. + */ + Bs3MemZero(&State, sizeof(State)); + State.bMode = bMode; + switch (bMode & BS3_MODE_CODE_MASK) + { + case BS3_MODE_CODE_16: State.cbAccess = sizeof(uint16_t); break; + case BS3_MODE_CODE_V86: State.cbAccess = sizeof(uint16_t); break; + case BS3_MODE_CODE_32: State.cbAccess = sizeof(uint32_t); break; + case BS3_MODE_CODE_64: State.cbAccess = sizeof(uint64_t); break; + } + State.pCmnMode = &g_aCmnModes[0]; + while (State.pCmnMode->bMode != (bMode & BS3_MODE_CODE_MASK)) + State.pCmnMode++; + State.fUseInvlPg = (g_uBs3CpuDetected & BS3CPU_TYPE_MASK) >= BS3CPU_80486; + + /* Figure physical addressing width. */ + State.cBitsPhysWidth = 32; + if ( (g_uBs3CpuDetected & BS3CPU_F_CPUID) + && (ASMCpuId_EDX(1) & (X86_CPUID_FEATURE_EDX_PSE36 | X86_CPUID_FEATURE_EDX_PAE)) ) + State.cBitsPhysWidth = 36; + + if ( (g_uBs3CpuDetected & BS3CPU_F_CPUID_EXT_LEAVES) + && ASMCpuId_EAX(0x80000000) >= 0x80000008) + { + uint8_t cBits = (uint8_t)ASMCpuId_EAX(0x80000008); + if (cBits >= 32 && cBits <= 52) + State.cBitsPhysWidth = cBits; + else + Bs3TestPrintf("CPUID 0x80000008: Physical bitcount out of range: %u\n", cBits); + } + //Bs3TestPrintf("Physical bitcount: %u\n", State.cBitsPhysWidth); + + /* + * Allocate a some memory we can play around with, then carve a size aligned + * chunk out of it so we might be able to maybe play with 2/4MB pages too. + */ + cbTestUnaligned = _8M * 2; + while ((pvTestUnaligned = Bs3MemAlloc(BS3MEMKIND_FLAT32, cbTestUnaligned)) == NULL) + { + cbTestUnaligned >>= 1; + if (cbTestUnaligned <= _16K) + { + Bs3TestFailed("Failed to allocate memory to play around with\n"); + return 1; + } + } + + /* align. */ + if ((uintptr_t)pvTestUnaligned & (cbTestUnaligned - 1)) + { + State.cbTest = cbTestUnaligned >> 1; + State.pbOrgTest = (uint8_t *)(((uintptr_t)pvTestUnaligned + State.cbTest - 1) & ~(State.cbTest - 1)); + } + else + { + State.pbOrgTest = pvTestUnaligned; + State.cbTest = cbTestUnaligned; + } + State.cTestPages = State.cbTest >> X86_PAGE_SHIFT; + + /* + * Alias this memory far away from where our code and data lives. + */ + if (bMode & BS3_MODE_CODE_64) + State.uTestAddr.u = UINT64_C(0x0000648680000000); + else + State.uTestAddr.u = UINT32_C(0x80000000); + rc = Bs3PagingAlias(State.uTestAddr.u, (uintptr_t)State.pbOrgTest, State.cbTest, X86_PTE_P | X86_PTE_RW | X86_PTE_US); + if (RT_SUCCESS(rc)) + { + rc = Bs3PagingQueryAddressInfo(State.uTestAddr.u, &State.PgInfo); + if (RT_SUCCESS(rc)) + { +if (bMode & BS3_MODE_CODE_64) ASMHalt(); + /* Set values that derives from the test memory size and paging info. */ + if (State.PgInfo.cEntries == 2) + { + State.cTestPdes = (State.cTestPages + X86_PG_ENTRIES - 1) / X86_PG_ENTRIES; + State.cTest1stPtes = RT_MIN(State.cTestPages, X86_PG_ENTRIES); + State.cbPdeBackup = State.cTestPdes * (X86_PAGE_SIZE / X86_PG_ENTRIES); + State.cbPteBackup = State.cTest1stPtes * (X86_PAGE_SIZE / X86_PG_ENTRIES); + } + else + { + State.cTestPdes = (State.cTestPages + X86_PG_PAE_ENTRIES - 1) / X86_PG_PAE_ENTRIES; + State.cTest1stPtes = RT_MIN(State.cTestPages, X86_PG_PAE_ENTRIES); + State.cbPdeBackup = State.cTestPdes * (X86_PAGE_SIZE / X86_PG_PAE_ENTRIES); + State.cbPteBackup = State.cTest1stPtes * (X86_PAGE_SIZE / X86_PG_PAE_ENTRIES); + } +#ifdef BS3CPUBASIC2PF_FASTER + State.cbPteBackup = State.PgInfo.cbEntry * 4; +#endif + if (State.cTestPdes <= RT_ELEMENTS(State.au64PdeBackup)) + { + uint32_t cr0 = ASMGetCR0(); + + /* Back up the structures. */ + Bs3MemCpy(&State.PteBackup, State.PgInfo.u.Legacy.pPte, State.cbPteBackup); + Bs3MemCpy(State.au64PdeBackup, State.PgInfo.u.Legacy.pPde, State.cbPdeBackup); + if (State.PgInfo.cEntries > 2) + State.u64PdpteBackup = State.PgInfo.u.Pae.pPdpe->u; + if (State.PgInfo.cEntries > 3) + State.u64Pml4eBackup = State.PgInfo.u.Pae.pPml4e->u; + + /* + * Setup a 16-bit selector for accessing the alias. + */ + Bs3SelSetup16BitData(&Bs3GdteSpare00, State.uTestAddr.u32); + State.uSel16TestData = BS3_SEL_SPARE_00 | 3; + + /* + * Do the testing. + */ + ASMSetCR0(ASMGetCR0() & ~X86_CR0_WP); + bRet = bs3CpuBasic2_RaiseXcpt0eWorker(&State, false /*fWp*/, false /*fNxe*/); + if (bRet == 0 && (g_uBs3CpuDetected & BS3CPU_TYPE_MASK) >= BS3CPU_80486) + { + ASMSetCR0(ASMGetCR0() | X86_CR0_WP); + bRet = bs3CpuBasic2_RaiseXcpt0eWorker(&State, true /*fWp*/, false /*fNxe*/); + } + + /* Do again with NX enabled. */ + if (bRet == 0 && (g_uBs3CpuDetected & BS3CPU_F_NX)) + { + ASMWrMsr(MSR_K6_EFER, ASMRdMsr(MSR_K6_EFER) | MSR_K6_EFER_NXE); + ASMSetCR0(ASMGetCR0() & ~X86_CR0_WP); + bRet = bs3CpuBasic2_RaiseXcpt0eWorker(&State, false /*fWp*/, State.PgInfo.cbEntry == 8 /*fNxe*/); + ASMSetCR0(ASMGetCR0() | X86_CR0_WP); + bRet = bs3CpuBasic2_RaiseXcpt0eWorker(&State, true /*fWp*/, State.PgInfo.cbEntry == 8 /*fNxe*/); + ASMWrMsr(MSR_K6_EFER, ASMRdMsr(MSR_K6_EFER) & ~MSR_K6_EFER_NXE); + } + bs3CpuBasic2Pf_RestoreFromBackups(&State); + ASMSetCR0((ASMGetCR0() & ~X86_CR0_WP) | (cr0 & X86_CR0_WP)); + } + else + Bs3TestFailedF("cTestPdes=%u!\n", State.cTestPdes); + } + else + Bs3TestFailedF("Bs3PagingQueryAddressInfo failed: %d\n", rc); + Bs3PagingUnalias(State.uTestAddr.u, State.cbTest); + } + else + Bs3TestFailedF("Bs3PagingAlias failed! rc=%d\n", rc); + Bs3MemFree(pvTestUnaligned, cbTestUnaligned); + return bRet; +} + diff --git a/src/VBox/ValidationKit/bootsectors/bs3-cpu-basic-2-template.c b/src/VBox/ValidationKit/bootsectors/bs3-cpu-basic-2-template.c new file mode 100644 index 00000000..97edb18c --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3-cpu-basic-2-template.c @@ -0,0 +1,1538 @@ +/* $Id: bs3-cpu-basic-2-template.c $ */ +/** @file + * BS3Kit - bs3-cpu-basic-2, C code template. + */ + +/* + * Copyright (C) 2007-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include <iprt/asm.h> +#include <iprt/asm-amd64-x86.h> + + +/********************************************************************************************************************************* +* Defined Constants And Macros * +*********************************************************************************************************************************/ +#undef CHECK_MEMBER +#define CHECK_MEMBER(a_szName, a_szFmt, a_Actual, a_Expected) \ + do \ + { \ + if ((a_Actual) == (a_Expected)) { /* likely */ } \ + else bs3CpuBasic2_FailedF(a_szName "=" a_szFmt " expected " a_szFmt, (a_Actual), (a_Expected)); \ + } while (0) + + +#ifdef BS3_INSTANTIATING_MODE +# undef MyBs3Idt +# undef MY_SYS_SEL_R0_CS +# undef MY_SYS_SEL_R0_CS_CNF +# undef MY_SYS_SEL_R0_DS +# undef MY_SYS_SEL_R0_SS +# if BS3_MODE_IS_16BIT_SYS(TMPL_MODE) +# define MyBs3Idt Bs3Idt16 +# define MY_SYS_SEL_R0_CS BS3_SEL_R0_CS16 +# define MY_SYS_SEL_R0_CS_CNF BS3_SEL_R0_CS16_CNF +# define MY_SYS_SEL_R0_DS BS3_SEL_R0_DS16 +# define MY_SYS_SEL_R0_SS BS3_SEL_R0_SS16 +# elif BS3_MODE_IS_32BIT_SYS(TMPL_MODE) +# define MyBs3Idt Bs3Idt32 +# define MY_SYS_SEL_R0_CS BS3_SEL_R0_CS32 +# define MY_SYS_SEL_R0_CS_CNF BS3_SEL_R0_CS32_CNF +# define MY_SYS_SEL_R0_DS BS3_SEL_R0_DS32 +# define MY_SYS_SEL_R0_SS BS3_SEL_R0_SS32 +# elif BS3_MODE_IS_64BIT_SYS(TMPL_MODE) +# define MyBs3Idt Bs3Idt64 +# define MY_SYS_SEL_R0_CS BS3_SEL_R0_CS64 +# define MY_SYS_SEL_R0_CS_CNF BS3_SEL_R0_CS64_CNF +# define MY_SYS_SEL_R0_DS BS3_SEL_R0_DS64 +# define MY_SYS_SEL_R0_SS BS3_SEL_R0_DS64 +# else +# error "TMPL_MODE" +# endif +#endif + + +/********************************************************************************************************************************* +* Structures and Typedefs * +*********************************************************************************************************************************/ +#ifdef BS3_INSTANTIATING_CMN +typedef struct BS3CB2INVLDESCTYPE +{ + uint8_t u4Type; + uint8_t u1DescType; +} BS3CB2INVLDESCTYPE; +#endif + + +/********************************************************************************************************************************* +* External Symbols * +*********************************************************************************************************************************/ +#ifdef BS3_INSTANTIATING_CMN +extern FNBS3FAR bs3CpuBasic2_Int80; +extern FNBS3FAR bs3CpuBasic2_Int81; +extern FNBS3FAR bs3CpuBasic2_Int82; +extern FNBS3FAR bs3CpuBasic2_Int83; +extern FNBS3FAR bs3CpuBasic2_ud2; +# define g_bs3CpuBasic2_ud2_FlatAddr BS3_DATA_NM(g_bs3CpuBasic2_ud2_FlatAddr) +extern uint32_t g_bs3CpuBasic2_ud2_FlatAddr; +#endif + + +/********************************************************************************************************************************* +* Global Variables * +*********************************************************************************************************************************/ +#ifdef BS3_INSTANTIATING_CMN +# define g_pszTestMode BS3_CMN_NM(g_pszTestMode) +static const char BS3_FAR *g_pszTestMode = (const char *)1; +# define g_bTestMode BS3_CMN_NM(g_bTestMode) +static uint8_t g_bTestMode = 1; +# define g_f16BitSys BS3_CMN_NM(g_f16BitSys) +static bool g_f16BitSys = 1; + + +/** Table containing invalid CS selector types. */ +static const BS3CB2INVLDESCTYPE g_aInvalidCsTypes[] = +{ + { X86_SEL_TYPE_RO, 1 }, + { X86_SEL_TYPE_RO_ACC, 1 }, + { X86_SEL_TYPE_RW, 1 }, + { X86_SEL_TYPE_RW_ACC, 1 }, + { X86_SEL_TYPE_RO_DOWN, 1 }, + { X86_SEL_TYPE_RO_DOWN_ACC, 1 }, + { X86_SEL_TYPE_RW_DOWN, 1 }, + { X86_SEL_TYPE_RW_DOWN_ACC, 1 }, + { 0, 0 }, + { 1, 0 }, + { 2, 0 }, + { 3, 0 }, + { 4, 0 }, + { 5, 0 }, + { 6, 0 }, + { 7, 0 }, + { 8, 0 }, + { 9, 0 }, + { 10, 0 }, + { 11, 0 }, + { 12, 0 }, + { 13, 0 }, + { 14, 0 }, + { 15, 0 }, +}; + +/** Table containing invalid SS selector types. */ +static const BS3CB2INVLDESCTYPE g_aInvalidSsTypes[] = +{ + { X86_SEL_TYPE_EO, 1 }, + { X86_SEL_TYPE_EO_ACC, 1 }, + { X86_SEL_TYPE_ER, 1 }, + { X86_SEL_TYPE_ER_ACC, 1 }, + { X86_SEL_TYPE_EO_CONF, 1 }, + { X86_SEL_TYPE_EO_CONF_ACC, 1 }, + { X86_SEL_TYPE_ER_CONF, 1 }, + { X86_SEL_TYPE_ER_CONF_ACC, 1 }, + { 0, 0 }, + { 1, 0 }, + { 2, 0 }, + { 3, 0 }, + { 4, 0 }, + { 5, 0 }, + { 6, 0 }, + { 7, 0 }, + { 8, 0 }, + { 9, 0 }, + { 10, 0 }, + { 11, 0 }, + { 12, 0 }, + { 13, 0 }, + { 14, 0 }, + { 15, 0 }, +}; + +#endif /* BS3_INSTANTIATING_CMN - global */ + +#ifdef BS3_INSTANTIATING_CMN + +/** + * Wrapper around Bs3TestFailedF that prefixes the error with g_usBs3TestStep + * and g_pszTestMode. + */ +# define bs3CpuBasic2_FailedF BS3_CMN_NM(bs3CpuBasic2_FailedF) +BS3_DECL_NEAR(void) bs3CpuBasic2_FailedF(const char *pszFormat, ...) +{ + va_list va; + + char szTmp[168]; + va_start(va, pszFormat); + Bs3StrPrintfV(szTmp, sizeof(szTmp), pszFormat, va); + va_end(va); + + Bs3TestFailedF("%u - %s: %s", g_usBs3TestStep, g_pszTestMode, szTmp); +} + + +/** + * Compares trap stuff. + */ +# define bs3CpuBasic2_CompareIntCtx1 BS3_CMN_NM(bs3CpuBasic2_CompareIntCtx1) +BS3_DECL_NEAR(void) bs3CpuBasic2_CompareIntCtx1(PCBS3TRAPFRAME pTrapCtx, PCBS3REGCTX pStartCtx, uint8_t bXcpt) +{ + uint16_t const cErrorsBefore = Bs3TestSubErrorCount(); + CHECK_MEMBER("bXcpt", "%#04x", pTrapCtx->bXcpt, bXcpt); + CHECK_MEMBER("bErrCd", "%#06RX64", pTrapCtx->uErrCd, 0); + Bs3TestCheckRegCtxEx(&pTrapCtx->Ctx, pStartCtx, 2 /*int xx*/, 0 /*cbSpAdjust*/, 0 /*fExtraEfl*/, g_pszTestMode, g_usBs3TestStep); + if (Bs3TestSubErrorCount() != cErrorsBefore) + { + Bs3TrapPrintFrame(pTrapCtx); +#if 1 + Bs3TestPrintf("Halting: g_uBs3CpuDetected=%#x\n", g_uBs3CpuDetected); + Bs3TestPrintf("Halting in CompareTrapCtx1: bXcpt=%#x\n", bXcpt); + ASMHalt(); +#endif + } +} + + +/** + * Compares trap stuff. + */ +# define bs3CpuBasic2_CompareTrapCtx2 BS3_CMN_NM(bs3CpuBasic2_CompareTrapCtx2) +BS3_DECL_NEAR(void) bs3CpuBasic2_CompareTrapCtx2(PCBS3TRAPFRAME pTrapCtx, PCBS3REGCTX pStartCtx, uint16_t cbIpAdjust, + uint8_t bXcpt, uint16_t uHandlerCs) +{ + uint16_t const cErrorsBefore = Bs3TestSubErrorCount(); + CHECK_MEMBER("bXcpt", "%#04x", pTrapCtx->bXcpt, bXcpt); + CHECK_MEMBER("bErrCd", "%#06RX64", pTrapCtx->uErrCd, 0); + CHECK_MEMBER("uHandlerCs", "%#06x", pTrapCtx->uHandlerCs, uHandlerCs); + Bs3TestCheckRegCtxEx(&pTrapCtx->Ctx, pStartCtx, cbIpAdjust, 0 /*cbSpAdjust*/, 0 /*fExtraEfl*/, g_pszTestMode, g_usBs3TestStep); + if (Bs3TestSubErrorCount() != cErrorsBefore) + { + Bs3TrapPrintFrame(pTrapCtx); +#if 1 + Bs3TestPrintf("Halting: g_uBs3CpuDetected=%#x\n", g_uBs3CpuDetected); + Bs3TestPrintf("Halting in CompareTrapCtx2: bXcpt=%#x\n", bXcpt); + ASMHalt(); +#endif + } +} + +/** + * Compares a CPU trap. + */ +# define bs3CpuBasic2_CompareCpuTrapCtx BS3_CMN_NM(bs3CpuBasic2_CompareCpuTrapCtx) +BS3_DECL_NEAR(void) bs3CpuBasic2_CompareCpuTrapCtx(PCBS3TRAPFRAME pTrapCtx, PCBS3REGCTX pStartCtx, uint16_t uErrCd, + uint8_t bXcpt, bool f486ResumeFlagHint) +{ + uint16_t const cErrorsBefore = Bs3TestSubErrorCount(); + uint32_t fExtraEfl; + + CHECK_MEMBER("bXcpt", "%#04x", pTrapCtx->bXcpt, bXcpt); + CHECK_MEMBER("bErrCd", "%#06RX16", (uint16_t)pTrapCtx->uErrCd, (uint16_t)uErrCd); /* 486 only writes a word */ + + fExtraEfl = X86_EFL_RF; + if ( g_f16BitSys + || ( !f486ResumeFlagHint + && (g_uBs3CpuDetected & BS3CPU_TYPE_MASK) <= BS3CPU_80486 ) ) + fExtraEfl = 0; + else + fExtraEfl = X86_EFL_RF; +#if 0 /** @todo Running on an AMD Phenom II X6 1100T under AMD-V I'm not getting good X86_EFL_RF results. Enable this to get on with other work. */ + fExtraEfl = pTrapCtx->Ctx.rflags.u32 & X86_EFL_RF; +#endif + Bs3TestCheckRegCtxEx(&pTrapCtx->Ctx, pStartCtx, 0 /*cbIpAdjust*/, 0 /*cbSpAdjust*/, fExtraEfl, g_pszTestMode, g_usBs3TestStep); + if (Bs3TestSubErrorCount() != cErrorsBefore) + { + Bs3TrapPrintFrame(pTrapCtx); +#if 1 + Bs3TestPrintf("Halting: g_uBs3CpuDetected=%#x\n", g_uBs3CpuDetected); + Bs3TestPrintf("Halting: bXcpt=%#x uErrCd=%#x\n", bXcpt, uErrCd); + ASMHalt(); +#endif + } +} + + +/** + * Compares \#GP trap. + */ +# define bs3CpuBasic2_CompareGpCtx BS3_CMN_NM(bs3CpuBasic2_CompareGpCtx) +BS3_DECL_NEAR(void) bs3CpuBasic2_CompareGpCtx(PCBS3TRAPFRAME pTrapCtx, PCBS3REGCTX pStartCtx, uint16_t uErrCd) +{ + bs3CpuBasic2_CompareCpuTrapCtx(pTrapCtx, pStartCtx, uErrCd, X86_XCPT_GP, true /*f486ResumeFlagHint*/); +} + +/** + * Compares \#NP trap. + */ +# define bs3CpuBasic2_CompareNpCtx BS3_CMN_NM(bs3CpuBasic2_CompareNpCtx) +BS3_DECL_NEAR(void) bs3CpuBasic2_CompareNpCtx(PCBS3TRAPFRAME pTrapCtx, PCBS3REGCTX pStartCtx, uint16_t uErrCd) +{ + bs3CpuBasic2_CompareCpuTrapCtx(pTrapCtx, pStartCtx, uErrCd, X86_XCPT_NP, true /*f486ResumeFlagHint*/); +} + +/** + * Compares \#SS trap. + */ +# define bs3CpuBasic2_CompareSsCtx BS3_CMN_NM(bs3CpuBasic2_CompareSsCtx) +BS3_DECL_NEAR(void) bs3CpuBasic2_CompareSsCtx(PCBS3TRAPFRAME pTrapCtx, PCBS3REGCTX pStartCtx, uint16_t uErrCd, bool f486ResumeFlagHint) +{ + bs3CpuBasic2_CompareCpuTrapCtx(pTrapCtx, pStartCtx, uErrCd, X86_XCPT_SS, f486ResumeFlagHint); +} + +/** + * Compares \#TS trap. + */ +# define bs3CpuBasic2_CompareTsCtx BS3_CMN_NM(bs3CpuBasic2_CompareTsCtx) +BS3_DECL_NEAR(void) bs3CpuBasic2_CompareTsCtx(PCBS3TRAPFRAME pTrapCtx, PCBS3REGCTX pStartCtx, uint16_t uErrCd) +{ + bs3CpuBasic2_CompareCpuTrapCtx(pTrapCtx, pStartCtx, uErrCd, X86_XCPT_TS, false /*f486ResumeFlagHint*/); +} + +/** + * Compares \#PF trap. + */ +# define bs3CpuBasic2_ComparePfCtx BS3_CMN_NM(bs3CpuBasic2_ComparePfCtx) +BS3_DECL_NEAR(void) bs3CpuBasic2_ComparePfCtx(PCBS3TRAPFRAME pTrapCtx, PBS3REGCTX pStartCtx, uint16_t uErrCd, uint64_t uCr2Expected) +{ + uint64_t const uCr2Saved = pStartCtx->cr2.u; + pStartCtx->cr2.u = uCr2Expected; + bs3CpuBasic2_CompareCpuTrapCtx(pTrapCtx, pStartCtx, uErrCd, X86_XCPT_PF, true /*f486ResumeFlagHint*/); + pStartCtx->cr2.u = uCr2Saved; +} + +/** + * Compares \#UD trap. + */ +# define bs3CpuBasic2_CompareUdCtx BS3_CMN_NM(bs3CpuBasic2_CompareUdCtx) +BS3_DECL_NEAR(void) bs3CpuBasic2_CompareUdCtx(PCBS3TRAPFRAME pTrapCtx, PCBS3REGCTX pStartCtx) +{ + bs3CpuBasic2_CompareCpuTrapCtx(pTrapCtx, pStartCtx, 0 /*no error code*/, X86_XCPT_UD, true /*f486ResumeFlagHint*/); +} + + +# define bs3CpuBasic2_RaiseXcpt1Common BS3_CMN_NM(bs3CpuBasic2_RaiseXcpt1Common) +BS3_DECL_NEAR(void) bs3CpuBasic2_RaiseXcpt1Common(uint16_t const uSysR0Cs, uint16_t const uSysR0CsConf, uint16_t const uSysR0Ss, + PX86DESC const paIdt, unsigned const cIdteShift) +{ + BS3TRAPFRAME TrapCtx; + BS3REGCTX Ctx80; + BS3REGCTX Ctx81; + BS3REGCTX Ctx82; + BS3REGCTX Ctx83; + BS3REGCTX CtxTmp; + BS3REGCTX CtxTmp2; + PBS3REGCTX apCtx8x[4]; + unsigned iCtx; + unsigned iRing; + unsigned iDpl; + unsigned iRpl; + unsigned i, j, k; + uint32_t uExpected; + bool const f486Plus = (g_uBs3CpuDetected & BS3CPU_TYPE_MASK) >= BS3CPU_80486; +# if TMPL_BITS == 16 + bool const f386Plus = (g_uBs3CpuDetected & BS3CPU_TYPE_MASK) >= BS3CPU_80386; + bool const f286 = (g_uBs3CpuDetected & BS3CPU_TYPE_MASK) == BS3CPU_80286; +# else + bool const f286 = false; + bool const f386Plus = true; + int rc; + uint8_t *pbIdtCopyAlloc; + PX86DESC pIdtCopy; + const unsigned cbIdte = 1 << (3 + cIdteShift); + RTCCUINTXREG uCr0Saved = ASMGetCR0(); + RTGDTR GdtrSaved; +# endif + RTIDTR IdtrSaved; + RTIDTR Idtr; + + ASMGetIDTR(&IdtrSaved); +# if TMPL_BITS != 16 + ASMGetGDTR(&GdtrSaved); +# endif + + /* make sure they're allocated */ + Bs3MemZero(&TrapCtx, sizeof(TrapCtx)); + Bs3MemZero(&Ctx80, sizeof(Ctx80)); + Bs3MemZero(&Ctx81, sizeof(Ctx81)); + Bs3MemZero(&Ctx82, sizeof(Ctx82)); + Bs3MemZero(&Ctx83, sizeof(Ctx83)); + Bs3MemZero(&CtxTmp, sizeof(CtxTmp)); + Bs3MemZero(&CtxTmp2, sizeof(CtxTmp2)); + + /* Context array. */ + apCtx8x[0] = &Ctx80; + apCtx8x[1] = &Ctx81; + apCtx8x[2] = &Ctx82; + apCtx8x[3] = &Ctx83; + +# if TMPL_BITS != 16 + /* Allocate memory for playing around with the IDT. */ + pbIdtCopyAlloc = NULL; + if (BS3_MODE_IS_PAGED(g_bTestMode)) + pbIdtCopyAlloc = Bs3MemAlloc(BS3MEMKIND_FLAT32, 12*_1K); +# endif + + /* + * IDT entry 80 thru 83 are assigned DPLs according to the number. + * (We'll be useing more, but this'll do for now.) + */ + paIdt[0x80 << cIdteShift].Gate.u2Dpl = 0; + paIdt[0x81 << cIdteShift].Gate.u2Dpl = 1; + paIdt[0x82 << cIdteShift].Gate.u2Dpl = 2; + paIdt[0x83 << cIdteShift].Gate.u2Dpl = 3; + + Bs3RegCtxSave(&Ctx80); + Ctx80.rsp.u -= 0x300; + Ctx80.rip.u = (uintptr_t)BS3_FP_OFF(&bs3CpuBasic2_Int80); +# if TMPL_BITS == 16 + Ctx80.cs = BS3_MODE_IS_RM_OR_V86(g_bTestMode) ? BS3_SEL_TEXT16 : BS3_SEL_R0_CS16; +# elif TMPL_BITS == 32 + g_uBs3TrapEipHint = Ctx80.rip.u32; +# endif + Bs3MemCpy(&Ctx81, &Ctx80, sizeof(Ctx80)); + Ctx81.rip.u = (uintptr_t)BS3_FP_OFF(&bs3CpuBasic2_Int81); + Bs3MemCpy(&Ctx82, &Ctx80, sizeof(Ctx80)); + Ctx82.rip.u = (uintptr_t)BS3_FP_OFF(&bs3CpuBasic2_Int82); + Bs3MemCpy(&Ctx83, &Ctx80, sizeof(Ctx80)); + Ctx83.rip.u = (uintptr_t)BS3_FP_OFF(&bs3CpuBasic2_Int83); + + /* + * Check that all the above gates work from ring-0. + */ + for (iCtx = 0; iCtx < RT_ELEMENTS(apCtx8x); iCtx++) + { + g_usBs3TestStep = iCtx; +# if TMPL_BITS == 32 + g_uBs3TrapEipHint = apCtx8x[iCtx]->rip.u32; +# endif + Bs3TrapSetJmpAndRestore(apCtx8x[iCtx], &TrapCtx); + bs3CpuBasic2_CompareIntCtx1(&TrapCtx, apCtx8x[iCtx], 0x80+iCtx /*bXcpt*/); + } + + /* + * Check that the gate DPL checks works. + */ + g_usBs3TestStep = 100; + for (iRing = 0; iRing <= 3; iRing++) + { + for (iCtx = 0; iCtx < RT_ELEMENTS(apCtx8x); iCtx++) + { + Bs3MemCpy(&CtxTmp, apCtx8x[iCtx], sizeof(CtxTmp)); + Bs3RegCtxConvertToRingX(&CtxTmp, iRing); +# if TMPL_BITS == 32 + g_uBs3TrapEipHint = CtxTmp.rip.u32; +# endif + Bs3TrapSetJmpAndRestore(&CtxTmp, &TrapCtx); + if (iCtx < iRing) + bs3CpuBasic2_CompareGpCtx(&TrapCtx, &CtxTmp, ((0x80 + iCtx) << X86_TRAP_ERR_SEL_SHIFT) | X86_TRAP_ERR_IDT); + else + bs3CpuBasic2_CompareIntCtx1(&TrapCtx, &CtxTmp, 0x80 + iCtx /*bXcpt*/); + g_usBs3TestStep++; + } + } + + /* + * Modify the gate CS value and run the handler at a different CPL. + * Throw RPL variations into the mix (completely ignored) together + * with gate presence. + * 1. CPL <= GATE.DPL + * 2. GATE.P + * 3. GATE.CS.DPL <= CPL (non-conforming segments) + */ + g_usBs3TestStep = 1000; + for (i = 0; i <= 3; i++) + { + for (iRing = 0; iRing <= 3; iRing++) + { + for (iCtx = 0; iCtx < RT_ELEMENTS(apCtx8x); iCtx++) + { +# if TMPL_BITS == 32 + g_uBs3TrapEipHint = apCtx8x[iCtx]->rip.u32; +# endif + Bs3MemCpy(&CtxTmp, apCtx8x[iCtx], sizeof(CtxTmp)); + Bs3RegCtxConvertToRingX(&CtxTmp, iRing); + + for (j = 0; j <= 3; j++) + { + uint16_t const uCs = (uSysR0Cs | j) + (i << BS3_SEL_RING_SHIFT); + for (k = 0; k < 2; k++) + { + g_usBs3TestStep++; + /*Bs3TestPrintf("g_usBs3TestStep=%u iCtx=%u iRing=%u i=%u uCs=%04x\n", g_usBs3TestStep, iCtx, iRing, i, uCs);*/ + paIdt[(0x80 + iCtx) << cIdteShift].Gate.u16Sel = uCs; + paIdt[(0x80 + iCtx) << cIdteShift].Gate.u1Present = k; + Bs3TrapSetJmpAndRestore(&CtxTmp, &TrapCtx); + /*Bs3TrapPrintFrame(&TrapCtx);*/ + if (iCtx < iRing) + bs3CpuBasic2_CompareGpCtx(&TrapCtx, &CtxTmp, ((0x80 + iCtx) << X86_TRAP_ERR_SEL_SHIFT) | X86_TRAP_ERR_IDT); + else if (k == 0) + bs3CpuBasic2_CompareNpCtx(&TrapCtx, &CtxTmp, ((0x80 + iCtx) << X86_TRAP_ERR_SEL_SHIFT) | X86_TRAP_ERR_IDT); + else if (i > iRing) + bs3CpuBasic2_CompareGpCtx(&TrapCtx, &CtxTmp, uCs & X86_SEL_MASK_OFF_RPL); + else + { + uint16_t uExpectedCs = uCs & X86_SEL_MASK_OFF_RPL; + if (i <= iCtx && i <= iRing) + uExpectedCs |= i; + bs3CpuBasic2_CompareTrapCtx2(&TrapCtx, &CtxTmp, 2 /*int 8xh*/, 0x80 + iCtx /*bXcpt*/, uExpectedCs); + } + } + } + + paIdt[(0x80 + iCtx) << cIdteShift].Gate.u16Sel = uSysR0Cs; + paIdt[(0x80 + iCtx) << cIdteShift].Gate.u1Present = 1; + } + } + } + BS3_ASSERT(g_usBs3TestStep < 1600); + + /* + * Various CS and SS related faults + * + * We temporarily reconfigure gate 80 and 83 with new CS selectors, the + * latter have a CS.DPL of 2 for testing ring transisions and SS loading + * without making it impossible to handle faults. + */ + g_usBs3TestStep = 1600; + Bs3GdteTestPage00 = Bs3Gdt[uSysR0Cs >> X86_SEL_SHIFT]; + Bs3GdteTestPage00.Gen.u1Present = 0; + Bs3GdteTestPage00.Gen.u4Type &= ~X86_SEL_TYPE_ACCESSED; + paIdt[0x80 << cIdteShift].Gate.u16Sel = BS3_SEL_TEST_PAGE_00; + + /* CS.PRESENT = 0 */ + Bs3TrapSetJmpAndRestore(&Ctx80, &TrapCtx); + bs3CpuBasic2_CompareNpCtx(&TrapCtx, &Ctx80, BS3_SEL_TEST_PAGE_00); + if (Bs3GdteTestPage00.Gen.u4Type & X86_SEL_TYPE_ACCESSED) + bs3CpuBasic2_FailedF("selector was accessed"); + g_usBs3TestStep++; + + /* Check that GATE.DPL is checked before CS.PRESENT. */ + for (iRing = 1; iRing < 4; iRing++) + { + Bs3MemCpy(&CtxTmp, &Ctx80, sizeof(CtxTmp)); + Bs3RegCtxConvertToRingX(&CtxTmp, iRing); + Bs3TrapSetJmpAndRestore(&CtxTmp, &TrapCtx); + bs3CpuBasic2_CompareGpCtx(&TrapCtx, &CtxTmp, (0x80 << X86_TRAP_ERR_SEL_SHIFT) | X86_TRAP_ERR_IDT); + if (Bs3GdteTestPage00.Gen.u4Type & X86_SEL_TYPE_ACCESSED) + bs3CpuBasic2_FailedF("selector was accessed"); + g_usBs3TestStep++; + } + + /* CS.DPL mismatch takes precedence over CS.PRESENT = 0. */ + Bs3GdteTestPage00.Gen.u4Type &= ~X86_SEL_TYPE_ACCESSED; + Bs3TrapSetJmpAndRestore(&Ctx80, &TrapCtx); + bs3CpuBasic2_CompareNpCtx(&TrapCtx, &Ctx80, BS3_SEL_TEST_PAGE_00); + if (Bs3GdteTestPage00.Gen.u4Type & X86_SEL_TYPE_ACCESSED) + bs3CpuBasic2_FailedF("CS selector was accessed"); + g_usBs3TestStep++; + for (iDpl = 1; iDpl < 4; iDpl++) + { + Bs3GdteTestPage00.Gen.u2Dpl = iDpl; + Bs3TrapSetJmpAndRestore(&Ctx80, &TrapCtx); + bs3CpuBasic2_CompareGpCtx(&TrapCtx, &Ctx80, BS3_SEL_TEST_PAGE_00); + if (Bs3GdteTestPage00.Gen.u4Type & X86_SEL_TYPE_ACCESSED) + bs3CpuBasic2_FailedF("CS selector was accessed"); + g_usBs3TestStep++; + } + + /* 1608: Check all the invalid CS selector types alone. */ + Bs3GdteTestPage00 = Bs3Gdt[uSysR0Cs >> X86_SEL_SHIFT]; + for (i = 0; i < RT_ELEMENTS(g_aInvalidCsTypes); i++) + { + Bs3GdteTestPage00.Gen.u4Type = g_aInvalidCsTypes[i].u4Type; + Bs3GdteTestPage00.Gen.u1DescType = g_aInvalidCsTypes[i].u1DescType; + Bs3TrapSetJmpAndRestore(&Ctx80, &TrapCtx); + bs3CpuBasic2_CompareGpCtx(&TrapCtx, &Ctx80, BS3_SEL_TEST_PAGE_00); + if (Bs3GdteTestPage00.Gen.u4Type != g_aInvalidCsTypes[i].u4Type) + bs3CpuBasic2_FailedF("Invalid CS type %#x/%u -> %#x/%u\n", + g_aInvalidCsTypes[i].u4Type, g_aInvalidCsTypes[i].u1DescType, + Bs3GdteTestPage00.Gen.u4Type, Bs3GdteTestPage00.Gen.u1DescType); + g_usBs3TestStep++; + + /* Incorrect CS.TYPE takes precedence over CS.PRESENT = 0. */ + Bs3GdteTestPage00.Gen.u1Present = 0; + Bs3TrapSetJmpAndRestore(&Ctx80, &TrapCtx); + bs3CpuBasic2_CompareGpCtx(&TrapCtx, &Ctx80, BS3_SEL_TEST_PAGE_00); + Bs3GdteTestPage00.Gen.u1Present = 1; + g_usBs3TestStep++; + } + + /* Fix CS again. */ + Bs3GdteTestPage00 = Bs3Gdt[uSysR0Cs >> X86_SEL_SHIFT]; + + /* 1632: Test SS. */ + if (!BS3_MODE_IS_64BIT_SYS(g_bTestMode)) + { + uint16_t BS3_FAR *puTssSs2 = BS3_MODE_IS_16BIT_SYS(g_bTestMode) ? &Bs3Tss16.ss2 : &Bs3Tss32.ss2; + uint16_t const uSavedSs2 = *puTssSs2; + X86DESC const SavedGate83 = paIdt[0x83 << cIdteShift]; + + /* Make the handler execute in ring-2. */ + Bs3GdteTestPage02 = Bs3Gdt[(uSysR0Cs + (2 << BS3_SEL_RING_SHIFT)) >> X86_SEL_SHIFT]; + Bs3GdteTestPage02.Gen.u4Type &= ~X86_SEL_TYPE_ACCESSED; + paIdt[0x83 << cIdteShift].Gate.u16Sel = BS3_SEL_TEST_PAGE_02 | 2; + + Bs3MemCpy(&CtxTmp, &Ctx83, sizeof(CtxTmp)); + Bs3RegCtxConvertToRingX(&CtxTmp, 3); /* yeah, from 3 so SS:xSP is reloaded. */ + Bs3TrapSetJmpAndRestore(&CtxTmp, &TrapCtx); + bs3CpuBasic2_CompareIntCtx1(&TrapCtx, &CtxTmp, 0x83); + if (!(Bs3GdteTestPage02.Gen.u4Type & X86_SEL_TYPE_ACCESSED)) + bs3CpuBasic2_FailedF("CS selector was not access"); + g_usBs3TestStep++; + + /* Create a SS.DPL=2 stack segment and check that SS2.RPL matters and + that we get #SS if the selector isn't present. */ + i = 0; /* used for cycling thru invalid CS types */ + for (k = 0; k < 10; k++) + { + /* k=0: present, + k=1: not-present, + k=2: present but very low limit, + k=3: not-present, low limit. + k=4: present, read-only. + k=5: not-present, read-only. + k=6: present, code-selector. + k=7: not-present, code-selector. + k=8: present, read-write / no access + system (=LDT). + k=9: not-present, read-write / no access + system (=LDT). + */ + Bs3GdteTestPage03 = Bs3Gdt[(uSysR0Ss + (2 << BS3_SEL_RING_SHIFT)) >> X86_SEL_SHIFT]; + Bs3GdteTestPage03.Gen.u1Present = !(k & 1); + if (k >= 8) + { + Bs3GdteTestPage03.Gen.u1DescType = 0; /* system */ + Bs3GdteTestPage03.Gen.u4Type = X86_SEL_TYPE_RW; /* = LDT */ + } + else if (k >= 6) + Bs3GdteTestPage03.Gen.u4Type = X86_SEL_TYPE_ER; + else if (k >= 4) + Bs3GdteTestPage03.Gen.u4Type = X86_SEL_TYPE_RO; + else if (k >= 2) + { + Bs3GdteTestPage03.Gen.u16LimitLow = 0x400; + Bs3GdteTestPage03.Gen.u4LimitHigh = 0; + Bs3GdteTestPage03.Gen.u1Granularity = 0; + } + + for (iDpl = 0; iDpl < 4; iDpl++) + { + Bs3GdteTestPage03.Gen.u2Dpl = iDpl; + + for (iRpl = 0; iRpl < 4; iRpl++) + { + *puTssSs2 = BS3_SEL_TEST_PAGE_03 | iRpl; + //Bs3TestPrintf("k=%u iDpl=%u iRpl=%u step=%u\n", k, iDpl, iRpl, g_usBs3TestStep); + Bs3GdteTestPage02.Gen.u4Type &= ~X86_SEL_TYPE_ACCESSED; + Bs3GdteTestPage03.Gen.u4Type &= ~X86_SEL_TYPE_ACCESSED; + Bs3TrapSetJmpAndRestore(&CtxTmp, &TrapCtx); + if (iRpl != 2 || iRpl != iDpl || k >= 4) + bs3CpuBasic2_CompareTsCtx(&TrapCtx, &CtxTmp, BS3_SEL_TEST_PAGE_03); + else if (k != 0) + bs3CpuBasic2_CompareSsCtx(&TrapCtx, &CtxTmp, BS3_SEL_TEST_PAGE_03, + k == 2 /*f486ResumeFlagHint*/); + else + { + bs3CpuBasic2_CompareIntCtx1(&TrapCtx, &CtxTmp, 0x83); + if (TrapCtx.uHandlerSs != (BS3_SEL_TEST_PAGE_03 | 2)) + bs3CpuBasic2_FailedF("uHandlerSs=%#x expected %#x\n", TrapCtx.uHandlerSs, BS3_SEL_TEST_PAGE_03 | 2); + } + if (!(Bs3GdteTestPage02.Gen.u4Type & X86_SEL_TYPE_ACCESSED)) + bs3CpuBasic2_FailedF("CS selector was not access"); + if ( TrapCtx.bXcpt == 0x83 + || (TrapCtx.bXcpt == X86_XCPT_SS && k == 2) ) + { + if (!(Bs3GdteTestPage03.Gen.u4Type & X86_SEL_TYPE_ACCESSED)) + bs3CpuBasic2_FailedF("SS selector was not accessed"); + } + else if (Bs3GdteTestPage03.Gen.u4Type & X86_SEL_TYPE_ACCESSED) + bs3CpuBasic2_FailedF("SS selector was accessed"); + g_usBs3TestStep++; + + /* +1: Modify the gate DPL to check that this is checked before SS.DPL and SS.PRESENT. */ + paIdt[0x83 << cIdteShift].Gate.u2Dpl = 2; + Bs3TrapSetJmpAndRestore(&CtxTmp, &TrapCtx); + bs3CpuBasic2_CompareGpCtx(&TrapCtx, &CtxTmp, (0x83 << X86_TRAP_ERR_SEL_SHIFT) | X86_TRAP_ERR_IDT); + paIdt[0x83 << cIdteShift].Gate.u2Dpl = 3; + g_usBs3TestStep++; + + /* +2: Check the CS.DPL check is done before the SS ones. Restoring the + ring-0 INT 83 context triggers the CS.DPL < CPL check. */ + Bs3TrapSetJmpAndRestore(&Ctx83, &TrapCtx); + bs3CpuBasic2_CompareGpCtx(&TrapCtx, &Ctx83, BS3_SEL_TEST_PAGE_02); + g_usBs3TestStep++; + + /* +3: Now mark the CS selector not present and check that that also triggers before SS stuff. */ + Bs3GdteTestPage02.Gen.u1Present = 0; + Bs3TrapSetJmpAndRestore(&CtxTmp, &TrapCtx); + bs3CpuBasic2_CompareNpCtx(&TrapCtx, &CtxTmp, BS3_SEL_TEST_PAGE_02); + Bs3GdteTestPage02.Gen.u1Present = 1; + g_usBs3TestStep++; + + /* +4: Make the CS selector some invalid type and check it triggers before SS stuff. */ + Bs3GdteTestPage02.Gen.u4Type = g_aInvalidCsTypes[i].u4Type; + Bs3GdteTestPage02.Gen.u1DescType = g_aInvalidCsTypes[i].u1DescType; + Bs3TrapSetJmpAndRestore(&CtxTmp, &TrapCtx); + bs3CpuBasic2_CompareGpCtx(&TrapCtx, &CtxTmp, BS3_SEL_TEST_PAGE_02); + Bs3GdteTestPage02.Gen.u4Type = X86_SEL_TYPE_ER_ACC; + Bs3GdteTestPage02.Gen.u1DescType = 1; + g_usBs3TestStep++; + + /* +5: Now, make the CS selector limit too small and that it triggers after SS trouble. + The 286 had a simpler approach to these GP(0). */ + Bs3GdteTestPage02.Gen.u16LimitLow = 0; + Bs3GdteTestPage02.Gen.u4LimitHigh = 0; + Bs3GdteTestPage02.Gen.u1Granularity = 0; + Bs3TrapSetJmpAndRestore(&CtxTmp, &TrapCtx); + if (f286) + bs3CpuBasic2_CompareGpCtx(&TrapCtx, &CtxTmp, 0 /*uErrCd*/); + else if (iRpl != 2 || iRpl != iDpl || k >= 4) + bs3CpuBasic2_CompareTsCtx(&TrapCtx, &CtxTmp, BS3_SEL_TEST_PAGE_03); + else if (k != 0) + bs3CpuBasic2_CompareSsCtx(&TrapCtx, &CtxTmp, BS3_SEL_TEST_PAGE_03, k == 2 /*f486ResumeFlagHint*/); + else + bs3CpuBasic2_CompareGpCtx(&TrapCtx, &CtxTmp, 0 /*uErrCd*/); + Bs3GdteTestPage02 = Bs3Gdt[(uSysR0Cs + (2 << BS3_SEL_RING_SHIFT)) >> X86_SEL_SHIFT]; + g_usBs3TestStep++; + } + } + } + + /* Check all the invalid SS selector types alone. */ + Bs3GdteTestPage02 = Bs3Gdt[(uSysR0Cs + (2 << BS3_SEL_RING_SHIFT)) >> X86_SEL_SHIFT]; + Bs3GdteTestPage03 = Bs3Gdt[(uSysR0Ss + (2 << BS3_SEL_RING_SHIFT)) >> X86_SEL_SHIFT]; + *puTssSs2 = BS3_SEL_TEST_PAGE_03 | 2; + Bs3TrapSetJmpAndRestore(&CtxTmp, &TrapCtx); + bs3CpuBasic2_CompareIntCtx1(&TrapCtx, &CtxTmp, 0x83); + g_usBs3TestStep++; + for (i = 0; i < RT_ELEMENTS(g_aInvalidSsTypes); i++) + { + Bs3GdteTestPage03.Gen.u4Type = g_aInvalidSsTypes[i].u4Type; + Bs3GdteTestPage03.Gen.u1DescType = g_aInvalidSsTypes[i].u1DescType; + Bs3TrapSetJmpAndRestore(&CtxTmp, &TrapCtx); + bs3CpuBasic2_CompareTsCtx(&TrapCtx, &CtxTmp, BS3_SEL_TEST_PAGE_03); + if (Bs3GdteTestPage03.Gen.u4Type != g_aInvalidSsTypes[i].u4Type) + bs3CpuBasic2_FailedF("Invalid SS type %#x/%u -> %#x/%u\n", + g_aInvalidSsTypes[i].u4Type, g_aInvalidSsTypes[i].u1DescType, + Bs3GdteTestPage03.Gen.u4Type, Bs3GdteTestPage03.Gen.u1DescType); + g_usBs3TestStep++; + } + + /* + * Continue the SS experiments with a expand down segment. We'll use + * the same setup as we already have with gate 83h being DPL and + * having CS.DPL=2. + * + * Expand down segments are weird. The valid area is practically speaking + * reversed. So, a 16-bit segment with a limit of 0x6000 will have valid + * addresses from 0xffff thru 0x6001. + * + * So, with expand down segments we can more easily cut partially into the + * pushing of the iret frame and trigger more interesting behavior than + * with regular "expand up" segments where the whole pushing area is either + * all fine or not not fine. + */ + Bs3GdteTestPage02 = Bs3Gdt[(uSysR0Cs + (2 << BS3_SEL_RING_SHIFT)) >> X86_SEL_SHIFT]; + Bs3GdteTestPage03 = Bs3Gdt[(uSysR0Ss + (2 << BS3_SEL_RING_SHIFT)) >> X86_SEL_SHIFT]; + Bs3GdteTestPage03.Gen.u2Dpl = 2; + Bs3GdteTestPage03.Gen.u4Type = X86_SEL_TYPE_RW_DOWN; + *puTssSs2 = BS3_SEL_TEST_PAGE_03 | 2; + + /* First test, limit = max --> no bytes accessible --> #GP */ + Bs3TrapSetJmpAndRestore(&CtxTmp, &TrapCtx); + bs3CpuBasic2_CompareSsCtx(&TrapCtx, &CtxTmp, BS3_SEL_TEST_PAGE_03, true /*f486ResumeFlagHint*/); + + /* Second test, limit = 0 --> all by zero byte accessible --> works */ + Bs3GdteTestPage03.Gen.u16LimitLow = 0; + Bs3GdteTestPage03.Gen.u4LimitHigh = 0; + Bs3TrapSetJmpAndRestore(&CtxTmp, &TrapCtx); + bs3CpuBasic2_CompareIntCtx1(&TrapCtx, &CtxTmp, 0x83); + + /* Modify the gate handler to be a dummy that immediately does UD2 + and triggers #UD, then advance the limit down till we get the #UD. */ + Bs3GdteTestPage03.Gen.u1Granularity = 0; + + Bs3MemCpy(&CtxTmp2, &CtxTmp, sizeof(CtxTmp2)); /* #UD result context */ + if (g_f16BitSys) + { + CtxTmp2.rip.u = g_bs3CpuBasic2_ud2_FlatAddr - BS3_ADDR_BS3TEXT16; + Bs3Trap16SetGate(0x83, X86_SEL_TYPE_SYS_286_INT_GATE, 3, BS3_SEL_TEST_PAGE_02, CtxTmp2.rip.u16, 0 /*cParams*/); + CtxTmp2.rsp.u = Bs3Tss16.sp2 - 2*5; + } + else + { + CtxTmp2.rip.u = g_bs3CpuBasic2_ud2_FlatAddr; + Bs3Trap32SetGate(0x83, X86_SEL_TYPE_SYS_386_INT_GATE, 3, BS3_SEL_TEST_PAGE_02, CtxTmp2.rip.u32, 0 /*cParams*/); + CtxTmp2.rsp.u = Bs3Tss32.esp2 - 4*5; + } + CtxTmp2.bMode = g_bTestMode; /* g_bBs3CurrentMode not changed by the UD2 handler. */ + CtxTmp2.cs = BS3_SEL_TEST_PAGE_02 | 2; + CtxTmp2.ss = BS3_SEL_TEST_PAGE_03 | 2; + CtxTmp2.bCpl = 2; + + /* test run. */ + Bs3TrapSetJmpAndRestore(&CtxTmp, &TrapCtx); + bs3CpuBasic2_CompareUdCtx(&TrapCtx, &CtxTmp2); + g_usBs3TestStep++; + + /* Real run. */ + i = (g_f16BitSys ? 2 : 4) * 6 + 1; + while (i-- > 0) + { + Bs3GdteTestPage03.Gen.u16LimitLow = CtxTmp2.rsp.u16 + i - 1; + Bs3TrapSetJmpAndRestore(&CtxTmp, &TrapCtx); + if (i > 0) + bs3CpuBasic2_CompareSsCtx(&TrapCtx, &CtxTmp, BS3_SEL_TEST_PAGE_03, true /*f486ResumeFlagHint*/); + else + bs3CpuBasic2_CompareUdCtx(&TrapCtx, &CtxTmp2); + g_usBs3TestStep++; + } + + /* Do a run where we do the same-ring kind of access. */ + Bs3RegCtxConvertToRingX(&CtxTmp, 2); + if (g_f16BitSys) + { + CtxTmp2.rsp.u32 = CtxTmp.rsp.u32 - 2*3; + i = 2*3 - 1; + } + else + { + CtxTmp2.rsp.u32 = CtxTmp.rsp.u32 - 4*3; + i = 4*3 - 1; + } + CtxTmp.ss = BS3_SEL_TEST_PAGE_03 | 2; + CtxTmp2.ds = CtxTmp.ds; + CtxTmp2.es = CtxTmp.es; + CtxTmp2.fs = CtxTmp.fs; + CtxTmp2.gs = CtxTmp.gs; + while (i-- > 0) + { + Bs3GdteTestPage03.Gen.u16LimitLow = CtxTmp2.rsp.u16 + i - 1; + Bs3TrapSetJmpAndRestore(&CtxTmp, &TrapCtx); + if (i > 0) + bs3CpuBasic2_CompareSsCtx(&TrapCtx, &CtxTmp, 0 /*BS3_SEL_TEST_PAGE_03*/, true /*f486ResumeFlagHint*/); + else + bs3CpuBasic2_CompareUdCtx(&TrapCtx, &CtxTmp2); + g_usBs3TestStep++; + } + + *puTssSs2 = uSavedSs2; + paIdt[0x83 << cIdteShift] = SavedGate83; + } + paIdt[0x80 << cIdteShift].Gate.u16Sel = uSysR0Cs; + BS3_ASSERT(g_usBs3TestStep < 3000); + + /* + * Modify the gate CS value with a conforming segment. + */ + g_usBs3TestStep = 3000; + for (i = 0; i <= 3; i++) /* cs.dpl */ + { + for (iRing = 0; iRing <= 3; iRing++) + { + for (iCtx = 0; iCtx < RT_ELEMENTS(apCtx8x); iCtx++) + { + Bs3MemCpy(&CtxTmp, apCtx8x[iCtx], sizeof(CtxTmp)); + Bs3RegCtxConvertToRingX(&CtxTmp, iRing); +# if TMPL_BITS == 32 + g_uBs3TrapEipHint = CtxTmp.rip.u32; +# endif + + for (j = 0; j <= 3; j++) /* rpl */ + { + uint16_t const uCs = (uSysR0CsConf | j) + (i << BS3_SEL_RING_SHIFT); + /*Bs3TestPrintf("g_usBs3TestStep=%u iCtx=%u iRing=%u i=%u uCs=%04x\n", g_usBs3TestStep, iCtx, iRing, i, uCs);*/ + paIdt[(0x80 + iCtx) << cIdteShift].Gate.u16Sel = uCs; + Bs3TrapSetJmpAndRestore(&CtxTmp, &TrapCtx); + //Bs3TestPrintf("%u/%u/%u/%u: cs=%04x hcs=%04x xcpt=%02x\n", i, iRing, iCtx, j, uCs, TrapCtx.uHandlerCs, TrapCtx.bXcpt); + /*Bs3TrapPrintFrame(&TrapCtx);*/ + g_usBs3TestStep++; + if (iCtx < iRing) + bs3CpuBasic2_CompareGpCtx(&TrapCtx, &CtxTmp, ((0x80 + iCtx) << X86_TRAP_ERR_SEL_SHIFT) | X86_TRAP_ERR_IDT); + else if (i > iRing) + bs3CpuBasic2_CompareGpCtx(&TrapCtx, &CtxTmp, uCs & X86_SEL_MASK_OFF_RPL); + else + bs3CpuBasic2_CompareIntCtx1(&TrapCtx, &CtxTmp, 0x80 + iCtx /*bXcpt*/); + } + paIdt[(0x80 + iCtx) << cIdteShift].Gate.u16Sel = uSysR0Cs; + } + } + } + BS3_ASSERT(g_usBs3TestStep < 3500); + + /* + * The gates must be 64-bit in long mode. + */ + if (cIdteShift != 0) + { + g_usBs3TestStep = 3500; + for (i = 0; i <= 3; i++) + { + for (iRing = 0; iRing <= 3; iRing++) + { + for (iCtx = 0; iCtx < RT_ELEMENTS(apCtx8x); iCtx++) + { + Bs3MemCpy(&CtxTmp, apCtx8x[iCtx], sizeof(CtxTmp)); + Bs3RegCtxConvertToRingX(&CtxTmp, iRing); + + for (j = 0; j < 2; j++) + { + static const uint16_t s_auCSes[2] = { BS3_SEL_R0_CS16, BS3_SEL_R0_CS32 }; + uint16_t uCs = (s_auCSes[j] | i) + (i << BS3_SEL_RING_SHIFT); + g_usBs3TestStep++; + /*Bs3TestPrintf("g_usBs3TestStep=%u iCtx=%u iRing=%u i=%u uCs=%04x\n", g_usBs3TestStep, iCtx, iRing, i, uCs);*/ + paIdt[(0x80 + iCtx) << cIdteShift].Gate.u16Sel = uCs; + Bs3TrapSetJmpAndRestore(&CtxTmp, &TrapCtx); + /*Bs3TrapPrintFrame(&TrapCtx);*/ + if (iCtx < iRing) + bs3CpuBasic2_CompareGpCtx(&TrapCtx, &CtxTmp, ((0x80 + iCtx) << X86_TRAP_ERR_SEL_SHIFT) | X86_TRAP_ERR_IDT); + else + bs3CpuBasic2_CompareGpCtx(&TrapCtx, &CtxTmp, uCs & X86_SEL_MASK_OFF_RPL); + } + paIdt[(0x80 + iCtx) << cIdteShift].Gate.u16Sel = uSysR0Cs; + } + } + } + BS3_ASSERT(g_usBs3TestStep < 4000); + } + + /* + * IDT limit check. The 286 does not access X86DESCGATE::u16OffsetHigh. + */ + g_usBs3TestStep = 5000; + i = (0x80 << (cIdteShift + 3)) - 1; + j = (0x82 << (cIdteShift + 3)) - (!f286 ? 1 : 3); + k = (0x83 << (cIdteShift + 3)) - 1; + for (; i <= k; i++, g_usBs3TestStep++) + { + Idtr = IdtrSaved; + Idtr.cbIdt = i; + ASMSetIDTR(&Idtr); + Bs3TrapSetJmpAndRestore(&Ctx81, &TrapCtx); + if (i < j) + bs3CpuBasic2_CompareGpCtx(&TrapCtx, &Ctx81, (0x81 << X86_TRAP_ERR_SEL_SHIFT) | X86_TRAP_ERR_IDT); + else + bs3CpuBasic2_CompareIntCtx1(&TrapCtx, &Ctx81, 0x81 /*bXcpt*/); + } + ASMSetIDTR(&IdtrSaved); + BS3_ASSERT(g_usBs3TestStep < 5100); + +# if TMPL_BITS != 16 /* Only do the paging related stuff in 32-bit and 64-bit modes. */ + + /* + * IDT page not present. Placing the IDT copy such that 0x80 is on the + * first page and 0x81 is on the second page. We need proceed to move + * it down byte by byte to check that any inaccessible byte means #PF. + * + * Note! We must reload the alternative IDTR for each run as any kind of + * printing to the string (like error reporting) will cause a switch + * to real mode and back, reloading the default IDTR. + */ + g_usBs3TestStep = 5200; + if (BS3_MODE_IS_PAGED(g_bTestMode) && pbIdtCopyAlloc) + { + uint32_t const uCr2Expected = Bs3SelPtrToFlat(pbIdtCopyAlloc) + _4K; + for (j = 0; j < cbIdte; j++) + { + pIdtCopy = (PX86DESC)&pbIdtCopyAlloc[_4K - cbIdte * 0x81 - j]; + Bs3MemCpy(pIdtCopy, paIdt, cbIdte * 256); + + Idtr.cbIdt = IdtrSaved.cbIdt; + Idtr.pIdt = Bs3SelPtrToFlat(pIdtCopy); + + ASMSetIDTR(&Idtr); + Bs3TrapSetJmpAndRestore(&Ctx81, &TrapCtx); + bs3CpuBasic2_CompareIntCtx1(&TrapCtx, &Ctx81, 0x81 /*bXcpt*/); + g_usBs3TestStep++; + + ASMSetIDTR(&Idtr); + Bs3TrapSetJmpAndRestore(&Ctx80, &TrapCtx); + bs3CpuBasic2_CompareIntCtx1(&TrapCtx, &Ctx80, 0x80 /*bXcpt*/); + g_usBs3TestStep++; + + rc = Bs3PagingProtect(uCr2Expected, _4K, 0 /*fSet*/, X86_PTE_P /*fClear*/); + if (RT_SUCCESS(rc)) + { + ASMSetIDTR(&Idtr); + Bs3TrapSetJmpAndRestore(&Ctx80, &TrapCtx); + bs3CpuBasic2_CompareIntCtx1(&TrapCtx, &Ctx80, 0x80 /*bXcpt*/); + g_usBs3TestStep++; + + ASMSetIDTR(&Idtr); + Bs3TrapSetJmpAndRestore(&Ctx81, &TrapCtx); + if (f486Plus) + bs3CpuBasic2_ComparePfCtx(&TrapCtx, &Ctx81, 0 /*uErrCd*/, uCr2Expected); + else + bs3CpuBasic2_ComparePfCtx(&TrapCtx, &Ctx81, X86_TRAP_PF_RW /*uErrCd*/, uCr2Expected + 4 - RT_MIN(j, 4)); + g_usBs3TestStep++; + + Bs3PagingProtect(uCr2Expected, _4K, X86_PTE_P /*fSet*/, 0 /*fClear*/); + + /* Check if that the entry type is checked after the whole IDTE has been cleared for #PF. */ + pIdtCopy[0x80 << cIdteShift].Gate.u4Type = 0; + rc = Bs3PagingProtect(uCr2Expected, _4K, 0 /*fSet*/, X86_PTE_P /*fClear*/); + if (RT_SUCCESS(rc)) + { + ASMSetIDTR(&Idtr); + Bs3TrapSetJmpAndRestore(&Ctx81, &TrapCtx); + if (f486Plus) + bs3CpuBasic2_ComparePfCtx(&TrapCtx, &Ctx81, 0 /*uErrCd*/, uCr2Expected); + else + bs3CpuBasic2_ComparePfCtx(&TrapCtx, &Ctx81, X86_TRAP_PF_RW /*uErrCd*/, uCr2Expected + 4 - RT_MIN(j, 4)); + g_usBs3TestStep++; + + Bs3PagingProtect(uCr2Expected, _4K, X86_PTE_P /*fSet*/, 0 /*fClear*/); + } + } + else + Bs3TestPrintf("Bs3PagingProtectPtr: %d\n", i); + + ASMSetIDTR(&IdtrSaved); + } + } + + /* + * The read/write and user/supervisor bits the IDT PTEs are irrelevant. + */ + g_usBs3TestStep = 5300; + if (BS3_MODE_IS_PAGED(g_bTestMode) && pbIdtCopyAlloc) + { + Bs3MemCpy(pbIdtCopyAlloc, paIdt, cbIdte * 256); + Idtr.cbIdt = IdtrSaved.cbIdt; + Idtr.pIdt = Bs3SelPtrToFlat(pbIdtCopyAlloc); + + ASMSetIDTR(&Idtr); + Bs3TrapSetJmpAndRestore(&Ctx81, &TrapCtx); + bs3CpuBasic2_CompareIntCtx1(&TrapCtx, &Ctx81, 0x81 /*bXcpt*/); + g_usBs3TestStep++; + + rc = Bs3PagingProtect(Idtr.pIdt, _4K, 0 /*fSet*/, X86_PTE_RW | X86_PTE_US /*fClear*/); + if (RT_SUCCESS(rc)) + { + ASMSetIDTR(&Idtr); + Bs3TrapSetJmpAndRestore(&Ctx81, &TrapCtx); + bs3CpuBasic2_CompareIntCtx1(&TrapCtx, &Ctx81, 0x81 /*bXcpt*/); + g_usBs3TestStep++; + + Bs3PagingProtect(Idtr.pIdt, _4K, X86_PTE_RW | X86_PTE_US /*fSet*/, 0 /*fClear*/); + } + ASMSetIDTR(&IdtrSaved); + } + + /* + * Check that CS.u1Accessed is set to 1. Use the test page selector #0 and #3 together + * with interrupt gates 80h and 83h, respectively. + */ +/** @todo Throw in SS.u1Accessed too. */ + g_usBs3TestStep = 5400; + if (BS3_MODE_IS_PAGED(g_bTestMode) && pbIdtCopyAlloc) + { + Bs3GdteTestPage00 = Bs3Gdt[uSysR0Cs >> X86_SEL_SHIFT]; + Bs3GdteTestPage00.Gen.u4Type &= ~X86_SEL_TYPE_ACCESSED; + paIdt[0x80 << cIdteShift].Gate.u16Sel = BS3_SEL_TEST_PAGE_00; + + Bs3GdteTestPage03 = Bs3Gdt[(uSysR0Cs + (3 << BS3_SEL_RING_SHIFT)) >> X86_SEL_SHIFT]; + Bs3GdteTestPage03.Gen.u4Type &= ~X86_SEL_TYPE_ACCESSED; + paIdt[0x83 << cIdteShift].Gate.u16Sel = BS3_SEL_TEST_PAGE_03; /* rpl is ignored, so leave it as zero. */ + + /* Check that the CS.A bit is being set on a general basis and that + the special CS values work with out generic handler code. */ + Bs3TrapSetJmpAndRestore(&Ctx80, &TrapCtx); + bs3CpuBasic2_CompareIntCtx1(&TrapCtx, &Ctx80, 0x80 /*bXcpt*/); + if (!(Bs3GdteTestPage00.Gen.u4Type & X86_SEL_TYPE_ACCESSED)) + bs3CpuBasic2_FailedF("u4Type=%#x, not accessed", Bs3GdteTestPage00.Gen.u4Type); + g_usBs3TestStep++; + + Bs3MemCpy(&CtxTmp, &Ctx83, sizeof(CtxTmp)); + Bs3RegCtxConvertToRingX(&CtxTmp, 3); + Bs3TrapSetJmpAndRestore(&CtxTmp, &TrapCtx); + bs3CpuBasic2_CompareIntCtx1(&TrapCtx, &CtxTmp, 0x83 /*bXcpt*/); + if (!(Bs3GdteTestPage03.Gen.u4Type & X86_SEL_TYPE_ACCESSED)) + bs3CpuBasic2_FailedF("u4Type=%#x, not accessed!", Bs3GdteTestPage00.Gen.u4Type); + if (TrapCtx.uHandlerCs != (BS3_SEL_TEST_PAGE_03 | 3)) + bs3CpuBasic2_FailedF("uHandlerCs=%#x, expected %#x", TrapCtx.uHandlerCs, (BS3_SEL_TEST_PAGE_03 | 3)); + g_usBs3TestStep++; + + /* + * Now check that setting CS.u1Access to 1 does __NOT__ trigger a page + * fault due to the RW bit being zero. + * (We check both with with and without the WP bit if 80486.) + */ + if ((g_uBs3CpuDetected & BS3CPU_TYPE_MASK) >= BS3CPU_80486) + ASMSetCR0(uCr0Saved | X86_CR0_WP); + + Bs3GdteTestPage00.Gen.u4Type &= ~X86_SEL_TYPE_ACCESSED; + Bs3GdteTestPage03.Gen.u4Type &= ~X86_SEL_TYPE_ACCESSED; + rc = Bs3PagingProtect(GdtrSaved.pGdt + BS3_SEL_TEST_PAGE_00, 8, 0 /*fSet*/, X86_PTE_RW /*fClear*/); + if (RT_SUCCESS(rc)) + { + /* ring-0 handler */ + Bs3TrapSetJmpAndRestore(&Ctx80, &TrapCtx); + bs3CpuBasic2_CompareIntCtx1(&TrapCtx, &Ctx80, 0x80 /*bXcpt*/); + if (!(Bs3GdteTestPage00.Gen.u4Type & X86_SEL_TYPE_ACCESSED)) + bs3CpuBasic2_FailedF("u4Type=%#x, not accessed!", Bs3GdteTestPage00.Gen.u4Type); + g_usBs3TestStep++; + + /* ring-3 handler */ + Bs3MemCpy(&CtxTmp, &Ctx83, sizeof(CtxTmp)); + Bs3RegCtxConvertToRingX(&CtxTmp, 3); + Bs3TrapSetJmpAndRestore(&CtxTmp, &TrapCtx); + bs3CpuBasic2_CompareIntCtx1(&TrapCtx, &CtxTmp, 0x83 /*bXcpt*/); + if (!(Bs3GdteTestPage03.Gen.u4Type & X86_SEL_TYPE_ACCESSED)) + bs3CpuBasic2_FailedF("u4Type=%#x, not accessed!", Bs3GdteTestPage00.Gen.u4Type); + g_usBs3TestStep++; + + /* clear WP and repeat the above. */ + if ((g_uBs3CpuDetected & BS3CPU_TYPE_MASK) >= BS3CPU_80486) + ASMSetCR0(uCr0Saved & ~X86_CR0_WP); + Bs3GdteTestPage00.Gen.u4Type &= ~X86_SEL_TYPE_ACCESSED; /* (No need to RW the page - ring-0, WP=0.) */ + Bs3GdteTestPage03.Gen.u4Type &= ~X86_SEL_TYPE_ACCESSED; /* (No need to RW the page - ring-0, WP=0.) */ + + Bs3TrapSetJmpAndRestore(&Ctx80, &TrapCtx); + bs3CpuBasic2_CompareIntCtx1(&TrapCtx, &Ctx80, 0x80 /*bXcpt*/); + if (!(Bs3GdteTestPage00.Gen.u4Type & X86_SEL_TYPE_ACCESSED)) + bs3CpuBasic2_FailedF("u4Type=%#x, not accessed!", Bs3GdteTestPage00.Gen.u4Type); + g_usBs3TestStep++; + + Bs3TrapSetJmpAndRestore(&CtxTmp, &TrapCtx); + bs3CpuBasic2_CompareIntCtx1(&TrapCtx, &CtxTmp, 0x83 /*bXcpt*/); + if (!(Bs3GdteTestPage03.Gen.u4Type & X86_SEL_TYPE_ACCESSED)) + bs3CpuBasic2_FailedF("u4Type=%#x, not accessed!n", Bs3GdteTestPage03.Gen.u4Type); + g_usBs3TestStep++; + + Bs3PagingProtect(GdtrSaved.pGdt + BS3_SEL_TEST_PAGE_00, 8, X86_PTE_RW /*fSet*/, 0 /*fClear*/); + } + + ASMSetCR0(uCr0Saved); + + /* + * While we're here, check that if the CS GDT entry is a non-present + * page we do get a #PF with the rigth error code and CR2. + */ + Bs3GdteTestPage00.Gen.u4Type &= ~X86_SEL_TYPE_ACCESSED; /* Just for fun, really a pointless gesture. */ + Bs3GdteTestPage03.Gen.u4Type &= ~X86_SEL_TYPE_ACCESSED; + rc = Bs3PagingProtect(GdtrSaved.pGdt + BS3_SEL_TEST_PAGE_00, 8, 0 /*fSet*/, X86_PTE_P /*fClear*/); + if (RT_SUCCESS(rc)) + { + Bs3TrapSetJmpAndRestore(&Ctx80, &TrapCtx); + if (f486Plus) + bs3CpuBasic2_ComparePfCtx(&TrapCtx, &Ctx80, 0 /*uErrCd*/, GdtrSaved.pGdt + BS3_SEL_TEST_PAGE_00); + else + bs3CpuBasic2_ComparePfCtx(&TrapCtx, &Ctx80, X86_TRAP_PF_RW, GdtrSaved.pGdt + BS3_SEL_TEST_PAGE_00 + 4); + g_usBs3TestStep++; + + /* Do it from ring-3 to check ErrCd, which doesn't set X86_TRAP_PF_US it turns out. */ + Bs3MemCpy(&CtxTmp, &Ctx83, sizeof(CtxTmp)); + Bs3RegCtxConvertToRingX(&CtxTmp, 3); + Bs3TrapSetJmpAndRestore(&CtxTmp, &TrapCtx); + + if (f486Plus) + bs3CpuBasic2_ComparePfCtx(&TrapCtx, &CtxTmp, 0 /*uErrCd*/, GdtrSaved.pGdt + BS3_SEL_TEST_PAGE_03); + else + bs3CpuBasic2_ComparePfCtx(&TrapCtx, &CtxTmp, X86_TRAP_PF_RW, GdtrSaved.pGdt + BS3_SEL_TEST_PAGE_03 + 4); + g_usBs3TestStep++; + + Bs3PagingProtect(GdtrSaved.pGdt + BS3_SEL_TEST_PAGE_00, 8, X86_PTE_P /*fSet*/, 0 /*fClear*/); + if (Bs3GdteTestPage00.Gen.u4Type & X86_SEL_TYPE_ACCESSED) + bs3CpuBasic2_FailedF("u4Type=%#x, accessed! #1", Bs3GdteTestPage00.Gen.u4Type); + if (Bs3GdteTestPage03.Gen.u4Type & X86_SEL_TYPE_ACCESSED) + bs3CpuBasic2_FailedF("u4Type=%#x, accessed! #2", Bs3GdteTestPage03.Gen.u4Type); + } + + /* restore */ + paIdt[0x80 << cIdteShift].Gate.u16Sel = uSysR0Cs; + paIdt[0x83 << cIdteShift].Gate.u16Sel = uSysR0Cs;// + (3 << BS3_SEL_RING_SHIFT) + 3; + } + +# endif /* 32 || 64*/ + + /* + * Check broad EFLAGS effects. + */ + g_usBs3TestStep = 5600; + for (iCtx = 0; iCtx < RT_ELEMENTS(apCtx8x); iCtx++) + { + for (iRing = 0; iRing < 4; iRing++) + { + Bs3MemCpy(&CtxTmp, apCtx8x[iCtx], sizeof(CtxTmp)); + Bs3RegCtxConvertToRingX(&CtxTmp, iRing); + + /* all set */ + CtxTmp.rflags.u32 &= X86_EFL_VM | X86_EFL_1; + CtxTmp.rflags.u32 |= X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF /* | X86_EFL_TF */ /*| X86_EFL_IF*/ + | X86_EFL_DF | X86_EFL_OF | X86_EFL_IOPL /* | X86_EFL_NT*/; + if (f486Plus) + CtxTmp.rflags.u32 |= X86_EFL_AC; + if (f486Plus && !g_f16BitSys) + CtxTmp.rflags.u32 |= X86_EFL_RF; + if (g_uBs3CpuDetected & BS3CPU_F_CPUID) + CtxTmp.rflags.u32 |= X86_EFL_VIF | X86_EFL_VIP; + Bs3TrapSetJmpAndRestore(&CtxTmp, &TrapCtx); + CtxTmp.rflags.u32 &= ~X86_EFL_RF; + + if (iCtx >= iRing) + bs3CpuBasic2_CompareIntCtx1(&TrapCtx, &CtxTmp, 0x80 + iCtx /*bXcpt*/); + else + bs3CpuBasic2_CompareGpCtx(&TrapCtx, &CtxTmp, ((0x80 + iCtx) << X86_TRAP_ERR_SEL_SHIFT) | X86_TRAP_ERR_IDT); + uExpected = CtxTmp.rflags.u32 + & ( X86_EFL_1 | X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF | X86_EFL_DF + | X86_EFL_OF | X86_EFL_IOPL | X86_EFL_NT | X86_EFL_VM | X86_EFL_AC | X86_EFL_VIF | X86_EFL_VIP + | X86_EFL_ID /*| X86_EFL_TF*/ /*| X86_EFL_IF*/ /*| X86_EFL_RF*/ ); + if (TrapCtx.fHandlerRfl != uExpected) + bs3CpuBasic2_FailedF("unexpected handler rflags value: %RX64 expected %RX32; CtxTmp.rflags=%RX64 Ctx.rflags=%RX64\n", + TrapCtx.fHandlerRfl, uExpected, CtxTmp.rflags.u, TrapCtx.Ctx.rflags.u); + g_usBs3TestStep++; + + /* all cleared */ + if ((g_uBs3CpuDetected & BS3CPU_TYPE_MASK) < BS3CPU_80286) + CtxTmp.rflags.u32 = apCtx8x[iCtx]->rflags.u32 & (X86_EFL_RA1_MASK | UINT16_C(0xf000)); + else + CtxTmp.rflags.u32 = apCtx8x[iCtx]->rflags.u32 & (X86_EFL_VM | X86_EFL_RA1_MASK); + Bs3TrapSetJmpAndRestore(&CtxTmp, &TrapCtx); + if (iCtx >= iRing) + bs3CpuBasic2_CompareIntCtx1(&TrapCtx, &CtxTmp, 0x80 + iCtx /*bXcpt*/); + else + bs3CpuBasic2_CompareGpCtx(&TrapCtx, &CtxTmp, ((0x80 + iCtx) << X86_TRAP_ERR_SEL_SHIFT) | X86_TRAP_ERR_IDT); + uExpected = CtxTmp.rflags.u32; + if (TrapCtx.fHandlerRfl != uExpected) + bs3CpuBasic2_FailedF("unexpected handler rflags value: %RX64 expected %RX32; CtxTmp.rflags=%RX64 Ctx.rflags=%RX64\n", + TrapCtx.fHandlerRfl, uExpected, CtxTmp.rflags.u, TrapCtx.Ctx.rflags.u); + g_usBs3TestStep++; + } + } + +/** @todo CS.LIMIT / canonical(CS) */ + + + /* + * Check invalid gate types. + */ + g_usBs3TestStep = 32000; + for (iRing = 0; iRing <= 3; iRing++) + { + static const uint16_t s_auCSes[] = { BS3_SEL_R0_CS16, BS3_SEL_R0_CS32, BS3_SEL_R0_CS64, + BS3_SEL_TSS16, BS3_SEL_TSS32, BS3_SEL_TSS64, 0, BS3_SEL_SPARE_1f }; + static uint16_t const s_auInvlTypes64[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f }; + static uint16_t const s_auInvlTypes32[] = { 0, 1, 2, 3, 8, 9, 10, 11, 13, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + /*286:*/ 12, 14, 15 }; + uint16_t const * const pauInvTypes = cIdteShift != 0 ? s_auInvlTypes64 : s_auInvlTypes32; + uint16_t const cInvTypes = cIdteShift != 0 ? RT_ELEMENTS(s_auInvlTypes64) + : f386Plus ? RT_ELEMENTS(s_auInvlTypes32) - 3 : RT_ELEMENTS(s_auInvlTypes32); + + + for (iCtx = 0; iCtx < RT_ELEMENTS(apCtx8x); iCtx++) + { + unsigned iType; + + Bs3MemCpy(&CtxTmp, apCtx8x[iCtx], sizeof(CtxTmp)); + Bs3RegCtxConvertToRingX(&CtxTmp, iRing); +# if TMPL_BITS == 32 + g_uBs3TrapEipHint = CtxTmp.rip.u32; +# endif + for (iType = 0; iType < cInvTypes; iType++) + { + uint8_t const bSavedType = paIdt[(0x80 + iCtx) << cIdteShift].Gate.u4Type; + paIdt[(0x80 + iCtx) << cIdteShift].Gate.u1DescType = pauInvTypes[iType] >> 4; + paIdt[(0x80 + iCtx) << cIdteShift].Gate.u4Type = pauInvTypes[iType] & 0xf; + + for (i = 0; i < 4; i++) + { + for (j = 0; j < RT_ELEMENTS(s_auCSes); j++) + { + uint16_t uCs = (unsigned)(s_auCSes[j] - BS3_SEL_R0_FIRST) < (unsigned)(4 << BS3_SEL_RING_SHIFT) + ? (s_auCSes[j] | i) + (i << BS3_SEL_RING_SHIFT) + : s_auCSes[j] | i; + /*Bs3TestPrintf("g_usBs3TestStep=%u iCtx=%u iRing=%u i=%u uCs=%04x type=%#x\n", g_usBs3TestStep, iCtx, iRing, i, uCs, pauInvTypes[iType]);*/ + paIdt[(0x80 + iCtx) << cIdteShift].Gate.u16Sel = uCs; + Bs3TrapSetJmpAndRestore(&CtxTmp, &TrapCtx); + g_usBs3TestStep++; + bs3CpuBasic2_CompareGpCtx(&TrapCtx, &CtxTmp, ((0x80 + iCtx) << X86_TRAP_ERR_SEL_SHIFT) | X86_TRAP_ERR_IDT); + + /* Mark it not-present to check that invalid type takes precedence. */ + paIdt[(0x80 + iCtx) << cIdteShift].Gate.u1Present = 0; + Bs3TrapSetJmpAndRestore(&CtxTmp, &TrapCtx); + g_usBs3TestStep++; + bs3CpuBasic2_CompareGpCtx(&TrapCtx, &CtxTmp, ((0x80 + iCtx) << X86_TRAP_ERR_SEL_SHIFT) | X86_TRAP_ERR_IDT); + paIdt[(0x80 + iCtx) << cIdteShift].Gate.u1Present = 1; + } + } + + paIdt[(0x80 + iCtx) << cIdteShift].Gate.u16Sel = uSysR0Cs; + paIdt[(0x80 + iCtx) << cIdteShift].Gate.u4Type = bSavedType; + paIdt[(0x80 + iCtx) << cIdteShift].Gate.u1DescType = 0; + paIdt[(0x80 + iCtx) << cIdteShift].Gate.u1Present = 1; + } + } + } + BS3_ASSERT(g_usBs3TestStep < 62000U && g_usBs3TestStep > 32000U); + + + /** @todo + * - Run \#PF and \#GP (and others?) at CPLs other than zero. + * - Quickly generate all faults. + * - All the peculiarities v8086. + */ + +# if TMPL_BITS != 16 + Bs3MemFree(pbIdtCopyAlloc, 12*_1K); +# endif +} + +# if ARCH_BITS != 64 + +/** + * Worker for bs3CpuBasic2_TssGateEsp that tests the INT 80 from outer rings. + */ +# define bs3CpuBasic2_TssGateEsp_AltStackOuterRing BS3_CMN_NM(bs3CpuBasic2_TssGateEsp_AltStackOuterRing) +BS3_DECL_NEAR(void) bs3CpuBasic2_TssGateEsp_AltStackOuterRing(PCBS3REGCTX pCtx, uint8_t bRing, uint8_t *pbAltStack, + size_t cbAltStack, bool f16BitStack, bool f16BitTss, + bool f16BitHandler, unsigned uLine) +{ + uint8_t const cbIretFrame = f16BitHandler ? 5*2 : 5*4; + BS3REGCTX Ctx2; + BS3TRAPFRAME TrapCtx; + uint8_t *pbTmp; + g_usBs3TestStep = uLine; + + Bs3MemCpy(&Ctx2, pCtx, sizeof(Ctx2)); + Bs3RegCtxConvertToRingX(&Ctx2, bRing); + + if (pbAltStack) + { + Ctx2.rsp.u = Bs3SelPtrToFlat(pbAltStack + 0x1980); + Bs3MemZero(pbAltStack, cbAltStack); + } + + Bs3TrapSetJmpAndRestore(&Ctx2, &TrapCtx); + + if (!f16BitStack && f16BitTss) + Ctx2.rsp.u &= UINT16_MAX; + + bs3CpuBasic2_CompareIntCtx1(&TrapCtx, &Ctx2, 0x80 /*bXcpt*/); + CHECK_MEMBER("bCpl", "%u", TrapCtx.Ctx.bCpl, bRing); + CHECK_MEMBER("cbIretFrame", "%#x", TrapCtx.cbIretFrame, cbIretFrame); + + if (pbAltStack) + { + uint64_t uExpectedRsp = (f16BitTss ? Bs3Tss16.sp0 : Bs3Tss32.esp0) - cbIretFrame; + if (f16BitStack) + { + uExpectedRsp &= UINT16_MAX; + uExpectedRsp |= Ctx2.rsp.u & ~(uint64_t)UINT16_MAX; + } + if ( TrapCtx.uHandlerRsp != uExpectedRsp + || TrapCtx.uHandlerSs != (f16BitTss ? Bs3Tss16.ss0 : Bs3Tss32.ss0)) + bs3CpuBasic2_FailedF("handler SS:ESP=%04x:%08RX64, expected %04x:%08RX16", + TrapCtx.uHandlerSs, TrapCtx.uHandlerRsp, Bs3Tss16.ss0, uExpectedRsp); + + pbTmp = (uint8_t *)ASMMemFirstNonZero(pbAltStack, cbAltStack); + if ((f16BitStack || TrapCtx.uHandlerRsp <= UINT16_MAX) && pbTmp != NULL) + bs3CpuBasic2_FailedF("someone touched the alt stack (%p) with SS:ESP=%04x:%#RX32: %p=%02x", + pbAltStack, Ctx2.ss, Ctx2.rsp.u32, pbTmp, *pbTmp); + else if (!f16BitStack && TrapCtx.uHandlerRsp > UINT16_MAX && pbTmp == NULL) + bs3CpuBasic2_FailedF("the alt stack (%p) was not used SS:ESP=%04x:%#RX32\n", pbAltStack, Ctx2.ss, Ctx2.rsp.u32); + } +} + +# define bs3CpuBasic2_TssGateEspCommon BS3_CMN_NM(bs3CpuBasic2_TssGateEspCommon) +BS3_DECL_NEAR(void) bs3CpuBasic2_TssGateEspCommon(bool const g_f16BitSys, PX86DESC const paIdt, unsigned const cIdteShift) +{ + BS3TRAPFRAME TrapCtx; + BS3REGCTX Ctx; + BS3REGCTX Ctx2; +# if TMPL_BITS == 16 + uint8_t *pbTmp; +# endif + + /* make sure they're allocated */ + Bs3MemZero(&Ctx, sizeof(Ctx)); + Bs3MemZero(&Ctx2, sizeof(Ctx2)); + Bs3MemZero(&TrapCtx, sizeof(TrapCtx)); + + Bs3RegCtxSave(&Ctx); + Ctx.rsp.u -= 0x80; + + Bs3RegCtxSetRipCsFromLnkPtr(&Ctx, bs3CpuBasic2_Int80); +# if TMPL_BITS == 32 + g_uBs3TrapEipHint = Ctx.rip.u32; +# endif + + /* + * We'll be using IDT entry 80 and 81 here. The first one will be + * accessible from all DPLs, the latter not. So, start with setting + * the DPLs. + */ + paIdt[0x80 << cIdteShift].Gate.u2Dpl = 3; + paIdt[0x81 << cIdteShift].Gate.u2Dpl = 0; + + /* + * Check that the basic stuff works first. + */ + Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx); + g_usBs3TestStep = __LINE__; + bs3CpuBasic2_CompareIntCtx1(&TrapCtx, &Ctx, 0x80 /*bXcpt*/); + + bs3CpuBasic2_TssGateEsp_AltStackOuterRing(&Ctx, 1, NULL, 0, g_f16BitSys, g_f16BitSys, g_f16BitSys, __LINE__); + bs3CpuBasic2_TssGateEsp_AltStackOuterRing(&Ctx, 2, NULL, 0, g_f16BitSys, g_f16BitSys, g_f16BitSys, __LINE__); + bs3CpuBasic2_TssGateEsp_AltStackOuterRing(&Ctx, 3, NULL, 0, g_f16BitSys, g_f16BitSys, g_f16BitSys, __LINE__); + + /* + * Check that the upper part of ESP is preserved when doing . + */ + if ((g_uBs3CpuDetected & BS3CPU_TYPE_MASK) >= BS3CPU_80386) + { + size_t const cbAltStack = _8K; + uint8_t *pbAltStack = Bs3MemAllocZ(BS3MEMKIND_TILED, cbAltStack); + if (pbAltStack) + { + /* same ring */ + g_usBs3TestStep = __LINE__; + Bs3MemCpy(&Ctx2, &Ctx, sizeof(Ctx2)); + Ctx2.rsp.u = Bs3SelPtrToFlat(pbAltStack + 0x1980); + if (Bs3TrapSetJmp(&TrapCtx)) + Bs3RegCtxRestore(&Ctx2, 0); /* (does not return) */ + bs3CpuBasic2_CompareIntCtx1(&TrapCtx, &Ctx2, 0x80 /*bXcpt*/); +# if TMPL_BITS == 16 + if ((pbTmp = (uint8_t *)ASMMemFirstNonZero(pbAltStack, cbAltStack)) != NULL) + bs3CpuBasic2_FailedF("someone touched the alt stack (%p) with SS:ESP=%04x:%#RX32: %p=%02x\n", + pbAltStack, Ctx2.ss, Ctx2.rsp.u32, pbTmp, *pbTmp); +# else + if (ASMMemIsZero(pbAltStack, cbAltStack)) + bs3CpuBasic2_FailedF("alt stack wasn't used despite SS:ESP=%04x:%#RX32\n", Ctx2.ss, Ctx2.rsp.u32); +# endif + + /* Different rings (load SS0:SP0 from TSS). */ + bs3CpuBasic2_TssGateEsp_AltStackOuterRing(&Ctx, 1, pbAltStack, cbAltStack, + g_f16BitSys, g_f16BitSys, g_f16BitSys, __LINE__); + bs3CpuBasic2_TssGateEsp_AltStackOuterRing(&Ctx, 2, pbAltStack, cbAltStack, + g_f16BitSys, g_f16BitSys, g_f16BitSys, __LINE__); + bs3CpuBasic2_TssGateEsp_AltStackOuterRing(&Ctx, 3, pbAltStack, cbAltStack, + g_f16BitSys, g_f16BitSys, g_f16BitSys, __LINE__); + + /* Different rings but switch the SS bitness in the TSS. */ + if (g_f16BitSys) + { + Bs3Tss16.ss0 = BS3_SEL_R0_SS32; + bs3CpuBasic2_TssGateEsp_AltStackOuterRing(&Ctx, 1, pbAltStack, cbAltStack, + false, g_f16BitSys, g_f16BitSys, __LINE__); + Bs3Tss16.ss0 = BS3_SEL_R0_SS16; + } + else + { + Bs3Tss32.ss0 = BS3_SEL_R0_SS16; + bs3CpuBasic2_TssGateEsp_AltStackOuterRing(&Ctx, 1, pbAltStack, cbAltStack, + true, g_f16BitSys, g_f16BitSys, __LINE__); + Bs3Tss32.ss0 = BS3_SEL_R0_SS32; + } + + Bs3MemFree(pbAltStack, cbAltStack); + } + else + Bs3TestPrintf("%s: Skipping ESP check, alloc failed\n", g_pszTestMode); + } + else + Bs3TestPrintf("%s: Skipping ESP check, CPU too old\n", g_pszTestMode); +} + +# endif /* ARCH_BITS != 64 */ +#endif /* BS3_INSTANTIATING_CMN */ + + +/* + * Mode specific code. + * Mode specific code. + * Mode specific code. + */ +#ifdef BS3_INSTANTIATING_MODE + +BS3_DECL_FAR(uint8_t) TMPL_NM(bs3CpuBasic2_TssGateEsp)(uint8_t bMode) +{ + uint8_t bRet = 0; + + g_pszTestMode = TMPL_NM(g_szBs3ModeName); + g_bTestMode = bMode; + g_f16BitSys = BS3_MODE_IS_16BIT_SYS(TMPL_MODE); + +# if TMPL_MODE == BS3_MODE_PE16 \ + || TMPL_MODE == BS3_MODE_PE16_32 \ + || TMPL_MODE == BS3_MODE_PP16 \ + || TMPL_MODE == BS3_MODE_PP16_32 \ + || TMPL_MODE == BS3_MODE_PAE16 \ + || TMPL_MODE == BS3_MODE_PAE16_32 \ + || TMPL_MODE == BS3_MODE_PE32 + bs3CpuBasic2_TssGateEspCommon(BS3_MODE_IS_16BIT_SYS(TMPL_MODE), + (PX86DESC)MyBs3Idt, + BS3_MODE_IS_64BIT_SYS(TMPL_MODE) ? 1 : 0); +# else + bRet = BS3TESTDOMODE_SKIPPED; +# endif + + /* + * Re-initialize the IDT. + */ + Bs3TrapInit(); + return bRet; +} + + +BS3_DECL_FAR(uint8_t) TMPL_NM(bs3CpuBasic2_RaiseXcpt1)(uint8_t bMode) +{ + g_pszTestMode = TMPL_NM(g_szBs3ModeName); + g_bTestMode = bMode; + g_f16BitSys = BS3_MODE_IS_16BIT_SYS(TMPL_MODE); + +# if !BS3_MODE_IS_RM_OR_V86(TMPL_MODE) + + /* + * Pass to common worker which is only compiled once per mode. + */ + bs3CpuBasic2_RaiseXcpt1Common(MY_SYS_SEL_R0_CS, + MY_SYS_SEL_R0_CS_CNF, + MY_SYS_SEL_R0_SS, + (PX86DESC)MyBs3Idt, + BS3_MODE_IS_64BIT_SYS(TMPL_MODE) ? 1 : 0); + + /* + * Re-initialize the IDT. + */ + Bs3TrapInit(); + return 0; +# elif TMPL_MODE == BS3_MODE_RM + + /* + * Check + */ + /** @todo check */ + return BS3TESTDOMODE_SKIPPED; + +# else + return BS3TESTDOMODE_SKIPPED; +# endif +} + +#endif /* BS3_INSTANTIATING_MODE */ + diff --git a/src/VBox/ValidationKit/bootsectors/bs3-cpu-basic-2-template.mac b/src/VBox/ValidationKit/bootsectors/bs3-cpu-basic-2-template.mac new file mode 100644 index 00000000..e4050869 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3-cpu-basic-2-template.mac @@ -0,0 +1,405 @@ +; $Id: bs3-cpu-basic-2-template.mac $ +;; @file +; BS3Kit - bs3-cpu-basic-2 assembly template. +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + + +;********************************************************************************************************************************* +;* Header Files * +;********************************************************************************************************************************* +%include "bs3kit-template-header.mac" ; setup environment + + +;********************************************************************************************************************************* +;* External Symbols * +;********************************************************************************************************************************* +TMPL_BEGIN_TEXT + + +; +; Test code snippets containing code which differs between 16-bit, 32-bit +; and 64-bit CPUs modes. +; +%ifdef BS3_INSTANTIATING_CMN + +; +; SIDT +; +BS3_PROC_BEGIN_CMN bs3CpuBasic2_sidt_bx_ud2, BS3_PBC_NEAR + sidt [xBX] +.again: ud2 + jmp .again +AssertCompile(.again - BS3_CMN_NM(bs3CpuBasic2_sidt_bx_ud2) == 3) +BS3_PROC_END_CMN bs3CpuBasic2_sidt_bx_ud2 + +BS3_PROC_BEGIN_CMN bs3CpuBasic2_sidt_opsize_bx_ud2, BS3_PBC_NEAR + db X86_OP_PRF_SIZE_OP + sidt [xBX] +.again: ud2 + jmp .again +AssertCompile(.again - BS3_CMN_NM(bs3CpuBasic2_sidt_opsize_bx_ud2) == 4) +BS3_PROC_END_CMN bs3CpuBasic2_sidt_opsize_bx_ud2 + + %if TMPL_BITS == 64 +BS3_PROC_BEGIN_CMN bs3CpuBasic2_sidt_rexw_bx_ud2, BS3_PBC_NEAR + db X86_OP_REX_W + sidt [xBX] +.again: ud2 + jmp .again +AssertCompile(.again - BS3_CMN_NM(bs3CpuBasic2_sidt_rexw_bx_ud2) == 4) +BS3_PROC_END_CMN bs3CpuBasic2_sidt_rexw_bx_ud2 + +BS3_PROC_BEGIN_CMN bs3CpuBasic2_sidt_opsize_rexw_bx_ud2, BS3_PBC_NEAR + db X86_OP_PRF_SIZE_OP + db X86_OP_REX_W + sidt [xBX] +.again: ud2 + jmp .again +AssertCompile(.again - BS3_CMN_NM(bs3CpuBasic2_sidt_opsize_rexw_bx_ud2) == 5) +BS3_PROC_END_CMN bs3CpuBasic2_sidt_opsize_rexw_bx_ud2 + %endif + + %if TMPL_BITS != 64 +BS3_PROC_BEGIN_CMN bs3CpuBasic2_sidt_ss_bx_ud2, BS3_PBC_NEAR + sidt [ss:xBX] +.again: ud2 + jmp .again +AssertCompile(.again - BS3_CMN_NM(bs3CpuBasic2_sidt_ss_bx_ud2) == 4) +BS3_PROC_END_CMN bs3CpuBasic2_sidt_ss_bx_ud2 + +BS3_PROC_BEGIN_CMN bs3CpuBasic2_sidt_opsize_ss_bx_ud2, BS3_PBC_NEAR + db X86_OP_PRF_SIZE_OP + sidt [ss:xBX] +.again: ud2 + jmp .again +AssertCompile(.again - BS3_CMN_NM(bs3CpuBasic2_sidt_opsize_ss_bx_ud2) == 5) +BS3_PROC_END_CMN bs3CpuBasic2_sidt_opsize_ss_bx_ud2 + %endif + + +; +; SGDT +; +BS3_PROC_BEGIN_CMN bs3CpuBasic2_sgdt_bx_ud2, BS3_PBC_NEAR + sgdt [xBX] +.again: ud2 + jmp .again +AssertCompile(.again - BS3_CMN_NM(bs3CpuBasic2_sgdt_bx_ud2) == 3) +BS3_PROC_END_CMN bs3CpuBasic2_sgdt_bx_ud2 + +BS3_PROC_BEGIN_CMN bs3CpuBasic2_sgdt_opsize_bx_ud2, BS3_PBC_NEAR + db X86_OP_PRF_SIZE_OP + sgdt [xBX] +.again: ud2 + jmp .again +AssertCompile(.again - BS3_CMN_NM(bs3CpuBasic2_sgdt_opsize_bx_ud2) == 4) +BS3_PROC_END_CMN bs3CpuBasic2_sgdt_opsize_bx_ud2 + + %if TMPL_BITS == 64 +BS3_PROC_BEGIN_CMN bs3CpuBasic2_sgdt_rexw_bx_ud2, BS3_PBC_NEAR + db X86_OP_REX_W + sgdt [xBX] +.again: ud2 + jmp .again +AssertCompile(.again - BS3_CMN_NM(bs3CpuBasic2_sgdt_rexw_bx_ud2) == 4) +BS3_PROC_END_CMN bs3CpuBasic2_sgdt_rexw_bx_ud2 + +BS3_PROC_BEGIN_CMN bs3CpuBasic2_sgdt_opsize_rexw_bx_ud2, BS3_PBC_NEAR + db X86_OP_PRF_SIZE_OP + db X86_OP_REX_W + sgdt [xBX] +.again: ud2 + jmp .again +AssertCompile(.again - BS3_CMN_NM(bs3CpuBasic2_sgdt_opsize_rexw_bx_ud2) == 5) +BS3_PROC_END_CMN bs3CpuBasic2_sgdt_opsize_rexw_bx_ud2 + %endif + + %if TMPL_BITS != 64 +BS3_PROC_BEGIN_CMN bs3CpuBasic2_sgdt_ss_bx_ud2, BS3_PBC_NEAR + sgdt [ss:xBX] +.again: ud2 + jmp .again +AssertCompile(.again - BS3_CMN_NM(bs3CpuBasic2_sgdt_ss_bx_ud2) == 4) +BS3_PROC_END_CMN bs3CpuBasic2_sgdt_ss_bx_ud2 + +BS3_PROC_BEGIN_CMN bs3CpuBasic2_sgdt_opsize_ss_bx_ud2, BS3_PBC_NEAR + db X86_OP_PRF_SIZE_OP + sgdt [ss:xBX] +.again: ud2 + jmp .again +AssertCompile(.again - BS3_CMN_NM(bs3CpuBasic2_sgdt_opsize_ss_bx_ud2) == 5) +BS3_PROC_END_CMN bs3CpuBasic2_sgdt_opsize_ss_bx_ud2 + %endif + + +; +; LIDT +; +BS3_PROC_BEGIN_CMN bs3CpuBasic2_lidt_bx__sidt_es_di__lidt_es_si__ud2, BS3_PBC_NEAR + lidt [xBX] + sidt [BS3_NOT_64BIT(es:) xDI] + lidt [BS3_NOT_64BIT(es:) xSI] +.again: + ud2 + jmp .again +AssertCompile(.again - BS3_CMN_NM(bs3CpuBasic2_lidt_bx__sidt_es_di__lidt_es_si__ud2) == BS3_IF_64BIT_OTHERWISE(9,11)) +BS3_PROC_END_CMN bs3CpuBasic2_lidt_bx__sidt_es_di__lidt_es_si__ud2 + +BS3_PROC_BEGIN_CMN bs3CpuBasic2_lidt_opsize_bx__sidt_es_di__lidt_es_si__ud2, BS3_PBC_NEAR + db X86_OP_PRF_SIZE_OP + lidt [xBX] + sidt [BS3_NOT_64BIT(es:) xDI] + lidt [BS3_NOT_64BIT(es:) xSI] +.again: + ud2 + jmp .again +AssertCompile(.again - BS3_CMN_NM(bs3CpuBasic2_lidt_opsize_bx__sidt_es_di__lidt_es_si__ud2) == BS3_IF_64BIT_OTHERWISE(10,12)) +BS3_PROC_END_CMN bs3CpuBasic2_lidt_opsize_bx__sidt_es_di__lidt_es_si__ud2 + +%if TMPL_BITS == 16 +BS3_PROC_BEGIN_CMN bs3CpuBasic2_lidt_opsize_bx__sidt32_es_di__lidt_es_si__ud2, BS3_PBC_NEAR + db X86_OP_PRF_SIZE_OP + lidt [xBX] + jmp dword BS3_SEL_R0_CS32:.in_32bit wrt FLAT + BS3_SET_BITS 32 +.in_32bit: + sidt [es:edi] + lidt [es:esi] + jmp dword BS3_SEL_R0_CS16:.again wrt CGROUP16 + BS3_SET_BITS 16 +.again: + ud2 + jmp .again +AssertCompile(.again - BS3_CMN_NM(bs3CpuBasic2_lidt_opsize_bx__sidt32_es_di__lidt_es_si__ud2) == 27) +BS3_PROC_END_CMN bs3CpuBasic2_lidt_opsize_bx__sidt32_es_di__lidt_es_si__ud2 +%endif + + %if TMPL_BITS == 64 +BS3_PROC_BEGIN_CMN bs3CpuBasic2_lidt_rexw_bx__sidt_es_di__lidt_es_si__ud2, BS3_PBC_NEAR + db X86_OP_REX_W + lidt [xBX] + sidt [xDI] + lidt [xSI] +.again: + ud2 + jmp .again +AssertCompile(.again - BS3_CMN_NM(bs3CpuBasic2_lidt_rexw_bx__sidt_es_di__lidt_es_si__ud2) == 10) +BS3_PROC_END_CMN bs3CpuBasic2_lidt_rexw_bx__sidt_es_di__lidt_es_si__ud2 + +BS3_PROC_BEGIN_CMN bs3CpuBasic2_lidt_opsize_rexw_bx__sidt_es_di__lidt_es_si__ud2, BS3_PBC_NEAR + db X86_OP_PRF_SIZE_OP + db X86_OP_REX_W + lidt [xBX] + sidt [xDI] + lidt [xSI] +.again: + ud2 + jmp .again +AssertCompile(.again - BS3_CMN_NM(bs3CpuBasic2_lidt_opsize_rexw_bx__sidt_es_di__lidt_es_si__ud2) == 11) +BS3_PROC_END_CMN bs3CpuBasic2_lidt_opsize_rexw_bx__sidt_es_di__lidt_es_si__ud2 + %endif + + %if TMPL_BITS != 64 +BS3_PROC_BEGIN_CMN bs3CpuBasic2_lidt_ss_bx__sidt_es_di__lidt_es_si__ud2, BS3_PBC_NEAR + lidt [ss:xBX] + sidt [BS3_NOT_64BIT(es:) xDI] + lidt [BS3_NOT_64BIT(es:) xSI] +.again: + ud2 + jmp .again +AssertCompile(.again - BS3_CMN_NM(bs3CpuBasic2_lidt_ss_bx__sidt_es_di__lidt_es_si__ud2) == 12) +BS3_PROC_END_CMN bs3CpuBasic2_lidt_ss_bx__sidt_es_di__lidt_es_si__ud2 + +BS3_PROC_BEGIN_CMN bs3CpuBasic2_lidt_opsize_ss_bx__sidt_es_di__lidt_es_si__ud2, BS3_PBC_NEAR + db X86_OP_PRF_SIZE_OP + lidt [ss:xBX] + sidt [BS3_NOT_64BIT(es:) xDI] + lidt [BS3_NOT_64BIT(es:) xSI] +.again: + ud2 + jmp .again +AssertCompile(.again - BS3_CMN_NM(bs3CpuBasic2_lidt_opsize_ss_bx__sidt_es_di__lidt_es_si__ud2) == 13) +BS3_PROC_END_CMN bs3CpuBasic2_lidt_opsize_ss_bx__sidt_es_di__lidt_es_si__ud2 + %endif + + +; +; LGDT +; +BS3_PROC_BEGIN_CMN bs3CpuBasic2_lgdt_bx__sgdt_es_di__lgdt_es_si__ud2, BS3_PBC_NEAR + lgdt [xBX] + sgdt [BS3_NOT_64BIT(es:) xDI] + lgdt [BS3_NOT_64BIT(es:) xSI] +.again: + ud2 + jmp .again +AssertCompile(.again - BS3_CMN_NM(bs3CpuBasic2_lgdt_bx__sgdt_es_di__lgdt_es_si__ud2) == BS3_IF_64BIT_OTHERWISE(9,11)) +BS3_PROC_END_CMN bs3CpuBasic2_lgdt_bx__sgdt_es_di__lgdt_es_si__ud2 + +BS3_PROC_BEGIN_CMN bs3CpuBasic2_lgdt_opsize_bx__sgdt_es_di__lgdt_es_si__ud2, BS3_PBC_NEAR + db X86_OP_PRF_SIZE_OP + lgdt [xBX] + sgdt [BS3_NOT_64BIT(es:) xDI] + lgdt [BS3_NOT_64BIT(es:) xSI] +.again: + ud2 + jmp .again +AssertCompile(.again - BS3_CMN_NM(bs3CpuBasic2_lgdt_opsize_bx__sgdt_es_di__lgdt_es_si__ud2) == BS3_IF_64BIT_OTHERWISE(10,12)) +BS3_PROC_END_CMN bs3CpuBasic2_lgdt_opsize_bx__sgdt_es_di__lgdt_es_si__ud2 + + %if TMPL_BITS == 64 +BS3_PROC_BEGIN_CMN bs3CpuBasic2_lgdt_rexw_bx__sgdt_es_di__lgdt_es_si__ud2, BS3_PBC_NEAR + db X86_OP_REX_W + lgdt [xBX] + sgdt [xDI] + lgdt [xSI] +.again: + ud2 + jmp .again +AssertCompile(.again - BS3_CMN_NM(bs3CpuBasic2_lgdt_rexw_bx__sgdt_es_di__lgdt_es_si__ud2) == 10) +BS3_PROC_END_CMN bs3CpuBasic2_lgdt_rexw_bx__sgdt_es_di__lgdt_es_si__ud2 + +BS3_PROC_BEGIN_CMN bs3CpuBasic2_lgdt_opsize_rexw_bx__sgdt_es_di__lgdt_es_si__ud2, BS3_PBC_NEAR + db X86_OP_PRF_SIZE_OP + db X86_OP_REX_W + lgdt [xBX] + sgdt [xDI] + lgdt [xSI] +.again: + ud2 + jmp .again +AssertCompile(.again - BS3_CMN_NM(bs3CpuBasic2_lgdt_opsize_rexw_bx__sgdt_es_di__lgdt_es_si__ud2) == 11) +BS3_PROC_END_CMN bs3CpuBasic2_lgdt_opsize_rexw_bx__sgdt_es_di__lgdt_es_si__ud2 + %endif + + %if TMPL_BITS != 64 +BS3_PROC_BEGIN_CMN bs3CpuBasic2_lgdt_ss_bx__sgdt_es_di__lgdt_es_si__ud2, BS3_PBC_NEAR + lgdt [ss:xBX] + sgdt [BS3_NOT_64BIT(es:) xDI] + lgdt [BS3_NOT_64BIT(es:) xSI] +.again: + ud2 + jmp .again +AssertCompile(.again - BS3_CMN_NM(bs3CpuBasic2_lgdt_ss_bx__sgdt_es_di__lgdt_es_si__ud2) == 12) +BS3_PROC_END_CMN bs3CpuBasic2_lgdt_ss_bx__sgdt_es_di__lgdt_es_si__ud2 + +BS3_PROC_BEGIN_CMN bs3CpuBasic2_lgdt_opsize_ss_bx__sgdt_es_di__lgdt_es_si__ud2, BS3_PBC_NEAR + db X86_OP_PRF_SIZE_OP + lgdt [ss:xBX] + sgdt [BS3_NOT_64BIT(es:) xDI] + lgdt [BS3_NOT_64BIT(es:) xSI] +.again: + ud2 + jmp .again +AssertCompile(.again - BS3_CMN_NM(bs3CpuBasic2_lgdt_opsize_ss_bx__sgdt_es_di__lgdt_es_si__ud2) == 13) +BS3_PROC_END_CMN bs3CpuBasic2_lgdt_opsize_ss_bx__sgdt_es_di__lgdt_es_si__ud2 + %endif + +; +; #PF +; + +; For testing read access. +BS3_PROC_BEGIN_CMN bs3CpuBasic2_mov_ax_ds_bx__ud2, BS3_PBC_NEAR + mov xAX, [xBX] +.again: ud2 + jmp .again +AssertCompile(.again - BS3_LAST_LABEL == 2 + (TMPL_BITS == 64)) +BS3_PROC_END_CMN bs3CpuBasic2_mov_ax_ds_bx__ud2 + + +; For testing write access. +BS3_PROC_BEGIN_CMN bs3CpuBasic2_mov_ds_bx_ax__ud2, BS3_PBC_NEAR + mov [xBX], xAX +.again: ud2 + jmp .again +AssertCompile(.again - BS3_LAST_LABEL == 2 + (TMPL_BITS == 64)) +BS3_PROC_END_CMN bs3CpuBasic2_mov_ds_bx_ax__ud2 + + +; For testing read+write access. +BS3_PROC_BEGIN_CMN bs3CpuBasic2_xchg_ds_bx_ax__ud2, BS3_PBC_NEAR + xchg [xBX], xAX +.again: ud2 + jmp .again +AssertCompile(.again - BS3_LAST_LABEL == 2 + (TMPL_BITS == 64)) +BS3_PROC_END_CMN bs3CpuBasic2_xchg_ds_bx_ax__ud2 + + +; Another read+write access test. +BS3_PROC_BEGIN_CMN bs3CpuBasic2_cmpxchg_ds_bx_cx__ud2, BS3_PBC_NEAR + cmpxchg [xBX], xCX +.again: ud2 + jmp .again +AssertCompile(.again - BS3_LAST_LABEL == 3 + (TMPL_BITS == 64)) +BS3_PROC_END_CMN bs3CpuBasic2_cmpxchg_ds_bx_cx__ud2 + + +; For testing read access from an aborted instruction: DIV by zero +BS3_PROC_BEGIN_CMN bs3CpuBasic2_div_ds_bx__ud2, BS3_PBC_NEAR + div xPRE [xBX] +.again: ud2 + jmp .again +AssertCompile(.again - BS3_LAST_LABEL == 2 + (TMPL_BITS == 64)) +BS3_PROC_END_CMN bs3CpuBasic2_div_ds_bx__ud2 + + +; Two memory operands: push [mem] +BS3_PROC_BEGIN_CMN bs3CpuBasic2_push_ds_bx__ud2, BS3_PBC_NEAR + push xPRE [xBX] +.again: ud2 + jmp .again +AssertCompile(.again - BS3_LAST_LABEL == 2) +BS3_PROC_END_CMN bs3CpuBasic2_push_ds_bx__ud2 + +; Two memory operands: pop [mem] +BS3_PROC_BEGIN_CMN bs3CpuBasic2_push_ax__pop_ds_bx__ud2, BS3_PBC_NEAR + push xAX + pop xPRE [xBX] +.again: ud2 + jmp .again +AssertCompile(.again - BS3_LAST_LABEL == 3) +BS3_PROC_END_CMN bs3CpuBasic2_push_ax__pop_ds_bx__ud2 + +; Two memory operands: call [mem] +BS3_PROC_BEGIN_CMN bs3CpuBasic2_call_ds_bx__ud2, BS3_PBC_NEAR + call xPRE [xBX] +.again: ud2 + jmp .again +AssertCompile(.again - BS3_LAST_LABEL == 2) +BS3_PROC_END_CMN bs3CpuBasic2_call_ds_bx__ud2 + +; For testing #GP vs #PF write +BS3_PROC_BEGIN_CMN bs3CpuBasic2_insb__ud2, BS3_PBC_NEAR + insb +.again: ud2 + jmp .again +AssertCompile(.again - BS3_LAST_LABEL == 1) +BS3_PROC_END_CMN bs3CpuBasic2_insb__ud2 + + +%endif ; BS3_INSTANTIATING_CMN + +%include "bs3kit-template-footer.mac" ; reset environment + diff --git a/src/VBox/ValidationKit/bootsectors/bs3-cpu-basic-2-x0.c b/src/VBox/ValidationKit/bootsectors/bs3-cpu-basic-2-x0.c new file mode 100644 index 00000000..413eee39 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3-cpu-basic-2-x0.c @@ -0,0 +1,3225 @@ +/* $Id: bs3-cpu-basic-2-x0.c $ */ +/** @file + * BS3Kit - bs3-cpu-basic-2, C test driver code (16-bit). + */ + +/* + * Copyright (C) 2007-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#define BS3_USE_X0_TEXT_SEG +#include <bs3kit.h> +#include <iprt/asm.h> +#include <iprt/asm-amd64-x86.h> + + +/********************************************************************************************************************************* +* Defined Constants And Macros * +*********************************************************************************************************************************/ +#undef CHECK_MEMBER +#define CHECK_MEMBER(a_szName, a_szFmt, a_Actual, a_Expected) \ + do \ + { \ + if ((a_Actual) == (a_Expected)) { /* likely */ } \ + else bs3CpuBasic2_FailedF(a_szName "=" a_szFmt " expected " a_szFmt, (a_Actual), (a_Expected)); \ + } while (0) + + +/** Indicating that we've got operand size prefix and that it matters. */ +#define BS3CB2SIDTSGDT_F_OPSIZE UINT8_C(0x01) +/** Worker requires 386 or later. */ +#define BS3CB2SIDTSGDT_F_386PLUS UINT8_C(0x02) + + +/********************************************************************************************************************************* +* Structures and Typedefs * +*********************************************************************************************************************************/ +typedef struct BS3CB2INVLDESCTYPE +{ + uint8_t u4Type; + uint8_t u1DescType; +} BS3CB2INVLDESCTYPE; + +typedef struct BS3CB2SIDTSGDT +{ + const char *pszDesc; + FPFNBS3FAR fpfnWorker; + uint8_t cbInstr; + bool fSs; + uint8_t bMode; + uint8_t fFlags; +} BS3CB2SIDTSGDT; + + +/********************************************************************************************************************************* +* External Symbols * +*********************************************************************************************************************************/ +extern FNBS3FAR bs3CpuBasic2_Int80; +extern FNBS3FAR bs3CpuBasic2_Int81; +extern FNBS3FAR bs3CpuBasic2_Int82; +extern FNBS3FAR bs3CpuBasic2_Int83; + +extern FNBS3FAR bs3CpuBasic2_ud2; +#define g_bs3CpuBasic2_ud2_FlatAddr BS3_DATA_NM(g_bs3CpuBasic2_ud2_FlatAddr) +extern uint32_t g_bs3CpuBasic2_ud2_FlatAddr; + +extern FNBS3FAR bs3CpuBasic2_iret; +extern FNBS3FAR bs3CpuBasic2_iret_opsize; +extern FNBS3FAR bs3CpuBasic2_iret_rexw; + +extern FNBS3FAR bs3CpuBasic2_sidt_bx_ud2_c16; +extern FNBS3FAR bs3CpuBasic2_sidt_bx_ud2_c32; +extern FNBS3FAR bs3CpuBasic2_sidt_bx_ud2_c64; +extern FNBS3FAR bs3CpuBasic2_sidt_ss_bx_ud2_c16; +extern FNBS3FAR bs3CpuBasic2_sidt_ss_bx_ud2_c32; +extern FNBS3FAR bs3CpuBasic2_sidt_rexw_bx_ud2_c64; +extern FNBS3FAR bs3CpuBasic2_sidt_opsize_bx_ud2_c16; +extern FNBS3FAR bs3CpuBasic2_sidt_opsize_bx_ud2_c32; +extern FNBS3FAR bs3CpuBasic2_sidt_opsize_bx_ud2_c64; +extern FNBS3FAR bs3CpuBasic2_sidt_opsize_ss_bx_ud2_c16; +extern FNBS3FAR bs3CpuBasic2_sidt_opsize_ss_bx_ud2_c32; +extern FNBS3FAR bs3CpuBasic2_sidt_opsize_rexw_bx_ud2_c64; + +extern FNBS3FAR bs3CpuBasic2_sgdt_bx_ud2_c16; +extern FNBS3FAR bs3CpuBasic2_sgdt_bx_ud2_c32; +extern FNBS3FAR bs3CpuBasic2_sgdt_bx_ud2_c64; +extern FNBS3FAR bs3CpuBasic2_sgdt_ss_bx_ud2_c16; +extern FNBS3FAR bs3CpuBasic2_sgdt_ss_bx_ud2_c32; +extern FNBS3FAR bs3CpuBasic2_sgdt_rexw_bx_ud2_c64; +extern FNBS3FAR bs3CpuBasic2_sgdt_opsize_bx_ud2_c16; +extern FNBS3FAR bs3CpuBasic2_sgdt_opsize_bx_ud2_c32; +extern FNBS3FAR bs3CpuBasic2_sgdt_opsize_bx_ud2_c64; +extern FNBS3FAR bs3CpuBasic2_sgdt_opsize_ss_bx_ud2_c16; +extern FNBS3FAR bs3CpuBasic2_sgdt_opsize_ss_bx_ud2_c32; +extern FNBS3FAR bs3CpuBasic2_sgdt_opsize_rexw_bx_ud2_c64; + +extern FNBS3FAR bs3CpuBasic2_lidt_bx__sidt_es_di__lidt_es_si__ud2_c16; +extern FNBS3FAR bs3CpuBasic2_lidt_bx__sidt_es_di__lidt_es_si__ud2_c32; +extern FNBS3FAR bs3CpuBasic2_lidt_bx__sidt_es_di__lidt_es_si__ud2_c64; +extern FNBS3FAR bs3CpuBasic2_lidt_ss_bx__sidt_es_di__lidt_es_si__ud2_c16; +extern FNBS3FAR bs3CpuBasic2_lidt_ss_bx__sidt_es_di__lidt_es_si__ud2_c32; +extern FNBS3FAR bs3CpuBasic2_lidt_rexw_bx__sidt_es_di__lidt_es_si__ud2_c64; +extern FNBS3FAR bs3CpuBasic2_lidt_opsize_bx__sidt_es_di__lidt_es_si__ud2_c16; +extern FNBS3FAR bs3CpuBasic2_lidt_opsize_bx__sidt32_es_di__lidt_es_si__ud2_c16; +extern FNBS3FAR bs3CpuBasic2_lidt_opsize_bx__sidt_es_di__lidt_es_si__ud2_c32; +extern FNBS3FAR bs3CpuBasic2_lidt_opsize_bx__sidt_es_di__lidt_es_si__ud2_c64; +extern FNBS3FAR bs3CpuBasic2_lidt_opsize_ss_bx__sidt_es_di__lidt_es_si__ud2_c16; +extern FNBS3FAR bs3CpuBasic2_lidt_opsize_ss_bx__sidt_es_di__lidt_es_si__ud2_c32; +extern FNBS3FAR bs3CpuBasic2_lidt_opsize_rexw_bx__sidt_es_di__lidt_es_si__ud2_c64; + +extern FNBS3FAR bs3CpuBasic2_lgdt_bx__sgdt_es_di__lgdt_es_si__ud2_c16; +extern FNBS3FAR bs3CpuBasic2_lgdt_bx__sgdt_es_di__lgdt_es_si__ud2_c32; +extern FNBS3FAR bs3CpuBasic2_lgdt_bx__sgdt_es_di__lgdt_es_si__ud2_c64; +extern FNBS3FAR bs3CpuBasic2_lgdt_ss_bx__sgdt_es_di__lgdt_es_si__ud2_c16; +extern FNBS3FAR bs3CpuBasic2_lgdt_ss_bx__sgdt_es_di__lgdt_es_si__ud2_c32; +extern FNBS3FAR bs3CpuBasic2_lgdt_rexw_bx__sgdt_es_di__lgdt_es_si__ud2_c64; +extern FNBS3FAR bs3CpuBasic2_lgdt_opsize_bx__sgdt_es_di__lgdt_es_si__ud2_c16; +extern FNBS3FAR bs3CpuBasic2_lgdt_opsize_bx__sgdt_es_di__lgdt_es_si__ud2_c32; +extern FNBS3FAR bs3CpuBasic2_lgdt_opsize_bx__sgdt_es_di__lgdt_es_si__ud2_c64; +extern FNBS3FAR bs3CpuBasic2_lgdt_opsize_ss_bx__sgdt_es_di__lgdt_es_si__ud2_c16; +extern FNBS3FAR bs3CpuBasic2_lgdt_opsize_ss_bx__sgdt_es_di__lgdt_es_si__ud2_c32; +extern FNBS3FAR bs3CpuBasic2_lgdt_opsize_rexw_bx__sgdt_es_di__lgdt_es_si__ud2_c64; + + + +/********************************************************************************************************************************* +* Global Variables * +*********************************************************************************************************************************/ +static const char BS3_FAR *g_pszTestMode = (const char *)1; +static uint8_t g_bTestMode = 1; +static bool g_f16BitSys = 1; + + +/** SIDT test workers. */ +static BS3CB2SIDTSGDT const g_aSidtWorkers[] = +{ + { "sidt [bx]", bs3CpuBasic2_sidt_bx_ud2_c16, 3, false, BS3_MODE_CODE_16 | BS3_MODE_CODE_V86, 0 }, + { "sidt [ss:bx]", bs3CpuBasic2_sidt_ss_bx_ud2_c16, 4, true, BS3_MODE_CODE_16 | BS3_MODE_CODE_V86, 0 }, + { "o32 sidt [bx]", bs3CpuBasic2_sidt_opsize_bx_ud2_c16, 4, false, BS3_MODE_CODE_16 | BS3_MODE_CODE_V86, BS3CB2SIDTSGDT_F_386PLUS }, + { "o32 sidt [ss:bx]", bs3CpuBasic2_sidt_opsize_ss_bx_ud2_c16, 5, true, BS3_MODE_CODE_16 | BS3_MODE_CODE_V86, BS3CB2SIDTSGDT_F_386PLUS }, + { "sidt [ebx]", bs3CpuBasic2_sidt_bx_ud2_c32, 3, false, BS3_MODE_CODE_32, 0 }, + { "sidt [ss:ebx]", bs3CpuBasic2_sidt_ss_bx_ud2_c32, 4, true, BS3_MODE_CODE_32, 0 }, + { "o16 sidt [ebx]", bs3CpuBasic2_sidt_opsize_bx_ud2_c32, 4, false, BS3_MODE_CODE_32, 0 }, + { "o16 sidt [ss:ebx]", bs3CpuBasic2_sidt_opsize_ss_bx_ud2_c32, 5, true, BS3_MODE_CODE_32, 0 }, + { "sidt [rbx]", bs3CpuBasic2_sidt_bx_ud2_c64, 3, false, BS3_MODE_CODE_64, 0 }, + { "o64 sidt [rbx]", bs3CpuBasic2_sidt_rexw_bx_ud2_c64, 4, false, BS3_MODE_CODE_64, 0 }, + { "o32 sidt [rbx]", bs3CpuBasic2_sidt_opsize_bx_ud2_c64, 4, false, BS3_MODE_CODE_64, 0 }, + { "o32 o64 sidt [rbx]", bs3CpuBasic2_sidt_opsize_rexw_bx_ud2_c64, 5, false, BS3_MODE_CODE_64, 0 }, +}; + +/** SGDT test workers. */ +static BS3CB2SIDTSGDT const g_aSgdtWorkers[] = +{ + { "sgdt [bx]", bs3CpuBasic2_sgdt_bx_ud2_c16, 3, false, BS3_MODE_CODE_16 | BS3_MODE_CODE_V86, 0 }, + { "sgdt [ss:bx]", bs3CpuBasic2_sgdt_ss_bx_ud2_c16, 4, true, BS3_MODE_CODE_16 | BS3_MODE_CODE_V86, 0 }, + { "o32 sgdt [bx]", bs3CpuBasic2_sgdt_opsize_bx_ud2_c16, 4, false, BS3_MODE_CODE_16 | BS3_MODE_CODE_V86, BS3CB2SIDTSGDT_F_386PLUS }, + { "o32 sgdt [ss:bx]", bs3CpuBasic2_sgdt_opsize_ss_bx_ud2_c16, 5, true, BS3_MODE_CODE_16 | BS3_MODE_CODE_V86, BS3CB2SIDTSGDT_F_386PLUS }, + { "sgdt [ebx]", bs3CpuBasic2_sgdt_bx_ud2_c32, 3, false, BS3_MODE_CODE_32, 0 }, + { "sgdt [ss:ebx]", bs3CpuBasic2_sgdt_ss_bx_ud2_c32, 4, true, BS3_MODE_CODE_32, 0 }, + { "o16 sgdt [ebx]", bs3CpuBasic2_sgdt_opsize_bx_ud2_c32, 4, false, BS3_MODE_CODE_32, 0 }, + { "o16 sgdt [ss:ebx]", bs3CpuBasic2_sgdt_opsize_ss_bx_ud2_c32, 5, true, BS3_MODE_CODE_32, 0 }, + { "sgdt [rbx]", bs3CpuBasic2_sgdt_bx_ud2_c64, 3, false, BS3_MODE_CODE_64, 0 }, + { "o64 sgdt [rbx]", bs3CpuBasic2_sgdt_rexw_bx_ud2_c64, 4, false, BS3_MODE_CODE_64, 0 }, + { "o32 sgdt [rbx]", bs3CpuBasic2_sgdt_opsize_bx_ud2_c64, 4, false, BS3_MODE_CODE_64, 0 }, + { "o32 o64 sgdt [rbx]", bs3CpuBasic2_sgdt_opsize_rexw_bx_ud2_c64, 5, false, BS3_MODE_CODE_64, 0 }, +}; + +/** LIDT test workers. */ +static BS3CB2SIDTSGDT const g_aLidtWorkers[] = +{ + { "lidt [bx]", bs3CpuBasic2_lidt_bx__sidt_es_di__lidt_es_si__ud2_c16, 11, false, BS3_MODE_CODE_16 | BS3_MODE_CODE_V86, 0 }, + { "lidt [ss:bx]", bs3CpuBasic2_lidt_ss_bx__sidt_es_di__lidt_es_si__ud2_c16, 12, true, BS3_MODE_CODE_16 | BS3_MODE_CODE_V86, 0 }, + { "o32 lidt [bx]", bs3CpuBasic2_lidt_opsize_bx__sidt_es_di__lidt_es_si__ud2_c16, 12, false, BS3_MODE_CODE_16 | BS3_MODE_CODE_V86, BS3CB2SIDTSGDT_F_OPSIZE | BS3CB2SIDTSGDT_F_386PLUS }, + { "o32 lidt [bx]; sidt32", bs3CpuBasic2_lidt_opsize_bx__sidt32_es_di__lidt_es_si__ud2_c16, 27, false, BS3_MODE_CODE_16 | BS3_MODE_CODE_V86, BS3CB2SIDTSGDT_F_OPSIZE | BS3CB2SIDTSGDT_F_386PLUS }, + { "o32 lidt [ss:bx]", bs3CpuBasic2_lidt_opsize_ss_bx__sidt_es_di__lidt_es_si__ud2_c16, 13, true, BS3_MODE_CODE_16 | BS3_MODE_CODE_V86, BS3CB2SIDTSGDT_F_OPSIZE | BS3CB2SIDTSGDT_F_386PLUS }, + { "lidt [ebx]", bs3CpuBasic2_lidt_bx__sidt_es_di__lidt_es_si__ud2_c32, 11, false, BS3_MODE_CODE_32, 0 }, + { "lidt [ss:ebx]", bs3CpuBasic2_lidt_ss_bx__sidt_es_di__lidt_es_si__ud2_c32, 12, true, BS3_MODE_CODE_32, 0 }, + { "o16 lidt [ebx]", bs3CpuBasic2_lidt_opsize_bx__sidt_es_di__lidt_es_si__ud2_c32, 12, false, BS3_MODE_CODE_32, BS3CB2SIDTSGDT_F_OPSIZE }, + { "o16 lidt [ss:ebx]", bs3CpuBasic2_lidt_opsize_ss_bx__sidt_es_di__lidt_es_si__ud2_c32, 13, true, BS3_MODE_CODE_32, BS3CB2SIDTSGDT_F_OPSIZE }, + { "lidt [rbx]", bs3CpuBasic2_lidt_bx__sidt_es_di__lidt_es_si__ud2_c64, 9, false, BS3_MODE_CODE_64, 0 }, + { "o64 lidt [rbx]", bs3CpuBasic2_lidt_rexw_bx__sidt_es_di__lidt_es_si__ud2_c64, 10, false, BS3_MODE_CODE_64, 0 }, + { "o32 lidt [rbx]", bs3CpuBasic2_lidt_opsize_bx__sidt_es_di__lidt_es_si__ud2_c64, 10, false, BS3_MODE_CODE_64, 0 }, + { "o32 o64 lidt [rbx]", bs3CpuBasic2_lidt_opsize_rexw_bx__sidt_es_di__lidt_es_si__ud2_c64, 11, false, BS3_MODE_CODE_64, 0 }, +}; + +/** LGDT test workers. */ +static BS3CB2SIDTSGDT const g_aLgdtWorkers[] = +{ + { "lgdt [bx]", bs3CpuBasic2_lgdt_bx__sgdt_es_di__lgdt_es_si__ud2_c16, 11, false, BS3_MODE_CODE_16 | BS3_MODE_CODE_V86, 0 }, + { "lgdt [ss:bx]", bs3CpuBasic2_lgdt_ss_bx__sgdt_es_di__lgdt_es_si__ud2_c16, 12, true, BS3_MODE_CODE_16 | BS3_MODE_CODE_V86, 0 }, + { "o32 lgdt [bx]", bs3CpuBasic2_lgdt_opsize_bx__sgdt_es_di__lgdt_es_si__ud2_c16, 12, false, BS3_MODE_CODE_16 | BS3_MODE_CODE_V86, BS3CB2SIDTSGDT_F_OPSIZE | BS3CB2SIDTSGDT_F_386PLUS }, + { "o32 lgdt [ss:bx]", bs3CpuBasic2_lgdt_opsize_ss_bx__sgdt_es_di__lgdt_es_si__ud2_c16, 13, true, BS3_MODE_CODE_16 | BS3_MODE_CODE_V86, BS3CB2SIDTSGDT_F_OPSIZE | BS3CB2SIDTSGDT_F_386PLUS }, + { "lgdt [ebx]", bs3CpuBasic2_lgdt_bx__sgdt_es_di__lgdt_es_si__ud2_c32, 11, false, BS3_MODE_CODE_32, 0 }, + { "lgdt [ss:ebx]", bs3CpuBasic2_lgdt_ss_bx__sgdt_es_di__lgdt_es_si__ud2_c32, 12, true, BS3_MODE_CODE_32, 0 }, + { "o16 lgdt [ebx]", bs3CpuBasic2_lgdt_opsize_bx__sgdt_es_di__lgdt_es_si__ud2_c32, 12, false, BS3_MODE_CODE_32, BS3CB2SIDTSGDT_F_OPSIZE }, + { "o16 lgdt [ss:ebx]", bs3CpuBasic2_lgdt_opsize_ss_bx__sgdt_es_di__lgdt_es_si__ud2_c32, 13, true, BS3_MODE_CODE_32, BS3CB2SIDTSGDT_F_OPSIZE }, + { "lgdt [rbx]", bs3CpuBasic2_lgdt_bx__sgdt_es_di__lgdt_es_si__ud2_c64, 9, false, BS3_MODE_CODE_64, 0 }, + { "o64 lgdt [rbx]", bs3CpuBasic2_lgdt_rexw_bx__sgdt_es_di__lgdt_es_si__ud2_c64, 10, false, BS3_MODE_CODE_64, 0 }, + { "o32 lgdt [rbx]", bs3CpuBasic2_lgdt_opsize_bx__sgdt_es_di__lgdt_es_si__ud2_c64, 10, false, BS3_MODE_CODE_64, 0 }, + { "o32 o64 lgdt [rbx]", bs3CpuBasic2_lgdt_opsize_rexw_bx__sgdt_es_di__lgdt_es_si__ud2_c64, 11, false, BS3_MODE_CODE_64, 0 }, +}; + + + +#if 0 +/** Table containing invalid CS selector types. */ +static const BS3CB2INVLDESCTYPE g_aInvalidCsTypes[] = +{ + { X86_SEL_TYPE_RO, 1 }, + { X86_SEL_TYPE_RO_ACC, 1 }, + { X86_SEL_TYPE_RW, 1 }, + { X86_SEL_TYPE_RW_ACC, 1 }, + { X86_SEL_TYPE_RO_DOWN, 1 }, + { X86_SEL_TYPE_RO_DOWN_ACC, 1 }, + { X86_SEL_TYPE_RW_DOWN, 1 }, + { X86_SEL_TYPE_RW_DOWN_ACC, 1 }, + { 0, 0 }, + { 1, 0 }, + { 2, 0 }, + { 3, 0 }, + { 4, 0 }, + { 5, 0 }, + { 6, 0 }, + { 7, 0 }, + { 8, 0 }, + { 9, 0 }, + { 10, 0 }, + { 11, 0 }, + { 12, 0 }, + { 13, 0 }, + { 14, 0 }, + { 15, 0 }, +}; + +/** Table containing invalid SS selector types. */ +static const BS3CB2INVLDESCTYPE g_aInvalidSsTypes[] = +{ + { X86_SEL_TYPE_EO, 1 }, + { X86_SEL_TYPE_EO_ACC, 1 }, + { X86_SEL_TYPE_ER, 1 }, + { X86_SEL_TYPE_ER_ACC, 1 }, + { X86_SEL_TYPE_EO_CONF, 1 }, + { X86_SEL_TYPE_EO_CONF_ACC, 1 }, + { X86_SEL_TYPE_ER_CONF, 1 }, + { X86_SEL_TYPE_ER_CONF_ACC, 1 }, + { 0, 0 }, + { 1, 0 }, + { 2, 0 }, + { 3, 0 }, + { 4, 0 }, + { 5, 0 }, + { 6, 0 }, + { 7, 0 }, + { 8, 0 }, + { 9, 0 }, + { 10, 0 }, + { 11, 0 }, + { 12, 0 }, + { 13, 0 }, + { 14, 0 }, + { 15, 0 }, +}; +#endif + + +/** + * Sets globals according to the mode. + * + * @param bTestMode The test mode. + */ +static void bs3CpuBasic2_SetGlobals(uint8_t bTestMode) +{ + g_bTestMode = bTestMode; + g_pszTestMode = Bs3GetModeName(bTestMode); + g_f16BitSys = BS3_MODE_IS_16BIT_SYS(bTestMode); + g_usBs3TestStep = 0; +} + + +/** + * Wrapper around Bs3TestFailedF that prefixes the error with g_usBs3TestStep + * and g_pszTestMode. + */ +static void bs3CpuBasic2_FailedF(const char *pszFormat, ...) +{ + va_list va; + + char szTmp[168]; + va_start(va, pszFormat); + Bs3StrPrintfV(szTmp, sizeof(szTmp), pszFormat, va); + va_end(va); + + Bs3TestFailedF("%u - %s: %s", g_usBs3TestStep, g_pszTestMode, szTmp); +} + + +#if 0 +/** + * Compares trap stuff. + */ +static void bs3CpuBasic2_CompareIntCtx1(PCBS3TRAPFRAME pTrapCtx, PCBS3REGCTX pStartCtx, uint8_t bXcpt) +{ + uint16_t const cErrorsBefore = Bs3TestSubErrorCount(); + CHECK_MEMBER("bXcpt", "%#04x", pTrapCtx->bXcpt, bXcpt); + CHECK_MEMBER("bErrCd", "%#06RX64", pTrapCtx->uErrCd, 0); + Bs3TestCheckRegCtxEx(&pTrapCtx->Ctx, pStartCtx, 2 /*int xx*/, 0 /*cbSpAdjust*/, 0 /*fExtraEfl*/, g_pszTestMode, g_usBs3TestStep); + if (Bs3TestSubErrorCount() != cErrorsBefore) + { + Bs3TrapPrintFrame(pTrapCtx); +#if 1 + Bs3TestPrintf("Halting: g_uBs3CpuDetected=%#x\n", g_uBs3CpuDetected); + Bs3TestPrintf("Halting in CompareTrapCtx1: bXcpt=%#x\n", bXcpt); + ASMHalt(); +#endif + } +} +#endif + + +#if 0 +/** + * Compares trap stuff. + */ +static void bs3CpuBasic2_CompareTrapCtx2(PCBS3TRAPFRAME pTrapCtx, PCBS3REGCTX pStartCtx, uint16_t cbIpAdjust, + uint8_t bXcpt, uint16_t uHandlerCs) +{ + uint16_t const cErrorsBefore = Bs3TestSubErrorCount(); + CHECK_MEMBER("bXcpt", "%#04x", pTrapCtx->bXcpt, bXcpt); + CHECK_MEMBER("bErrCd", "%#06RX64", pTrapCtx->uErrCd, 0); + CHECK_MEMBER("uHandlerCs", "%#06x", pTrapCtx->uHandlerCs, uHandlerCs); + Bs3TestCheckRegCtxEx(&pTrapCtx->Ctx, pStartCtx, cbIpAdjust, 0 /*cbSpAdjust*/, 0 /*fExtraEfl*/, g_pszTestMode, g_usBs3TestStep); + if (Bs3TestSubErrorCount() != cErrorsBefore) + { + Bs3TrapPrintFrame(pTrapCtx); +#if 1 + Bs3TestPrintf("Halting: g_uBs3CpuDetected=%#x\n", g_uBs3CpuDetected); + Bs3TestPrintf("Halting in CompareTrapCtx2: bXcpt=%#x\n", bXcpt); + ASMHalt(); +#endif + } +} +#endif + +/** + * Compares a CPU trap. + */ +static void bs3CpuBasic2_CompareCpuTrapCtx(PCBS3TRAPFRAME pTrapCtx, PCBS3REGCTX pStartCtx, uint16_t uErrCd, + uint8_t bXcpt, bool f486ResumeFlagHint) +{ + uint16_t const cErrorsBefore = Bs3TestSubErrorCount(); + uint32_t fExtraEfl; + + CHECK_MEMBER("bXcpt", "%#04x", pTrapCtx->bXcpt, bXcpt); + CHECK_MEMBER("bErrCd", "%#06RX16", (uint16_t)pTrapCtx->uErrCd, (uint16_t)uErrCd); /* 486 only writes a word */ + + fExtraEfl = X86_EFL_RF; + if ( g_f16BitSys + || ( !f486ResumeFlagHint + && (g_uBs3CpuDetected & BS3CPU_TYPE_MASK) <= BS3CPU_80486 ) ) + fExtraEfl = 0; + else + fExtraEfl = X86_EFL_RF; +#if 0 /** @todo Running on an AMD Phenom II X6 1100T under AMD-V I'm not getting good X86_EFL_RF results. Enable this to get on with other work. */ + fExtraEfl = pTrapCtx->Ctx.rflags.u32 & X86_EFL_RF; +#endif + Bs3TestCheckRegCtxEx(&pTrapCtx->Ctx, pStartCtx, 0 /*cbIpAdjust*/, 0 /*cbSpAdjust*/, fExtraEfl, g_pszTestMode, g_usBs3TestStep); + if (Bs3TestSubErrorCount() != cErrorsBefore) + { + Bs3TrapPrintFrame(pTrapCtx); +#if 1 + Bs3TestPrintf("Halting: g_uBs3CpuDetected=%#x\n", g_uBs3CpuDetected); + Bs3TestPrintf("Halting: bXcpt=%#x uErrCd=%#x\n", bXcpt, uErrCd); + ASMHalt(); +#endif + } +} + + +/** + * Compares \#GP trap. + */ +static void bs3CpuBasic2_CompareGpCtx(PCBS3TRAPFRAME pTrapCtx, PCBS3REGCTX pStartCtx, uint16_t uErrCd) +{ + bs3CpuBasic2_CompareCpuTrapCtx(pTrapCtx, pStartCtx, uErrCd, X86_XCPT_GP, true /*f486ResumeFlagHint*/); +} + +#if 0 +/** + * Compares \#NP trap. + */ +static void bs3CpuBasic2_CompareNpCtx(PCBS3TRAPFRAME pTrapCtx, PCBS3REGCTX pStartCtx, uint16_t uErrCd) +{ + bs3CpuBasic2_CompareCpuTrapCtx(pTrapCtx, pStartCtx, uErrCd, X86_XCPT_NP, true /*f486ResumeFlagHint*/); +} +#endif + +/** + * Compares \#SS trap. + */ +static void bs3CpuBasic2_CompareSsCtx(PCBS3TRAPFRAME pTrapCtx, PCBS3REGCTX pStartCtx, uint16_t uErrCd, bool f486ResumeFlagHint) +{ + bs3CpuBasic2_CompareCpuTrapCtx(pTrapCtx, pStartCtx, uErrCd, X86_XCPT_SS, f486ResumeFlagHint); +} + +#if 0 +/** + * Compares \#TS trap. + */ +static void bs3CpuBasic2_CompareTsCtx(PCBS3TRAPFRAME pTrapCtx, PCBS3REGCTX pStartCtx, uint16_t uErrCd) +{ + bs3CpuBasic2_CompareCpuTrapCtx(pTrapCtx, pStartCtx, uErrCd, X86_XCPT_TS, false /*f486ResumeFlagHint*/); +} +#endif + +/** + * Compares \#PF trap. + */ +static void bs3CpuBasic2_ComparePfCtx(PCBS3TRAPFRAME pTrapCtx, PBS3REGCTX pStartCtx, uint16_t uErrCd, uint64_t uCr2Expected) +{ + uint64_t const uCr2Saved = pStartCtx->cr2.u; + pStartCtx->cr2.u = uCr2Expected; + bs3CpuBasic2_CompareCpuTrapCtx(pTrapCtx, pStartCtx, uErrCd, X86_XCPT_PF, true /*f486ResumeFlagHint*/); + pStartCtx->cr2.u = uCr2Saved; +} + +/** + * Compares \#UD trap. + */ +static void bs3CpuBasic2_CompareUdCtx(PCBS3TRAPFRAME pTrapCtx, PCBS3REGCTX pStartCtx) +{ + bs3CpuBasic2_CompareCpuTrapCtx(pTrapCtx, pStartCtx, 0 /*no error code*/, X86_XCPT_UD, true /*f486ResumeFlagHint*/); +} + + +#if 0 /* convert me */ +static void bs3CpuBasic2_RaiseXcpt1Common(uint16_t const uSysR0Cs, uint16_t const uSysR0CsConf, uint16_t const uSysR0Ss, + PX86DESC const paIdt, unsigned const cIdteShift) +{ + BS3TRAPFRAME TrapCtx; + BS3REGCTX Ctx80; + BS3REGCTX Ctx81; + BS3REGCTX Ctx82; + BS3REGCTX Ctx83; + BS3REGCTX CtxTmp; + BS3REGCTX CtxTmp2; + PBS3REGCTX apCtx8x[4]; + unsigned iCtx; + unsigned iRing; + unsigned iDpl; + unsigned iRpl; + unsigned i, j, k; + uint32_t uExpected; + bool const f486Plus = (g_uBs3CpuDetected & BS3CPU_TYPE_MASK) >= BS3CPU_80486; +# if TMPL_BITS == 16 + bool const f386Plus = (g_uBs3CpuDetected & BS3CPU_TYPE_MASK) >= BS3CPU_80386; + bool const f286 = (g_uBs3CpuDetected & BS3CPU_TYPE_MASK) == BS3CPU_80286; +# else + bool const f286 = false; + bool const f386Plus = true; + int rc; + uint8_t *pbIdtCopyAlloc; + PX86DESC pIdtCopy; + const unsigned cbIdte = 1 << (3 + cIdteShift); + RTCCUINTXREG uCr0Saved = ASMGetCR0(); + RTGDTR GdtrSaved; +# endif + RTIDTR IdtrSaved; + RTIDTR Idtr; + + ASMGetIDTR(&IdtrSaved); +# if TMPL_BITS != 16 + ASMGetGDTR(&GdtrSaved); +# endif + + /* make sure they're allocated */ + Bs3MemZero(&TrapCtx, sizeof(TrapCtx)); + Bs3MemZero(&Ctx80, sizeof(Ctx80)); + Bs3MemZero(&Ctx81, sizeof(Ctx81)); + Bs3MemZero(&Ctx82, sizeof(Ctx82)); + Bs3MemZero(&Ctx83, sizeof(Ctx83)); + Bs3MemZero(&CtxTmp, sizeof(CtxTmp)); + Bs3MemZero(&CtxTmp2, sizeof(CtxTmp2)); + + /* Context array. */ + apCtx8x[0] = &Ctx80; + apCtx8x[1] = &Ctx81; + apCtx8x[2] = &Ctx82; + apCtx8x[3] = &Ctx83; + +# if TMPL_BITS != 16 + /* Allocate memory for playing around with the IDT. */ + pbIdtCopyAlloc = NULL; + if (BS3_MODE_IS_PAGED(g_bTestMode)) + pbIdtCopyAlloc = Bs3MemAlloc(BS3MEMKIND_FLAT32, 12*_1K); +# endif + + /* + * IDT entry 80 thru 83 are assigned DPLs according to the number. + * (We'll be useing more, but this'll do for now.) + */ + paIdt[0x80 << cIdteShift].Gate.u2Dpl = 0; + paIdt[0x81 << cIdteShift].Gate.u2Dpl = 1; + paIdt[0x82 << cIdteShift].Gate.u2Dpl = 2; + paIdt[0x83 << cIdteShift].Gate.u2Dpl = 3; + + Bs3RegCtxSave(&Ctx80); + Ctx80.rsp.u -= 0x300; + Ctx80.rip.u = (uintptr_t)BS3_FP_OFF(&bs3CpuBasic2_Int80); +# if TMPL_BITS == 16 + Ctx80.cs = BS3_MODE_IS_RM_OR_V86(g_bTestMode) ? BS3_SEL_TEXT16 : BS3_SEL_R0_CS16; +# elif TMPL_BITS == 32 + g_uBs3TrapEipHint = Ctx80.rip.u32; +# endif + Bs3MemCpy(&Ctx81, &Ctx80, sizeof(Ctx80)); + Ctx81.rip.u = (uintptr_t)BS3_FP_OFF(&bs3CpuBasic2_Int81); + Bs3MemCpy(&Ctx82, &Ctx80, sizeof(Ctx80)); + Ctx82.rip.u = (uintptr_t)BS3_FP_OFF(&bs3CpuBasic2_Int82); + Bs3MemCpy(&Ctx83, &Ctx80, sizeof(Ctx80)); + Ctx83.rip.u = (uintptr_t)BS3_FP_OFF(&bs3CpuBasic2_Int83); + + /* + * Check that all the above gates work from ring-0. + */ + for (iCtx = 0; iCtx < RT_ELEMENTS(apCtx8x); iCtx++) + { + g_usBs3TestStep = iCtx; +# if TMPL_BITS == 32 + g_uBs3TrapEipHint = apCtx8x[iCtx]->rip.u32; +# endif + Bs3TrapSetJmpAndRestore(apCtx8x[iCtx], &TrapCtx); + bs3CpuBasic2_CompareIntCtx1(&TrapCtx, apCtx8x[iCtx], 0x80+iCtx /*bXcpt*/); + } + + /* + * Check that the gate DPL checks works. + */ + g_usBs3TestStep = 100; + for (iRing = 0; iRing <= 3; iRing++) + { + for (iCtx = 0; iCtx < RT_ELEMENTS(apCtx8x); iCtx++) + { + Bs3MemCpy(&CtxTmp, apCtx8x[iCtx], sizeof(CtxTmp)); + Bs3RegCtxConvertToRingX(&CtxTmp, iRing); +# if TMPL_BITS == 32 + g_uBs3TrapEipHint = CtxTmp.rip.u32; +# endif + Bs3TrapSetJmpAndRestore(&CtxTmp, &TrapCtx); + if (iCtx < iRing) + bs3CpuBasic2_CompareGpCtx(&TrapCtx, &CtxTmp, ((0x80 + iCtx) << X86_TRAP_ERR_SEL_SHIFT) | X86_TRAP_ERR_IDT); + else + bs3CpuBasic2_CompareIntCtx1(&TrapCtx, &CtxTmp, 0x80 + iCtx /*bXcpt*/); + g_usBs3TestStep++; + } + } + + /* + * Modify the gate CS value and run the handler at a different CPL. + * Throw RPL variations into the mix (completely ignored) together + * with gate presence. + * 1. CPL <= GATE.DPL + * 2. GATE.P + * 3. GATE.CS.DPL <= CPL (non-conforming segments) + */ + g_usBs3TestStep = 1000; + for (i = 0; i <= 3; i++) + { + for (iRing = 0; iRing <= 3; iRing++) + { + for (iCtx = 0; iCtx < RT_ELEMENTS(apCtx8x); iCtx++) + { +# if TMPL_BITS == 32 + g_uBs3TrapEipHint = apCtx8x[iCtx]->rip.u32; +# endif + Bs3MemCpy(&CtxTmp, apCtx8x[iCtx], sizeof(CtxTmp)); + Bs3RegCtxConvertToRingX(&CtxTmp, iRing); + + for (j = 0; j <= 3; j++) + { + uint16_t const uCs = (uSysR0Cs | j) + (i << BS3_SEL_RING_SHIFT); + for (k = 0; k < 2; k++) + { + g_usBs3TestStep++; + /*Bs3TestPrintf("g_usBs3TestStep=%u iCtx=%u iRing=%u i=%u uCs=%04x\n", g_usBs3TestStep, iCtx, iRing, i, uCs);*/ + paIdt[(0x80 + iCtx) << cIdteShift].Gate.u16Sel = uCs; + paIdt[(0x80 + iCtx) << cIdteShift].Gate.u1Present = k; + Bs3TrapSetJmpAndRestore(&CtxTmp, &TrapCtx); + /*Bs3TrapPrintFrame(&TrapCtx);*/ + if (iCtx < iRing) + bs3CpuBasic2_CompareGpCtx(&TrapCtx, &CtxTmp, ((0x80 + iCtx) << X86_TRAP_ERR_SEL_SHIFT) | X86_TRAP_ERR_IDT); + else if (k == 0) + bs3CpuBasic2_CompareNpCtx(&TrapCtx, &CtxTmp, ((0x80 + iCtx) << X86_TRAP_ERR_SEL_SHIFT) | X86_TRAP_ERR_IDT); + else if (i > iRing) + bs3CpuBasic2_CompareGpCtx(&TrapCtx, &CtxTmp, uCs & X86_SEL_MASK_OFF_RPL); + else + { + uint16_t uExpectedCs = uCs & X86_SEL_MASK_OFF_RPL; + if (i <= iCtx && i <= iRing) + uExpectedCs |= i; + bs3CpuBasic2_CompareTrapCtx2(&TrapCtx, &CtxTmp, 2 /*int 8xh*/, 0x80 + iCtx /*bXcpt*/, uExpectedCs); + } + } + } + + paIdt[(0x80 + iCtx) << cIdteShift].Gate.u16Sel = uSysR0Cs; + paIdt[(0x80 + iCtx) << cIdteShift].Gate.u1Present = 1; + } + } + } + BS3_ASSERT(g_usBs3TestStep < 1600); + + /* + * Various CS and SS related faults + * + * We temporarily reconfigure gate 80 and 83 with new CS selectors, the + * latter have a CS.DPL of 2 for testing ring transisions and SS loading + * without making it impossible to handle faults. + */ + g_usBs3TestStep = 1600; + Bs3GdteTestPage00 = Bs3Gdt[uSysR0Cs >> X86_SEL_SHIFT]; + Bs3GdteTestPage00.Gen.u1Present = 0; + Bs3GdteTestPage00.Gen.u4Type &= ~X86_SEL_TYPE_ACCESSED; + paIdt[0x80 << cIdteShift].Gate.u16Sel = BS3_SEL_TEST_PAGE_00; + + /* CS.PRESENT = 0 */ + Bs3TrapSetJmpAndRestore(&Ctx80, &TrapCtx); + bs3CpuBasic2_CompareNpCtx(&TrapCtx, &Ctx80, BS3_SEL_TEST_PAGE_00); + if (Bs3GdteTestPage00.Gen.u4Type & X86_SEL_TYPE_ACCESSED) + bs3CpuBasic2_FailedF("selector was accessed"); + g_usBs3TestStep++; + + /* Check that GATE.DPL is checked before CS.PRESENT. */ + for (iRing = 1; iRing < 4; iRing++) + { + Bs3MemCpy(&CtxTmp, &Ctx80, sizeof(CtxTmp)); + Bs3RegCtxConvertToRingX(&CtxTmp, iRing); + Bs3TrapSetJmpAndRestore(&CtxTmp, &TrapCtx); + bs3CpuBasic2_CompareGpCtx(&TrapCtx, &CtxTmp, (0x80 << X86_TRAP_ERR_SEL_SHIFT) | X86_TRAP_ERR_IDT); + if (Bs3GdteTestPage00.Gen.u4Type & X86_SEL_TYPE_ACCESSED) + bs3CpuBasic2_FailedF("selector was accessed"); + g_usBs3TestStep++; + } + + /* CS.DPL mismatch takes precedence over CS.PRESENT = 0. */ + Bs3GdteTestPage00.Gen.u4Type &= ~X86_SEL_TYPE_ACCESSED; + Bs3TrapSetJmpAndRestore(&Ctx80, &TrapCtx); + bs3CpuBasic2_CompareNpCtx(&TrapCtx, &Ctx80, BS3_SEL_TEST_PAGE_00); + if (Bs3GdteTestPage00.Gen.u4Type & X86_SEL_TYPE_ACCESSED) + bs3CpuBasic2_FailedF("CS selector was accessed"); + g_usBs3TestStep++; + for (iDpl = 1; iDpl < 4; iDpl++) + { + Bs3GdteTestPage00.Gen.u2Dpl = iDpl; + Bs3TrapSetJmpAndRestore(&Ctx80, &TrapCtx); + bs3CpuBasic2_CompareGpCtx(&TrapCtx, &Ctx80, BS3_SEL_TEST_PAGE_00); + if (Bs3GdteTestPage00.Gen.u4Type & X86_SEL_TYPE_ACCESSED) + bs3CpuBasic2_FailedF("CS selector was accessed"); + g_usBs3TestStep++; + } + + /* 1608: Check all the invalid CS selector types alone. */ + Bs3GdteTestPage00 = Bs3Gdt[uSysR0Cs >> X86_SEL_SHIFT]; + for (i = 0; i < RT_ELEMENTS(g_aInvalidCsTypes); i++) + { + Bs3GdteTestPage00.Gen.u4Type = g_aInvalidCsTypes[i].u4Type; + Bs3GdteTestPage00.Gen.u1DescType = g_aInvalidCsTypes[i].u1DescType; + Bs3TrapSetJmpAndRestore(&Ctx80, &TrapCtx); + bs3CpuBasic2_CompareGpCtx(&TrapCtx, &Ctx80, BS3_SEL_TEST_PAGE_00); + if (Bs3GdteTestPage00.Gen.u4Type != g_aInvalidCsTypes[i].u4Type) + bs3CpuBasic2_FailedF("Invalid CS type %#x/%u -> %#x/%u\n", + g_aInvalidCsTypes[i].u4Type, g_aInvalidCsTypes[i].u1DescType, + Bs3GdteTestPage00.Gen.u4Type, Bs3GdteTestPage00.Gen.u1DescType); + g_usBs3TestStep++; + + /* Incorrect CS.TYPE takes precedence over CS.PRESENT = 0. */ + Bs3GdteTestPage00.Gen.u1Present = 0; + Bs3TrapSetJmpAndRestore(&Ctx80, &TrapCtx); + bs3CpuBasic2_CompareGpCtx(&TrapCtx, &Ctx80, BS3_SEL_TEST_PAGE_00); + Bs3GdteTestPage00.Gen.u1Present = 1; + g_usBs3TestStep++; + } + + /* Fix CS again. */ + Bs3GdteTestPage00 = Bs3Gdt[uSysR0Cs >> X86_SEL_SHIFT]; + + /* 1632: Test SS. */ + if (!BS3_MODE_IS_64BIT_SYS(g_bTestMode)) + { + uint16_t BS3_FAR *puTssSs2 = BS3_MODE_IS_16BIT_SYS(g_bTestMode) ? &Bs3Tss16.ss2 : &Bs3Tss32.ss2; + uint16_t const uSavedSs2 = *puTssSs2; + X86DESC const SavedGate83 = paIdt[0x83 << cIdteShift]; + + /* Make the handler execute in ring-2. */ + Bs3GdteTestPage02 = Bs3Gdt[(uSysR0Cs + (2 << BS3_SEL_RING_SHIFT)) >> X86_SEL_SHIFT]; + Bs3GdteTestPage02.Gen.u4Type &= ~X86_SEL_TYPE_ACCESSED; + paIdt[0x83 << cIdteShift].Gate.u16Sel = BS3_SEL_TEST_PAGE_02 | 2; + + Bs3MemCpy(&CtxTmp, &Ctx83, sizeof(CtxTmp)); + Bs3RegCtxConvertToRingX(&CtxTmp, 3); /* yeah, from 3 so SS:xSP is reloaded. */ + Bs3TrapSetJmpAndRestore(&CtxTmp, &TrapCtx); + bs3CpuBasic2_CompareIntCtx1(&TrapCtx, &CtxTmp, 0x83); + if (!(Bs3GdteTestPage02.Gen.u4Type & X86_SEL_TYPE_ACCESSED)) + bs3CpuBasic2_FailedF("CS selector was not access"); + g_usBs3TestStep++; + + /* Create a SS.DPL=2 stack segment and check that SS2.RPL matters and + that we get #SS if the selector isn't present. */ + i = 0; /* used for cycling thru invalid CS types */ + for (k = 0; k < 10; k++) + { + /* k=0: present, + k=1: not-present, + k=2: present but very low limit, + k=3: not-present, low limit. + k=4: present, read-only. + k=5: not-present, read-only. + k=6: present, code-selector. + k=7: not-present, code-selector. + k=8: present, read-write / no access + system (=LDT). + k=9: not-present, read-write / no access + system (=LDT). + */ + Bs3GdteTestPage03 = Bs3Gdt[(uSysR0Ss + (2 << BS3_SEL_RING_SHIFT)) >> X86_SEL_SHIFT]; + Bs3GdteTestPage03.Gen.u1Present = !(k & 1); + if (k >= 8) + { + Bs3GdteTestPage03.Gen.u1DescType = 0; /* system */ + Bs3GdteTestPage03.Gen.u4Type = X86_SEL_TYPE_RW; /* = LDT */ + } + else if (k >= 6) + Bs3GdteTestPage03.Gen.u4Type = X86_SEL_TYPE_ER; + else if (k >= 4) + Bs3GdteTestPage03.Gen.u4Type = X86_SEL_TYPE_RO; + else if (k >= 2) + { + Bs3GdteTestPage03.Gen.u16LimitLow = 0x400; + Bs3GdteTestPage03.Gen.u4LimitHigh = 0; + Bs3GdteTestPage03.Gen.u1Granularity = 0; + } + + for (iDpl = 0; iDpl < 4; iDpl++) + { + Bs3GdteTestPage03.Gen.u2Dpl = iDpl; + + for (iRpl = 0; iRpl < 4; iRpl++) + { + *puTssSs2 = BS3_SEL_TEST_PAGE_03 | iRpl; + //Bs3TestPrintf("k=%u iDpl=%u iRpl=%u step=%u\n", k, iDpl, iRpl, g_usBs3TestStep); + Bs3GdteTestPage02.Gen.u4Type &= ~X86_SEL_TYPE_ACCESSED; + Bs3GdteTestPage03.Gen.u4Type &= ~X86_SEL_TYPE_ACCESSED; + Bs3TrapSetJmpAndRestore(&CtxTmp, &TrapCtx); + if (iRpl != 2 || iRpl != iDpl || k >= 4) + bs3CpuBasic2_CompareTsCtx(&TrapCtx, &CtxTmp, BS3_SEL_TEST_PAGE_03); + else if (k != 0) + bs3CpuBasic2_CompareSsCtx(&TrapCtx, &CtxTmp, BS3_SEL_TEST_PAGE_03, + k == 2 /*f486ResumeFlagHint*/); + else + { + bs3CpuBasic2_CompareIntCtx1(&TrapCtx, &CtxTmp, 0x83); + if (TrapCtx.uHandlerSs != (BS3_SEL_TEST_PAGE_03 | 2)) + bs3CpuBasic2_FailedF("uHandlerSs=%#x expected %#x\n", TrapCtx.uHandlerSs, BS3_SEL_TEST_PAGE_03 | 2); + } + if (!(Bs3GdteTestPage02.Gen.u4Type & X86_SEL_TYPE_ACCESSED)) + bs3CpuBasic2_FailedF("CS selector was not access"); + if ( TrapCtx.bXcpt == 0x83 + || (TrapCtx.bXcpt == X86_XCPT_SS && k == 2) ) + { + if (!(Bs3GdteTestPage03.Gen.u4Type & X86_SEL_TYPE_ACCESSED)) + bs3CpuBasic2_FailedF("SS selector was not accessed"); + } + else if (Bs3GdteTestPage03.Gen.u4Type & X86_SEL_TYPE_ACCESSED) + bs3CpuBasic2_FailedF("SS selector was accessed"); + g_usBs3TestStep++; + + /* +1: Modify the gate DPL to check that this is checked before SS.DPL and SS.PRESENT. */ + paIdt[0x83 << cIdteShift].Gate.u2Dpl = 2; + Bs3TrapSetJmpAndRestore(&CtxTmp, &TrapCtx); + bs3CpuBasic2_CompareGpCtx(&TrapCtx, &CtxTmp, (0x83 << X86_TRAP_ERR_SEL_SHIFT) | X86_TRAP_ERR_IDT); + paIdt[0x83 << cIdteShift].Gate.u2Dpl = 3; + g_usBs3TestStep++; + + /* +2: Check the CS.DPL check is done before the SS ones. Restoring the + ring-0 INT 83 context triggers the CS.DPL < CPL check. */ + Bs3TrapSetJmpAndRestore(&Ctx83, &TrapCtx); + bs3CpuBasic2_CompareGpCtx(&TrapCtx, &Ctx83, BS3_SEL_TEST_PAGE_02); + g_usBs3TestStep++; + + /* +3: Now mark the CS selector not present and check that that also triggers before SS stuff. */ + Bs3GdteTestPage02.Gen.u1Present = 0; + Bs3TrapSetJmpAndRestore(&CtxTmp, &TrapCtx); + bs3CpuBasic2_CompareNpCtx(&TrapCtx, &CtxTmp, BS3_SEL_TEST_PAGE_02); + Bs3GdteTestPage02.Gen.u1Present = 1; + g_usBs3TestStep++; + + /* +4: Make the CS selector some invalid type and check it triggers before SS stuff. */ + Bs3GdteTestPage02.Gen.u4Type = g_aInvalidCsTypes[i].u4Type; + Bs3GdteTestPage02.Gen.u1DescType = g_aInvalidCsTypes[i].u1DescType; + Bs3TrapSetJmpAndRestore(&CtxTmp, &TrapCtx); + bs3CpuBasic2_CompareGpCtx(&TrapCtx, &CtxTmp, BS3_SEL_TEST_PAGE_02); + Bs3GdteTestPage02.Gen.u4Type = X86_SEL_TYPE_ER_ACC; + Bs3GdteTestPage02.Gen.u1DescType = 1; + g_usBs3TestStep++; + + /* +5: Now, make the CS selector limit too small and that it triggers after SS trouble. + The 286 had a simpler approach to these GP(0). */ + Bs3GdteTestPage02.Gen.u16LimitLow = 0; + Bs3GdteTestPage02.Gen.u4LimitHigh = 0; + Bs3GdteTestPage02.Gen.u1Granularity = 0; + Bs3TrapSetJmpAndRestore(&CtxTmp, &TrapCtx); + if (f286) + bs3CpuBasic2_CompareGpCtx(&TrapCtx, &CtxTmp, 0 /*uErrCd*/); + else if (iRpl != 2 || iRpl != iDpl || k >= 4) + bs3CpuBasic2_CompareTsCtx(&TrapCtx, &CtxTmp, BS3_SEL_TEST_PAGE_03); + else if (k != 0) + bs3CpuBasic2_CompareSsCtx(&TrapCtx, &CtxTmp, BS3_SEL_TEST_PAGE_03, k == 2 /*f486ResumeFlagHint*/); + else + bs3CpuBasic2_CompareGpCtx(&TrapCtx, &CtxTmp, 0 /*uErrCd*/); + Bs3GdteTestPage02 = Bs3Gdt[(uSysR0Cs + (2 << BS3_SEL_RING_SHIFT)) >> X86_SEL_SHIFT]; + g_usBs3TestStep++; + } + } + } + + /* Check all the invalid SS selector types alone. */ + Bs3GdteTestPage02 = Bs3Gdt[(uSysR0Cs + (2 << BS3_SEL_RING_SHIFT)) >> X86_SEL_SHIFT]; + Bs3GdteTestPage03 = Bs3Gdt[(uSysR0Ss + (2 << BS3_SEL_RING_SHIFT)) >> X86_SEL_SHIFT]; + *puTssSs2 = BS3_SEL_TEST_PAGE_03 | 2; + Bs3TrapSetJmpAndRestore(&CtxTmp, &TrapCtx); + bs3CpuBasic2_CompareIntCtx1(&TrapCtx, &CtxTmp, 0x83); + g_usBs3TestStep++; + for (i = 0; i < RT_ELEMENTS(g_aInvalidSsTypes); i++) + { + Bs3GdteTestPage03.Gen.u4Type = g_aInvalidSsTypes[i].u4Type; + Bs3GdteTestPage03.Gen.u1DescType = g_aInvalidSsTypes[i].u1DescType; + Bs3TrapSetJmpAndRestore(&CtxTmp, &TrapCtx); + bs3CpuBasic2_CompareTsCtx(&TrapCtx, &CtxTmp, BS3_SEL_TEST_PAGE_03); + if (Bs3GdteTestPage03.Gen.u4Type != g_aInvalidSsTypes[i].u4Type) + bs3CpuBasic2_FailedF("Invalid SS type %#x/%u -> %#x/%u\n", + g_aInvalidSsTypes[i].u4Type, g_aInvalidSsTypes[i].u1DescType, + Bs3GdteTestPage03.Gen.u4Type, Bs3GdteTestPage03.Gen.u1DescType); + g_usBs3TestStep++; + } + + /* + * Continue the SS experiments with a expand down segment. We'll use + * the same setup as we already have with gate 83h being DPL and + * having CS.DPL=2. + * + * Expand down segments are weird. The valid area is practically speaking + * reversed. So, a 16-bit segment with a limit of 0x6000 will have valid + * addresses from 0xffff thru 0x6001. + * + * So, with expand down segments we can more easily cut partially into the + * pushing of the iret frame and trigger more interesting behavior than + * with regular "expand up" segments where the whole pushing area is either + * all fine or not not fine. + */ + Bs3GdteTestPage02 = Bs3Gdt[(uSysR0Cs + (2 << BS3_SEL_RING_SHIFT)) >> X86_SEL_SHIFT]; + Bs3GdteTestPage03 = Bs3Gdt[(uSysR0Ss + (2 << BS3_SEL_RING_SHIFT)) >> X86_SEL_SHIFT]; + Bs3GdteTestPage03.Gen.u2Dpl = 2; + Bs3GdteTestPage03.Gen.u4Type = X86_SEL_TYPE_RW_DOWN; + *puTssSs2 = BS3_SEL_TEST_PAGE_03 | 2; + + /* First test, limit = max --> no bytes accessible --> #GP */ + Bs3TrapSetJmpAndRestore(&CtxTmp, &TrapCtx); + bs3CpuBasic2_CompareSsCtx(&TrapCtx, &CtxTmp, BS3_SEL_TEST_PAGE_03, true /*f486ResumeFlagHint*/); + + /* Second test, limit = 0 --> all by zero byte accessible --> works */ + Bs3GdteTestPage03.Gen.u16LimitLow = 0; + Bs3GdteTestPage03.Gen.u4LimitHigh = 0; + Bs3TrapSetJmpAndRestore(&CtxTmp, &TrapCtx); + bs3CpuBasic2_CompareIntCtx1(&TrapCtx, &CtxTmp, 0x83); + + /* Modify the gate handler to be a dummy that immediately does UD2 + and triggers #UD, then advance the limit down till we get the #UD. */ + Bs3GdteTestPage03.Gen.u1Granularity = 0; + + Bs3MemCpy(&CtxTmp2, &CtxTmp, sizeof(CtxTmp2)); /* #UD result context */ + if (g_f16BitSys) + { + CtxTmp2.rip.u = g_bs3CpuBasic2_ud2_FlatAddr - BS3_ADDR_BS3TEXT16; + Bs3Trap16SetGate(0x83, X86_SEL_TYPE_SYS_286_INT_GATE, 3, BS3_SEL_TEST_PAGE_02, CtxTmp2.rip.u16, 0 /*cParams*/); + CtxTmp2.rsp.u = Bs3Tss16.sp2 - 2*5; + } + else + { + CtxTmp2.rip.u = g_bs3CpuBasic2_ud2_FlatAddr; + Bs3Trap32SetGate(0x83, X86_SEL_TYPE_SYS_386_INT_GATE, 3, BS3_SEL_TEST_PAGE_02, CtxTmp2.rip.u32, 0 /*cParams*/); + CtxTmp2.rsp.u = Bs3Tss32.esp2 - 4*5; + } + CtxTmp2.bMode = g_bTestMode; /* g_bBs3CurrentMode not changed by the UD2 handler. */ + CtxTmp2.cs = BS3_SEL_TEST_PAGE_02 | 2; + CtxTmp2.ss = BS3_SEL_TEST_PAGE_03 | 2; + CtxTmp2.bCpl = 2; + + /* test run. */ + Bs3TrapSetJmpAndRestore(&CtxTmp, &TrapCtx); + bs3CpuBasic2_CompareUdCtx(&TrapCtx, &CtxTmp2); + g_usBs3TestStep++; + + /* Real run. */ + i = (g_f16BitSys ? 2 : 4) * 6 + 1; + while (i-- > 0) + { + Bs3GdteTestPage03.Gen.u16LimitLow = CtxTmp2.rsp.u16 + i - 1; + Bs3TrapSetJmpAndRestore(&CtxTmp, &TrapCtx); + if (i > 0) + bs3CpuBasic2_CompareSsCtx(&TrapCtx, &CtxTmp, BS3_SEL_TEST_PAGE_03, true /*f486ResumeFlagHint*/); + else + bs3CpuBasic2_CompareUdCtx(&TrapCtx, &CtxTmp2); + g_usBs3TestStep++; + } + + /* Do a run where we do the same-ring kind of access. */ + Bs3RegCtxConvertToRingX(&CtxTmp, 2); + if (g_f16BitSys) + { + CtxTmp2.rsp.u32 = CtxTmp.rsp.u32 - 2*3; + i = 2*3 - 1; + } + else + { + CtxTmp2.rsp.u32 = CtxTmp.rsp.u32 - 4*3; + i = 4*3 - 1; + } + CtxTmp.ss = BS3_SEL_TEST_PAGE_03 | 2; + CtxTmp2.ds = CtxTmp.ds; + CtxTmp2.es = CtxTmp.es; + CtxTmp2.fs = CtxTmp.fs; + CtxTmp2.gs = CtxTmp.gs; + while (i-- > 0) + { + Bs3GdteTestPage03.Gen.u16LimitLow = CtxTmp2.rsp.u16 + i - 1; + Bs3TrapSetJmpAndRestore(&CtxTmp, &TrapCtx); + if (i > 0) + bs3CpuBasic2_CompareSsCtx(&TrapCtx, &CtxTmp, 0 /*BS3_SEL_TEST_PAGE_03*/, true /*f486ResumeFlagHint*/); + else + bs3CpuBasic2_CompareUdCtx(&TrapCtx, &CtxTmp2); + g_usBs3TestStep++; + } + + *puTssSs2 = uSavedSs2; + paIdt[0x83 << cIdteShift] = SavedGate83; + } + paIdt[0x80 << cIdteShift].Gate.u16Sel = uSysR0Cs; + BS3_ASSERT(g_usBs3TestStep < 3000); + + /* + * Modify the gate CS value with a conforming segment. + */ + g_usBs3TestStep = 3000; + for (i = 0; i <= 3; i++) /* cs.dpl */ + { + for (iRing = 0; iRing <= 3; iRing++) + { + for (iCtx = 0; iCtx < RT_ELEMENTS(apCtx8x); iCtx++) + { + Bs3MemCpy(&CtxTmp, apCtx8x[iCtx], sizeof(CtxTmp)); + Bs3RegCtxConvertToRingX(&CtxTmp, iRing); +# if TMPL_BITS == 32 + g_uBs3TrapEipHint = CtxTmp.rip.u32; +# endif + + for (j = 0; j <= 3; j++) /* rpl */ + { + uint16_t const uCs = (uSysR0CsConf | j) + (i << BS3_SEL_RING_SHIFT); + /*Bs3TestPrintf("g_usBs3TestStep=%u iCtx=%u iRing=%u i=%u uCs=%04x\n", g_usBs3TestStep, iCtx, iRing, i, uCs);*/ + paIdt[(0x80 + iCtx) << cIdteShift].Gate.u16Sel = uCs; + Bs3TrapSetJmpAndRestore(&CtxTmp, &TrapCtx); + //Bs3TestPrintf("%u/%u/%u/%u: cs=%04x hcs=%04x xcpt=%02x\n", i, iRing, iCtx, j, uCs, TrapCtx.uHandlerCs, TrapCtx.bXcpt); + /*Bs3TrapPrintFrame(&TrapCtx);*/ + g_usBs3TestStep++; + if (iCtx < iRing) + bs3CpuBasic2_CompareGpCtx(&TrapCtx, &CtxTmp, ((0x80 + iCtx) << X86_TRAP_ERR_SEL_SHIFT) | X86_TRAP_ERR_IDT); + else if (i > iRing) + bs3CpuBasic2_CompareGpCtx(&TrapCtx, &CtxTmp, uCs & X86_SEL_MASK_OFF_RPL); + else + bs3CpuBasic2_CompareIntCtx1(&TrapCtx, &CtxTmp, 0x80 + iCtx /*bXcpt*/); + } + paIdt[(0x80 + iCtx) << cIdteShift].Gate.u16Sel = uSysR0Cs; + } + } + } + BS3_ASSERT(g_usBs3TestStep < 3500); + + /* + * The gates must be 64-bit in long mode. + */ + if (cIdteShift != 0) + { + g_usBs3TestStep = 3500; + for (i = 0; i <= 3; i++) + { + for (iRing = 0; iRing <= 3; iRing++) + { + for (iCtx = 0; iCtx < RT_ELEMENTS(apCtx8x); iCtx++) + { + Bs3MemCpy(&CtxTmp, apCtx8x[iCtx], sizeof(CtxTmp)); + Bs3RegCtxConvertToRingX(&CtxTmp, iRing); + + for (j = 0; j < 2; j++) + { + static const uint16_t s_auCSes[2] = { BS3_SEL_R0_CS16, BS3_SEL_R0_CS32 }; + uint16_t uCs = (s_auCSes[j] | i) + (i << BS3_SEL_RING_SHIFT); + g_usBs3TestStep++; + /*Bs3TestPrintf("g_usBs3TestStep=%u iCtx=%u iRing=%u i=%u uCs=%04x\n", g_usBs3TestStep, iCtx, iRing, i, uCs);*/ + paIdt[(0x80 + iCtx) << cIdteShift].Gate.u16Sel = uCs; + Bs3TrapSetJmpAndRestore(&CtxTmp, &TrapCtx); + /*Bs3TrapPrintFrame(&TrapCtx);*/ + if (iCtx < iRing) + bs3CpuBasic2_CompareGpCtx(&TrapCtx, &CtxTmp, ((0x80 + iCtx) << X86_TRAP_ERR_SEL_SHIFT) | X86_TRAP_ERR_IDT); + else + bs3CpuBasic2_CompareGpCtx(&TrapCtx, &CtxTmp, uCs & X86_SEL_MASK_OFF_RPL); + } + paIdt[(0x80 + iCtx) << cIdteShift].Gate.u16Sel = uSysR0Cs; + } + } + } + BS3_ASSERT(g_usBs3TestStep < 4000); + } + + /* + * IDT limit check. The 286 does not access X86DESCGATE::u16OffsetHigh. + */ + g_usBs3TestStep = 5000; + i = (0x80 << (cIdteShift + 3)) - 1; + j = (0x82 << (cIdteShift + 3)) - (!f286 ? 1 : 3); + k = (0x83 << (cIdteShift + 3)) - 1; + for (; i <= k; i++, g_usBs3TestStep++) + { + Idtr = IdtrSaved; + Idtr.cbIdt = i; + ASMSetIDTR(&Idtr); + Bs3TrapSetJmpAndRestore(&Ctx81, &TrapCtx); + if (i < j) + bs3CpuBasic2_CompareGpCtx(&TrapCtx, &Ctx81, (0x81 << X86_TRAP_ERR_SEL_SHIFT) | X86_TRAP_ERR_IDT); + else + bs3CpuBasic2_CompareIntCtx1(&TrapCtx, &Ctx81, 0x81 /*bXcpt*/); + } + ASMSetIDTR(&IdtrSaved); + BS3_ASSERT(g_usBs3TestStep < 5100); + +# if TMPL_BITS != 16 /* Only do the paging related stuff in 32-bit and 64-bit modes. */ + + /* + * IDT page not present. Placing the IDT copy such that 0x80 is on the + * first page and 0x81 is on the second page. We need proceed to move + * it down byte by byte to check that any inaccessible byte means #PF. + * + * Note! We must reload the alternative IDTR for each run as any kind of + * printing to the string (like error reporting) will cause a switch + * to real mode and back, reloading the default IDTR. + */ + g_usBs3TestStep = 5200; + if (BS3_MODE_IS_PAGED(g_bTestMode) && pbIdtCopyAlloc) + { + uint32_t const uCr2Expected = Bs3SelPtrToFlat(pbIdtCopyAlloc) + _4K; + for (j = 0; j < cbIdte; j++) + { + pIdtCopy = (PX86DESC)&pbIdtCopyAlloc[_4K - cbIdte * 0x81 - j]; + Bs3MemCpy(pIdtCopy, paIdt, cbIdte * 256); + + Idtr.cbIdt = IdtrSaved.cbIdt; + Idtr.pIdt = Bs3SelPtrToFlat(pIdtCopy); + + ASMSetIDTR(&Idtr); + Bs3TrapSetJmpAndRestore(&Ctx81, &TrapCtx); + bs3CpuBasic2_CompareIntCtx1(&TrapCtx, &Ctx81, 0x81 /*bXcpt*/); + g_usBs3TestStep++; + + ASMSetIDTR(&Idtr); + Bs3TrapSetJmpAndRestore(&Ctx80, &TrapCtx); + bs3CpuBasic2_CompareIntCtx1(&TrapCtx, &Ctx80, 0x80 /*bXcpt*/); + g_usBs3TestStep++; + + rc = Bs3PagingProtect(uCr2Expected, _4K, 0 /*fSet*/, X86_PTE_P /*fClear*/); + if (RT_SUCCESS(rc)) + { + ASMSetIDTR(&Idtr); + Bs3TrapSetJmpAndRestore(&Ctx80, &TrapCtx); + bs3CpuBasic2_CompareIntCtx1(&TrapCtx, &Ctx80, 0x80 /*bXcpt*/); + g_usBs3TestStep++; + + ASMSetIDTR(&Idtr); + Bs3TrapSetJmpAndRestore(&Ctx81, &TrapCtx); + if (f486Plus) + bs3CpuBasic2_ComparePfCtx(&TrapCtx, &Ctx81, 0 /*uErrCd*/, uCr2Expected); + else + bs3CpuBasic2_ComparePfCtx(&TrapCtx, &Ctx81, X86_TRAP_PF_RW /*uErrCd*/, uCr2Expected + 4 - RT_MIN(j, 4)); + g_usBs3TestStep++; + + Bs3PagingProtect(uCr2Expected, _4K, X86_PTE_P /*fSet*/, 0 /*fClear*/); + + /* Check if that the entry type is checked after the whole IDTE has been cleared for #PF. */ + pIdtCopy[0x80 << cIdteShift].Gate.u4Type = 0; + rc = Bs3PagingProtect(uCr2Expected, _4K, 0 /*fSet*/, X86_PTE_P /*fClear*/); + if (RT_SUCCESS(rc)) + { + ASMSetIDTR(&Idtr); + Bs3TrapSetJmpAndRestore(&Ctx81, &TrapCtx); + if (f486Plus) + bs3CpuBasic2_ComparePfCtx(&TrapCtx, &Ctx81, 0 /*uErrCd*/, uCr2Expected); + else + bs3CpuBasic2_ComparePfCtx(&TrapCtx, &Ctx81, X86_TRAP_PF_RW /*uErrCd*/, uCr2Expected + 4 - RT_MIN(j, 4)); + g_usBs3TestStep++; + + Bs3PagingProtect(uCr2Expected, _4K, X86_PTE_P /*fSet*/, 0 /*fClear*/); + } + } + else + Bs3TestPrintf("Bs3PagingProtectPtr: %d\n", i); + + ASMSetIDTR(&IdtrSaved); + } + } + + /* + * The read/write and user/supervisor bits the IDT PTEs are irrelevant. + */ + g_usBs3TestStep = 5300; + if (BS3_MODE_IS_PAGED(g_bTestMode) && pbIdtCopyAlloc) + { + Bs3MemCpy(pbIdtCopyAlloc, paIdt, cbIdte * 256); + Idtr.cbIdt = IdtrSaved.cbIdt; + Idtr.pIdt = Bs3SelPtrToFlat(pbIdtCopyAlloc); + + ASMSetIDTR(&Idtr); + Bs3TrapSetJmpAndRestore(&Ctx81, &TrapCtx); + bs3CpuBasic2_CompareIntCtx1(&TrapCtx, &Ctx81, 0x81 /*bXcpt*/); + g_usBs3TestStep++; + + rc = Bs3PagingProtect(Idtr.pIdt, _4K, 0 /*fSet*/, X86_PTE_RW | X86_PTE_US /*fClear*/); + if (RT_SUCCESS(rc)) + { + ASMSetIDTR(&Idtr); + Bs3TrapSetJmpAndRestore(&Ctx81, &TrapCtx); + bs3CpuBasic2_CompareIntCtx1(&TrapCtx, &Ctx81, 0x81 /*bXcpt*/); + g_usBs3TestStep++; + + Bs3PagingProtect(Idtr.pIdt, _4K, X86_PTE_RW | X86_PTE_US /*fSet*/, 0 /*fClear*/); + } + ASMSetIDTR(&IdtrSaved); + } + + /* + * Check that CS.u1Accessed is set to 1. Use the test page selector #0 and #3 together + * with interrupt gates 80h and 83h, respectively. + */ +/** @todo Throw in SS.u1Accessed too. */ + g_usBs3TestStep = 5400; + if (BS3_MODE_IS_PAGED(g_bTestMode) && pbIdtCopyAlloc) + { + Bs3GdteTestPage00 = Bs3Gdt[uSysR0Cs >> X86_SEL_SHIFT]; + Bs3GdteTestPage00.Gen.u4Type &= ~X86_SEL_TYPE_ACCESSED; + paIdt[0x80 << cIdteShift].Gate.u16Sel = BS3_SEL_TEST_PAGE_00; + + Bs3GdteTestPage03 = Bs3Gdt[(uSysR0Cs + (3 << BS3_SEL_RING_SHIFT)) >> X86_SEL_SHIFT]; + Bs3GdteTestPage03.Gen.u4Type &= ~X86_SEL_TYPE_ACCESSED; + paIdt[0x83 << cIdteShift].Gate.u16Sel = BS3_SEL_TEST_PAGE_03; /* rpl is ignored, so leave it as zero. */ + + /* Check that the CS.A bit is being set on a general basis and that + the special CS values work with out generic handler code. */ + Bs3TrapSetJmpAndRestore(&Ctx80, &TrapCtx); + bs3CpuBasic2_CompareIntCtx1(&TrapCtx, &Ctx80, 0x80 /*bXcpt*/); + if (!(Bs3GdteTestPage00.Gen.u4Type & X86_SEL_TYPE_ACCESSED)) + bs3CpuBasic2_FailedF("u4Type=%#x, not accessed", Bs3GdteTestPage00.Gen.u4Type); + g_usBs3TestStep++; + + Bs3MemCpy(&CtxTmp, &Ctx83, sizeof(CtxTmp)); + Bs3RegCtxConvertToRingX(&CtxTmp, 3); + Bs3TrapSetJmpAndRestore(&CtxTmp, &TrapCtx); + bs3CpuBasic2_CompareIntCtx1(&TrapCtx, &CtxTmp, 0x83 /*bXcpt*/); + if (!(Bs3GdteTestPage03.Gen.u4Type & X86_SEL_TYPE_ACCESSED)) + bs3CpuBasic2_FailedF("u4Type=%#x, not accessed!", Bs3GdteTestPage00.Gen.u4Type); + if (TrapCtx.uHandlerCs != (BS3_SEL_TEST_PAGE_03 | 3)) + bs3CpuBasic2_FailedF("uHandlerCs=%#x, expected %#x", TrapCtx.uHandlerCs, (BS3_SEL_TEST_PAGE_03 | 3)); + g_usBs3TestStep++; + + /* + * Now check that setting CS.u1Access to 1 does __NOT__ trigger a page + * fault due to the RW bit being zero. + * (We check both with with and without the WP bit if 80486.) + */ + if ((g_uBs3CpuDetected & BS3CPU_TYPE_MASK) >= BS3CPU_80486) + ASMSetCR0(uCr0Saved | X86_CR0_WP); + + Bs3GdteTestPage00.Gen.u4Type &= ~X86_SEL_TYPE_ACCESSED; + Bs3GdteTestPage03.Gen.u4Type &= ~X86_SEL_TYPE_ACCESSED; + rc = Bs3PagingProtect(GdtrSaved.pGdt + BS3_SEL_TEST_PAGE_00, 8, 0 /*fSet*/, X86_PTE_RW /*fClear*/); + if (RT_SUCCESS(rc)) + { + /* ring-0 handler */ + Bs3TrapSetJmpAndRestore(&Ctx80, &TrapCtx); + bs3CpuBasic2_CompareIntCtx1(&TrapCtx, &Ctx80, 0x80 /*bXcpt*/); + if (!(Bs3GdteTestPage00.Gen.u4Type & X86_SEL_TYPE_ACCESSED)) + bs3CpuBasic2_FailedF("u4Type=%#x, not accessed!", Bs3GdteTestPage00.Gen.u4Type); + g_usBs3TestStep++; + + /* ring-3 handler */ + Bs3MemCpy(&CtxTmp, &Ctx83, sizeof(CtxTmp)); + Bs3RegCtxConvertToRingX(&CtxTmp, 3); + Bs3TrapSetJmpAndRestore(&CtxTmp, &TrapCtx); + bs3CpuBasic2_CompareIntCtx1(&TrapCtx, &CtxTmp, 0x83 /*bXcpt*/); + if (!(Bs3GdteTestPage03.Gen.u4Type & X86_SEL_TYPE_ACCESSED)) + bs3CpuBasic2_FailedF("u4Type=%#x, not accessed!", Bs3GdteTestPage00.Gen.u4Type); + g_usBs3TestStep++; + + /* clear WP and repeat the above. */ + if ((g_uBs3CpuDetected & BS3CPU_TYPE_MASK) >= BS3CPU_80486) + ASMSetCR0(uCr0Saved & ~X86_CR0_WP); + Bs3GdteTestPage00.Gen.u4Type &= ~X86_SEL_TYPE_ACCESSED; /* (No need to RW the page - ring-0, WP=0.) */ + Bs3GdteTestPage03.Gen.u4Type &= ~X86_SEL_TYPE_ACCESSED; /* (No need to RW the page - ring-0, WP=0.) */ + + Bs3TrapSetJmpAndRestore(&Ctx80, &TrapCtx); + bs3CpuBasic2_CompareIntCtx1(&TrapCtx, &Ctx80, 0x80 /*bXcpt*/); + if (!(Bs3GdteTestPage00.Gen.u4Type & X86_SEL_TYPE_ACCESSED)) + bs3CpuBasic2_FailedF("u4Type=%#x, not accessed!", Bs3GdteTestPage00.Gen.u4Type); + g_usBs3TestStep++; + + Bs3TrapSetJmpAndRestore(&CtxTmp, &TrapCtx); + bs3CpuBasic2_CompareIntCtx1(&TrapCtx, &CtxTmp, 0x83 /*bXcpt*/); + if (!(Bs3GdteTestPage03.Gen.u4Type & X86_SEL_TYPE_ACCESSED)) + bs3CpuBasic2_FailedF("u4Type=%#x, not accessed!n", Bs3GdteTestPage03.Gen.u4Type); + g_usBs3TestStep++; + + Bs3PagingProtect(GdtrSaved.pGdt + BS3_SEL_TEST_PAGE_00, 8, X86_PTE_RW /*fSet*/, 0 /*fClear*/); + } + + ASMSetCR0(uCr0Saved); + + /* + * While we're here, check that if the CS GDT entry is a non-present + * page we do get a #PF with the rigth error code and CR2. + */ + Bs3GdteTestPage00.Gen.u4Type &= ~X86_SEL_TYPE_ACCESSED; /* Just for fun, really a pointless gesture. */ + Bs3GdteTestPage03.Gen.u4Type &= ~X86_SEL_TYPE_ACCESSED; + rc = Bs3PagingProtect(GdtrSaved.pGdt + BS3_SEL_TEST_PAGE_00, 8, 0 /*fSet*/, X86_PTE_P /*fClear*/); + if (RT_SUCCESS(rc)) + { + Bs3TrapSetJmpAndRestore(&Ctx80, &TrapCtx); + if (f486Plus) + bs3CpuBasic2_ComparePfCtx(&TrapCtx, &Ctx80, 0 /*uErrCd*/, GdtrSaved.pGdt + BS3_SEL_TEST_PAGE_00); + else + bs3CpuBasic2_ComparePfCtx(&TrapCtx, &Ctx80, X86_TRAP_PF_RW, GdtrSaved.pGdt + BS3_SEL_TEST_PAGE_00 + 4); + g_usBs3TestStep++; + + /* Do it from ring-3 to check ErrCd, which doesn't set X86_TRAP_PF_US it turns out. */ + Bs3MemCpy(&CtxTmp, &Ctx83, sizeof(CtxTmp)); + Bs3RegCtxConvertToRingX(&CtxTmp, 3); + Bs3TrapSetJmpAndRestore(&CtxTmp, &TrapCtx); + + if (f486Plus) + bs3CpuBasic2_ComparePfCtx(&TrapCtx, &CtxTmp, 0 /*uErrCd*/, GdtrSaved.pGdt + BS3_SEL_TEST_PAGE_03); + else + bs3CpuBasic2_ComparePfCtx(&TrapCtx, &CtxTmp, X86_TRAP_PF_RW, GdtrSaved.pGdt + BS3_SEL_TEST_PAGE_03 + 4); + g_usBs3TestStep++; + + Bs3PagingProtect(GdtrSaved.pGdt + BS3_SEL_TEST_PAGE_00, 8, X86_PTE_P /*fSet*/, 0 /*fClear*/); + if (Bs3GdteTestPage00.Gen.u4Type & X86_SEL_TYPE_ACCESSED) + bs3CpuBasic2_FailedF("u4Type=%#x, accessed! #1", Bs3GdteTestPage00.Gen.u4Type); + if (Bs3GdteTestPage03.Gen.u4Type & X86_SEL_TYPE_ACCESSED) + bs3CpuBasic2_FailedF("u4Type=%#x, accessed! #2", Bs3GdteTestPage03.Gen.u4Type); + } + + /* restore */ + paIdt[0x80 << cIdteShift].Gate.u16Sel = uSysR0Cs; + paIdt[0x83 << cIdteShift].Gate.u16Sel = uSysR0Cs;// + (3 << BS3_SEL_RING_SHIFT) + 3; + } + +# endif /* 32 || 64*/ + + /* + * Check broad EFLAGS effects. + */ + g_usBs3TestStep = 5600; + for (iCtx = 0; iCtx < RT_ELEMENTS(apCtx8x); iCtx++) + { + for (iRing = 0; iRing < 4; iRing++) + { + Bs3MemCpy(&CtxTmp, apCtx8x[iCtx], sizeof(CtxTmp)); + Bs3RegCtxConvertToRingX(&CtxTmp, iRing); + + /* all set */ + CtxTmp.rflags.u32 &= X86_EFL_VM | X86_EFL_1; + CtxTmp.rflags.u32 |= X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF /* | X86_EFL_TF */ /*| X86_EFL_IF*/ + | X86_EFL_DF | X86_EFL_OF | X86_EFL_IOPL /* | X86_EFL_NT*/; + if (f486Plus) + CtxTmp.rflags.u32 |= X86_EFL_AC; + if (f486Plus && !g_f16BitSys) + CtxTmp.rflags.u32 |= X86_EFL_RF; + if (g_uBs3CpuDetected & BS3CPU_F_CPUID) + CtxTmp.rflags.u32 |= X86_EFL_VIF | X86_EFL_VIP; + Bs3TrapSetJmpAndRestore(&CtxTmp, &TrapCtx); + CtxTmp.rflags.u32 &= ~X86_EFL_RF; + + if (iCtx >= iRing) + bs3CpuBasic2_CompareIntCtx1(&TrapCtx, &CtxTmp, 0x80 + iCtx /*bXcpt*/); + else + bs3CpuBasic2_CompareGpCtx(&TrapCtx, &CtxTmp, ((0x80 + iCtx) << X86_TRAP_ERR_SEL_SHIFT) | X86_TRAP_ERR_IDT); + uExpected = CtxTmp.rflags.u32 + & ( X86_EFL_1 | X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF | X86_EFL_DF + | X86_EFL_OF | X86_EFL_IOPL | X86_EFL_NT | X86_EFL_VM | X86_EFL_AC | X86_EFL_VIF | X86_EFL_VIP + | X86_EFL_ID /*| X86_EFL_TF*/ /*| X86_EFL_IF*/ /*| X86_EFL_RF*/ ); + if (TrapCtx.fHandlerRfl != uExpected) + bs3CpuBasic2_FailedF("unexpected handler rflags value: %RX64 expected %RX32; CtxTmp.rflags=%RX64 Ctx.rflags=%RX64\n", + TrapCtx.fHandlerRfl, uExpected, CtxTmp.rflags.u, TrapCtx.Ctx.rflags.u); + g_usBs3TestStep++; + + /* all cleared */ + if ((g_uBs3CpuDetected & BS3CPU_TYPE_MASK) < BS3CPU_80286) + CtxTmp.rflags.u32 = apCtx8x[iCtx]->rflags.u32 & (X86_EFL_RA1_MASK | UINT16_C(0xf000)); + else + CtxTmp.rflags.u32 = apCtx8x[iCtx]->rflags.u32 & (X86_EFL_VM | X86_EFL_RA1_MASK); + Bs3TrapSetJmpAndRestore(&CtxTmp, &TrapCtx); + if (iCtx >= iRing) + bs3CpuBasic2_CompareIntCtx1(&TrapCtx, &CtxTmp, 0x80 + iCtx /*bXcpt*/); + else + bs3CpuBasic2_CompareGpCtx(&TrapCtx, &CtxTmp, ((0x80 + iCtx) << X86_TRAP_ERR_SEL_SHIFT) | X86_TRAP_ERR_IDT); + uExpected = CtxTmp.rflags.u32; + if (TrapCtx.fHandlerRfl != uExpected) + bs3CpuBasic2_FailedF("unexpected handler rflags value: %RX64 expected %RX32; CtxTmp.rflags=%RX64 Ctx.rflags=%RX64\n", + TrapCtx.fHandlerRfl, uExpected, CtxTmp.rflags.u, TrapCtx.Ctx.rflags.u); + g_usBs3TestStep++; + } + } + +/** @todo CS.LIMIT / canonical(CS) */ + + + /* + * Check invalid gate types. + */ + g_usBs3TestStep = 32000; + for (iRing = 0; iRing <= 3; iRing++) + { + static const uint16_t s_auCSes[] = { BS3_SEL_R0_CS16, BS3_SEL_R0_CS32, BS3_SEL_R0_CS64, + BS3_SEL_TSS16, BS3_SEL_TSS32, BS3_SEL_TSS64, 0, BS3_SEL_SPARE_1f }; + static uint16_t const s_auInvlTypes64[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f }; + static uint16_t const s_auInvlTypes32[] = { 0, 1, 2, 3, 8, 9, 10, 11, 13, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + /*286:*/ 12, 14, 15 }; + uint16_t const * const pauInvTypes = cIdteShift != 0 ? s_auInvlTypes64 : s_auInvlTypes32; + uint16_t const cInvTypes = cIdteShift != 0 ? RT_ELEMENTS(s_auInvlTypes64) + : f386Plus ? RT_ELEMENTS(s_auInvlTypes32) - 3 : RT_ELEMENTS(s_auInvlTypes32); + + + for (iCtx = 0; iCtx < RT_ELEMENTS(apCtx8x); iCtx++) + { + unsigned iType; + + Bs3MemCpy(&CtxTmp, apCtx8x[iCtx], sizeof(CtxTmp)); + Bs3RegCtxConvertToRingX(&CtxTmp, iRing); +# if TMPL_BITS == 32 + g_uBs3TrapEipHint = CtxTmp.rip.u32; +# endif + for (iType = 0; iType < cInvTypes; iType++) + { + uint8_t const bSavedType = paIdt[(0x80 + iCtx) << cIdteShift].Gate.u4Type; + paIdt[(0x80 + iCtx) << cIdteShift].Gate.u1DescType = pauInvTypes[iType] >> 4; + paIdt[(0x80 + iCtx) << cIdteShift].Gate.u4Type = pauInvTypes[iType] & 0xf; + + for (i = 0; i < 4; i++) + { + for (j = 0; j < RT_ELEMENTS(s_auCSes); j++) + { + uint16_t uCs = (unsigned)(s_auCSes[j] - BS3_SEL_R0_FIRST) < (unsigned)(4 << BS3_SEL_RING_SHIFT) + ? (s_auCSes[j] | i) + (i << BS3_SEL_RING_SHIFT) + : s_auCSes[j] | i; + /*Bs3TestPrintf("g_usBs3TestStep=%u iCtx=%u iRing=%u i=%u uCs=%04x type=%#x\n", g_usBs3TestStep, iCtx, iRing, i, uCs, pauInvTypes[iType]);*/ + paIdt[(0x80 + iCtx) << cIdteShift].Gate.u16Sel = uCs; + Bs3TrapSetJmpAndRestore(&CtxTmp, &TrapCtx); + g_usBs3TestStep++; + bs3CpuBasic2_CompareGpCtx(&TrapCtx, &CtxTmp, ((0x80 + iCtx) << X86_TRAP_ERR_SEL_SHIFT) | X86_TRAP_ERR_IDT); + + /* Mark it not-present to check that invalid type takes precedence. */ + paIdt[(0x80 + iCtx) << cIdteShift].Gate.u1Present = 0; + Bs3TrapSetJmpAndRestore(&CtxTmp, &TrapCtx); + g_usBs3TestStep++; + bs3CpuBasic2_CompareGpCtx(&TrapCtx, &CtxTmp, ((0x80 + iCtx) << X86_TRAP_ERR_SEL_SHIFT) | X86_TRAP_ERR_IDT); + paIdt[(0x80 + iCtx) << cIdteShift].Gate.u1Present = 1; + } + } + + paIdt[(0x80 + iCtx) << cIdteShift].Gate.u16Sel = uSysR0Cs; + paIdt[(0x80 + iCtx) << cIdteShift].Gate.u4Type = bSavedType; + paIdt[(0x80 + iCtx) << cIdteShift].Gate.u1DescType = 0; + paIdt[(0x80 + iCtx) << cIdteShift].Gate.u1Present = 1; + } + } + } + BS3_ASSERT(g_usBs3TestStep < 62000U && g_usBs3TestStep > 32000U); + + + /** @todo + * - Run \#PF and \#GP (and others?) at CPLs other than zero. + * - Quickly generate all faults. + * - All the peculiarities v8086. + */ + +# if TMPL_BITS != 16 + Bs3MemFree(pbIdtCopyAlloc, 12*_1K); +# endif +} +#endif /* convert me */ + + +/** + * Executes one round of SIDT and SGDT tests using one assembly worker. + * + * This is written with driving everything from the 16-bit or 32-bit worker in + * mind, i.e. not assuming the test bitcount is the same as the current. + */ +static void bs3CpuBasic2_sidt_sgdt_One(BS3CB2SIDTSGDT const BS3_FAR *pWorker, uint8_t bTestMode, uint8_t bRing, + uint8_t const *pbExpected) +{ + BS3TRAPFRAME TrapCtx; + BS3REGCTX Ctx; + BS3REGCTX CtxUdExpected; + BS3REGCTX TmpCtx; + uint8_t const cbBuf = 8*2; /* test buffer area */ + uint8_t abBuf[8*2 + 8 + 8]; /* test buffer w/ misalignment test space and some extra guard. */ + uint8_t BS3_FAR *pbBuf = abBuf; + uint8_t const cbIdtr = BS3_MODE_IS_64BIT_CODE(bTestMode) ? 2+8 : 2+4; + bool const f286 = (g_uBs3CpuDetected & BS3CPU_TYPE_MASK) == BS3CPU_80286; + uint8_t bFiller; + int off; + int off2; + unsigned cb; + uint8_t BS3_FAR *pbTest; + + /* make sure they're allocated */ + Bs3MemZero(&Ctx, sizeof(Ctx)); + Bs3MemZero(&CtxUdExpected, sizeof(CtxUdExpected)); + Bs3MemZero(&TmpCtx, sizeof(TmpCtx)); + Bs3MemZero(&TrapCtx, sizeof(TrapCtx)); + Bs3MemZero(&abBuf, sizeof(abBuf)); + + /* Create a context, give this routine some more stack space, point the context + at our SIDT [xBX] + UD2 combo, and point DS:xBX at abBuf. */ + Bs3RegCtxSaveEx(&Ctx, bTestMode, 256 /*cbExtraStack*/); + Bs3RegCtxSetGrpSegFromCurPtr(&Ctx, &Ctx.rbx, pWorker->fSs ? &Ctx.ss : &Ctx.ds, abBuf); + Bs3RegCtxSetRipCsFromLnkPtr(&Ctx, pWorker->fpfnWorker); + if (BS3_MODE_IS_16BIT_SYS(bTestMode)) + g_uBs3TrapEipHint = Ctx.rip.u32; + if (!BS3_MODE_IS_RM_OR_V86(bTestMode)) + Bs3RegCtxConvertToRingX(&Ctx, bRing); + + /* For successful SIDT attempts, we'll stop at the UD2. */ + Bs3MemCpy(&CtxUdExpected, &Ctx, sizeof(Ctx)); + CtxUdExpected.rip.u += pWorker->cbInstr; + + /* + * Check that it works at all and that only bytes we expect gets written to. + */ + /* First with zero buffer. */ + Bs3MemZero(abBuf, sizeof(abBuf)); + if (!ASMMemIsAllU8(abBuf, sizeof(abBuf), 0)) + Bs3TestFailedF("ASMMemIsAllU8 or Bs3MemZero is busted: abBuf=%.*Rhxs\n", sizeof(abBuf), pbBuf); + if (!ASMMemIsZero(abBuf, sizeof(abBuf))) + Bs3TestFailedF("ASMMemIsZero or Bs3MemZero is busted: abBuf=%.*Rhxs\n", sizeof(abBuf), pbBuf); + Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx); + bs3CpuBasic2_CompareUdCtx(&TrapCtx, &CtxUdExpected); + if (f286 && abBuf[cbIdtr - 1] != 0xff) + Bs3TestFailedF("286: Top base byte isn't 0xff (#1): %#x\n", abBuf[cbIdtr - 1]); + if (!ASMMemIsZero(&abBuf[cbIdtr], cbBuf - cbIdtr)) + Bs3TestFailedF("Unexpected buffer bytes set (#1): cbIdtr=%u abBuf=%.*Rhxs\n", cbIdtr, cbBuf, pbBuf); + if (Bs3MemCmp(abBuf, pbExpected, cbIdtr) != 0) + Bs3TestFailedF("Mismatch (%s,#1): expected %.*Rhxs, got %.*Rhxs\n", pWorker->pszDesc, cbIdtr, pbExpected, cbIdtr, abBuf); + g_usBs3TestStep++; + + /* Again with a buffer filled with a byte not occuring in the previous result. */ + bFiller = 0x55; + while (Bs3MemChr(abBuf, bFiller, cbBuf) != NULL) + bFiller++; + Bs3MemSet(abBuf, bFiller, sizeof(abBuf)); + if (!ASMMemIsAllU8(abBuf, sizeof(abBuf), bFiller)) + Bs3TestFailedF("ASMMemIsAllU8 or Bs3MemSet is busted: bFiller=%#x abBuf=%.*Rhxs\n", bFiller, sizeof(abBuf), pbBuf); + + Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx); + bs3CpuBasic2_CompareUdCtx(&TrapCtx, &CtxUdExpected); + if (f286 && abBuf[cbIdtr - 1] != 0xff) + Bs3TestFailedF("286: Top base byte isn't 0xff (#2): %#x\n", abBuf[cbIdtr - 1]); + if (!ASMMemIsAllU8(&abBuf[cbIdtr], cbBuf - cbIdtr, bFiller)) + Bs3TestFailedF("Unexpected buffer bytes set (#2): cbIdtr=%u bFiller=%#x abBuf=%.*Rhxs\n", cbIdtr, bFiller, cbBuf, pbBuf); + if (Bs3MemChr(abBuf, bFiller, cbIdtr) != NULL) + Bs3TestFailedF("Not all bytes touched: cbIdtr=%u bFiller=%#x abBuf=%.*Rhxs\n", cbIdtr, bFiller, cbBuf, pbBuf); + if (Bs3MemCmp(abBuf, pbExpected, cbIdtr) != 0) + Bs3TestFailedF("Mismatch (%s,#2): expected %.*Rhxs, got %.*Rhxs\n", pWorker->pszDesc, cbIdtr, pbExpected, cbIdtr, abBuf); + g_usBs3TestStep++; + + /* + * Slide the buffer along 8 bytes to cover misalignment. + */ + for (off = 0; off < 8; off++) + { + pbBuf = &abBuf[off]; + Bs3RegCtxSetGrpSegFromCurPtr(&Ctx, &Ctx.rbx, pWorker->fSs ? &Ctx.ss : &Ctx.ds, &abBuf[off]); + CtxUdExpected.rbx.u = Ctx.rbx.u; + + /* First with zero buffer. */ + Bs3MemZero(abBuf, sizeof(abBuf)); + Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx); + bs3CpuBasic2_CompareUdCtx(&TrapCtx, &CtxUdExpected); + if (off > 0 && !ASMMemIsZero(abBuf, off)) + Bs3TestFailedF("Unexpected buffer bytes set before (#3): cbIdtr=%u off=%u abBuf=%.*Rhxs\n", + cbIdtr, off, off + cbBuf, abBuf); + if (!ASMMemIsZero(&abBuf[off + cbIdtr], sizeof(abBuf) - cbIdtr - off)) + Bs3TestFailedF("Unexpected buffer bytes set after (#3): cbIdtr=%u off=%u abBuf=%.*Rhxs\n", + cbIdtr, off, off + cbBuf, abBuf); + if (f286 && abBuf[off + cbIdtr - 1] != 0xff) + Bs3TestFailedF("286: Top base byte isn't 0xff (#3): %#x\n", abBuf[off + cbIdtr - 1]); + if (Bs3MemCmp(&abBuf[off], pbExpected, cbIdtr) != 0) + Bs3TestFailedF("Mismatch (#3): expected %.*Rhxs, got %.*Rhxs\n", cbIdtr, pbExpected, cbIdtr, &abBuf[off]); + g_usBs3TestStep++; + + /* Again with a buffer filled with a byte not occuring in the previous result. */ + Bs3MemSet(abBuf, bFiller, sizeof(abBuf)); + Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx); + bs3CpuBasic2_CompareUdCtx(&TrapCtx, &CtxUdExpected); + if (off > 0 && !ASMMemIsAllU8(abBuf, off, bFiller)) + Bs3TestFailedF("Unexpected buffer bytes set before (#4): cbIdtr=%u off=%u bFiller=%#x abBuf=%.*Rhxs\n", + cbIdtr, off, bFiller, off + cbBuf, abBuf); + if (!ASMMemIsAllU8(&abBuf[off + cbIdtr], sizeof(abBuf) - cbIdtr - off, bFiller)) + Bs3TestFailedF("Unexpected buffer bytes set after (#4): cbIdtr=%u off=%u bFiller=%#x abBuf=%.*Rhxs\n", + cbIdtr, off, bFiller, off + cbBuf, abBuf); + if (Bs3MemChr(&abBuf[off], bFiller, cbIdtr) != NULL) + Bs3TestFailedF("Not all bytes touched (#4): cbIdtr=%u off=%u bFiller=%#x abBuf=%.*Rhxs\n", + cbIdtr, off, bFiller, off + cbBuf, abBuf); + if (f286 && abBuf[off + cbIdtr - 1] != 0xff) + Bs3TestFailedF("286: Top base byte isn't 0xff (#4): %#x\n", abBuf[off + cbIdtr - 1]); + if (Bs3MemCmp(&abBuf[off], pbExpected, cbIdtr) != 0) + Bs3TestFailedF("Mismatch (#4): expected %.*Rhxs, got %.*Rhxs\n", cbIdtr, pbExpected, cbIdtr, &abBuf[off]); + g_usBs3TestStep++; + } + pbBuf = abBuf; + Bs3RegCtxSetGrpSegFromCurPtr(&Ctx, &Ctx.rbx, pWorker->fSs ? &Ctx.ss : &Ctx.ds, abBuf); + CtxUdExpected.rbx.u = Ctx.rbx.u; + + /* + * Play with the selector limit if the target mode supports limit checking + * We use BS3_SEL_TEST_PAGE_00 for this + */ + if ( !BS3_MODE_IS_RM_OR_V86(bTestMode) + && !BS3_MODE_IS_64BIT_CODE(bTestMode)) + { + uint16_t cbLimit; + uint32_t uFlatBuf = Bs3SelPtrToFlat(abBuf); + Bs3GdteTestPage00 = Bs3Gdte_DATA16; + Bs3GdteTestPage00.Gen.u2Dpl = bRing; + Bs3GdteTestPage00.Gen.u16BaseLow = (uint16_t)uFlatBuf; + Bs3GdteTestPage00.Gen.u8BaseHigh1 = (uint8_t)(uFlatBuf >> 16); + Bs3GdteTestPage00.Gen.u8BaseHigh2 = (uint8_t)(uFlatBuf >> 24); + + if (pWorker->fSs) + CtxUdExpected.ss = Ctx.ss = BS3_SEL_TEST_PAGE_00 | bRing; + else + CtxUdExpected.ds = Ctx.ds = BS3_SEL_TEST_PAGE_00 | bRing; + + /* Expand up (normal). */ + for (off = 0; off < 8; off++) + { + CtxUdExpected.rbx.u = Ctx.rbx.u = off; + for (cbLimit = 0; cbLimit < cbIdtr*2; cbLimit++) + { + Bs3GdteTestPage00.Gen.u16LimitLow = cbLimit; + Bs3MemSet(abBuf, bFiller, sizeof(abBuf)); + Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx); + if (off + cbIdtr <= cbLimit + 1) + { + bs3CpuBasic2_CompareUdCtx(&TrapCtx, &CtxUdExpected); + if (Bs3MemChr(&abBuf[off], bFiller, cbIdtr) != NULL) + Bs3TestFailedF("Not all bytes touched (#5): cbIdtr=%u off=%u cbLimit=%u bFiller=%#x abBuf=%.*Rhxs\n", + cbIdtr, off, cbLimit, bFiller, off + cbBuf, abBuf); + if (Bs3MemCmp(&abBuf[off], pbExpected, cbIdtr) != 0) + Bs3TestFailedF("Mismatch (#5): expected %.*Rhxs, got %.*Rhxs\n", cbIdtr, pbExpected, cbIdtr, &abBuf[off]); + if (f286 && abBuf[off + cbIdtr - 1] != 0xff) + Bs3TestFailedF("286: Top base byte isn't 0xff (#5): %#x\n", abBuf[off + cbIdtr - 1]); + } + else + { + if (pWorker->fSs) + bs3CpuBasic2_CompareSsCtx(&TrapCtx, &Ctx, 0, false /*f486ResumeFlagHint*/); + else + bs3CpuBasic2_CompareGpCtx(&TrapCtx, &Ctx, 0); + if (off + 2 <= cbLimit + 1) + { + if (Bs3MemChr(&abBuf[off], bFiller, 2) != NULL) + Bs3TestFailedF("Limit bytes not touched (#6): cbIdtr=%u off=%u cbLimit=%u bFiller=%#x abBuf=%.*Rhxs\n", + cbIdtr, off, cbLimit, bFiller, off + cbBuf, abBuf); + if (Bs3MemCmp(&abBuf[off], pbExpected, 2) != 0) + Bs3TestFailedF("Mismatch (#6): expected %.2Rhxs, got %.2Rhxs\n", pbExpected, &abBuf[off]); + if (!ASMMemIsAllU8(&abBuf[off + 2], cbIdtr - 2, bFiller)) + Bs3TestFailedF("Base bytes touched on #GP (#6): cbIdtr=%u off=%u cbLimit=%u bFiller=%#x abBuf=%.*Rhxs\n", + cbIdtr, off, cbLimit, bFiller, off + cbBuf, abBuf); + } + else if (!ASMMemIsAllU8(abBuf, sizeof(abBuf), bFiller)) + Bs3TestFailedF("Bytes touched on #GP: cbIdtr=%u off=%u cbLimit=%u bFiller=%#x abBuf=%.*Rhxs\n", + cbIdtr, off, cbLimit, bFiller, off + cbBuf, abBuf); + } + + if (off > 0 && !ASMMemIsAllU8(abBuf, off, bFiller)) + Bs3TestFailedF("Leading bytes touched (#7): cbIdtr=%u off=%u cbLimit=%u bFiller=%#x abBuf=%.*Rhxs\n", + cbIdtr, off, cbLimit, bFiller, off + cbBuf, abBuf); + if (!ASMMemIsAllU8(&abBuf[off + cbIdtr], sizeof(abBuf) - off - cbIdtr, bFiller)) + Bs3TestFailedF("Trailing bytes touched (#7): cbIdtr=%u off=%u cbLimit=%u bFiller=%#x abBuf=%.*Rhxs\n", + cbIdtr, off, cbLimit, bFiller, off + cbBuf, abBuf); + + g_usBs3TestStep++; + } + } + + /* Expand down (weird). Inverted valid area compared to expand up, + so a limit of zero give us a valid range for 0001..0ffffh (instead of + a segment with one valid byte at 0000h). Whereas a limit of 0fffeh + means one valid byte at 0ffffh, and a limit of 0ffffh means none + (because in a normal expand up the 0ffffh means all 64KB are + accessible). */ + Bs3GdteTestPage00.Gen.u4Type = X86_SEL_TYPE_RW_DOWN_ACC; + for (off = 0; off < 8; off++) + { + CtxUdExpected.rbx.u = Ctx.rbx.u = off; + for (cbLimit = 0; cbLimit < cbIdtr*2; cbLimit++) + { + Bs3GdteTestPage00.Gen.u16LimitLow = cbLimit; + Bs3MemSet(abBuf, bFiller, sizeof(abBuf)); + Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx); + + if (off > cbLimit) + { + bs3CpuBasic2_CompareUdCtx(&TrapCtx, &CtxUdExpected); + if (Bs3MemChr(&abBuf[off], bFiller, cbIdtr) != NULL) + Bs3TestFailedF("Not all bytes touched (#8): cbIdtr=%u off=%u cbLimit=%u bFiller=%#x abBuf=%.*Rhxs\n", + cbIdtr, off, cbLimit, bFiller, off + cbBuf, abBuf); + if (Bs3MemCmp(&abBuf[off], pbExpected, cbIdtr) != 0) + Bs3TestFailedF("Mismatch (#8): expected %.*Rhxs, got %.*Rhxs\n", cbIdtr, pbExpected, cbIdtr, &abBuf[off]); + if (f286 && abBuf[off + cbIdtr - 1] != 0xff) + Bs3TestFailedF("286: Top base byte isn't 0xff (#8): %#x\n", abBuf[off + cbIdtr - 1]); + } + else + { + if (pWorker->fSs) + bs3CpuBasic2_CompareSsCtx(&TrapCtx, &Ctx, 0, false /*f486ResumeFlagHint*/); + else + bs3CpuBasic2_CompareGpCtx(&TrapCtx, &Ctx, 0); + if (!ASMMemIsAllU8(abBuf, sizeof(abBuf), bFiller)) + Bs3TestFailedF("Bytes touched on #GP: cbIdtr=%u off=%u cbLimit=%u bFiller=%#x abBuf=%.*Rhxs\n", + cbIdtr, off, cbLimit, bFiller, off + cbBuf, abBuf); + } + + if (off > 0 && !ASMMemIsAllU8(abBuf, off, bFiller)) + Bs3TestFailedF("Leading bytes touched (#9): cbIdtr=%u off=%u cbLimit=%u bFiller=%#x abBuf=%.*Rhxs\n", + cbIdtr, off, cbLimit, bFiller, off + cbBuf, abBuf); + if (!ASMMemIsAllU8(&abBuf[off + cbIdtr], sizeof(abBuf) - off - cbIdtr, bFiller)) + Bs3TestFailedF("Trailing bytes touched (#9): cbIdtr=%u off=%u cbLimit=%u bFiller=%#x abBuf=%.*Rhxs\n", + cbIdtr, off, cbLimit, bFiller, off + cbBuf, abBuf); + + g_usBs3TestStep++; + } + } + + Bs3RegCtxSetGrpSegFromCurPtr(&Ctx, &Ctx.rbx, pWorker->fSs ? &Ctx.ss : &Ctx.ds, abBuf); + CtxUdExpected.rbx.u = Ctx.rbx.u; + CtxUdExpected.ss = Ctx.ss; + CtxUdExpected.ds = Ctx.ds; + } + + /* + * Play with the paging. + */ + if ( BS3_MODE_IS_PAGED(bTestMode) + && (!pWorker->fSs || bRing == 3) /* SS.DPL == CPL, we'll get some tiled ring-3 selector here. */ + && (pbTest = (uint8_t BS3_FAR *)Bs3MemGuardedTestPageAlloc(BS3MEMKIND_TILED)) != NULL) + { + RTCCUINTXREG uFlatTest = Bs3SelPtrToFlat(pbTest); + + /* + * Slide the buffer towards the trailing guard page. We'll observe the + * first word being written entirely separately from the 2nd dword/qword. + */ + for (off = X86_PAGE_SIZE - cbIdtr - 4; off < X86_PAGE_SIZE + 4; off++) + { + Bs3MemSet(&pbTest[X86_PAGE_SIZE - cbIdtr * 2], bFiller, cbIdtr * 2); + Bs3RegCtxSetGrpSegFromCurPtr(&Ctx, &Ctx.rbx, pWorker->fSs ? &Ctx.ss : &Ctx.ds, &pbTest[off]); + Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx); + if (off + cbIdtr <= X86_PAGE_SIZE) + { + CtxUdExpected.rbx = Ctx.rbx; + CtxUdExpected.ss = Ctx.ss; + CtxUdExpected.ds = Ctx.ds; + bs3CpuBasic2_CompareUdCtx(&TrapCtx, &CtxUdExpected); + if (Bs3MemCmp(&pbTest[off], pbExpected, cbIdtr) != 0) + Bs3TestFailedF("Mismatch (#9): expected %.*Rhxs, got %.*Rhxs\n", cbIdtr, pbExpected, cbIdtr, &pbTest[off]); + } + else + { + bs3CpuBasic2_ComparePfCtx(&TrapCtx, &Ctx, X86_TRAP_PF_RW | (Ctx.bCpl == 3 ? X86_TRAP_PF_US : 0), + uFlatTest + RT_MAX(off, X86_PAGE_SIZE)); + if ( off <= X86_PAGE_SIZE - 2 + && Bs3MemCmp(&pbTest[off], pbExpected, 2) != 0) + Bs3TestFailedF("Mismatch (#10): Expected limit %.2Rhxs, got %.2Rhxs; off=%#x\n", + pbExpected, &pbTest[off], off); + if ( off < X86_PAGE_SIZE - 2 + && !ASMMemIsAllU8(&pbTest[off + 2], X86_PAGE_SIZE - off - 2, bFiller)) + Bs3TestFailedF("Wrote partial base on #PF (#10): bFiller=%#x, got %.*Rhxs; off=%#x\n", + bFiller, X86_PAGE_SIZE - off - 2, &pbTest[off + 2], off); + if (off == X86_PAGE_SIZE - 1 && pbTest[off] != bFiller) + Bs3TestFailedF("Wrote partial limit on #PF (#10): Expected %02x, got %02x\n", bFiller, pbTest[off]); + } + g_usBs3TestStep++; + } + + /* + * Now, do it the other way around. It should look normal now since writing + * the limit will #PF first and nothing should be written. + */ + for (off = cbIdtr + 4; off >= -cbIdtr - 4; off--) + { + Bs3MemSet(pbTest, bFiller, 48); + Bs3RegCtxSetGrpSegFromCurPtr(&Ctx, &Ctx.rbx, pWorker->fSs ? &Ctx.ss : &Ctx.ds, &pbTest[off]); + Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx); + if (off >= 0) + { + CtxUdExpected.rbx = Ctx.rbx; + CtxUdExpected.ss = Ctx.ss; + CtxUdExpected.ds = Ctx.ds; + bs3CpuBasic2_CompareUdCtx(&TrapCtx, &CtxUdExpected); + if (Bs3MemCmp(&pbTest[off], pbExpected, cbIdtr) != 0) + Bs3TestFailedF("Mismatch (#11): expected %.*Rhxs, got %.*Rhxs\n", cbIdtr, pbExpected, cbIdtr, &pbTest[off]); + } + else + { + bs3CpuBasic2_ComparePfCtx(&TrapCtx, &Ctx, X86_TRAP_PF_RW | (Ctx.bCpl == 3 ? X86_TRAP_PF_US : 0), uFlatTest + off); + if ( -off < cbIdtr + && !ASMMemIsAllU8(pbTest, cbIdtr + off, bFiller)) + Bs3TestFailedF("Wrote partial content on #PF (#12): bFiller=%#x, found %.*Rhxs; off=%d\n", + bFiller, cbIdtr + off, pbTest, off); + } + if (!ASMMemIsAllU8(&pbTest[RT_MAX(cbIdtr + off, 0)], 16, bFiller)) + Bs3TestFailedF("Wrote beyond expected area (#13): bFiller=%#x, found %.16Rhxs; off=%d\n", + bFiller, &pbTest[RT_MAX(cbIdtr + off, 0)], off); + g_usBs3TestStep++; + } + + /* + * Combine paging and segment limit and check ordering. + * This is kind of interesting here since it the instruction seems to + * be doing two separate writes. + */ + if ( !BS3_MODE_IS_RM_OR_V86(bTestMode) + && !BS3_MODE_IS_64BIT_CODE(bTestMode)) + { + uint16_t cbLimit; + + Bs3GdteTestPage00 = Bs3Gdte_DATA16; + Bs3GdteTestPage00.Gen.u2Dpl = bRing; + Bs3GdteTestPage00.Gen.u16BaseLow = (uint16_t)uFlatTest; + Bs3GdteTestPage00.Gen.u8BaseHigh1 = (uint8_t)(uFlatTest >> 16); + Bs3GdteTestPage00.Gen.u8BaseHigh2 = (uint8_t)(uFlatTest >> 24); + + if (pWorker->fSs) + CtxUdExpected.ss = Ctx.ss = BS3_SEL_TEST_PAGE_00 | bRing; + else + CtxUdExpected.ds = Ctx.ds = BS3_SEL_TEST_PAGE_00 | bRing; + + /* Expand up (normal), approaching tail guard page. */ + for (off = X86_PAGE_SIZE - cbIdtr - 4; off < X86_PAGE_SIZE + 4; off++) + { + CtxUdExpected.rbx.u = Ctx.rbx.u = off; + for (cbLimit = X86_PAGE_SIZE - cbIdtr*2; cbLimit < X86_PAGE_SIZE + cbIdtr*2; cbLimit++) + { + Bs3GdteTestPage00.Gen.u16LimitLow = cbLimit; + Bs3MemSet(&pbTest[X86_PAGE_SIZE - cbIdtr * 2], bFiller, cbIdtr * 2); + Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx); + if (off + cbIdtr <= cbLimit + 1) + { + /* No #GP, but maybe #PF. */ + if (off + cbIdtr <= X86_PAGE_SIZE) + { + bs3CpuBasic2_CompareUdCtx(&TrapCtx, &CtxUdExpected); + if (Bs3MemCmp(&pbTest[off], pbExpected, cbIdtr) != 0) + Bs3TestFailedF("Mismatch (#14): expected %.*Rhxs, got %.*Rhxs\n", + cbIdtr, pbExpected, cbIdtr, &pbTest[off]); + } + else + { + bs3CpuBasic2_ComparePfCtx(&TrapCtx, &Ctx, X86_TRAP_PF_RW | (Ctx.bCpl == 3 ? X86_TRAP_PF_US : 0), + uFlatTest + RT_MAX(off, X86_PAGE_SIZE)); + if ( off <= X86_PAGE_SIZE - 2 + && Bs3MemCmp(&pbTest[off], pbExpected, 2) != 0) + Bs3TestFailedF("Mismatch (#15): Expected limit %.2Rhxs, got %.2Rhxs; off=%#x\n", + pbExpected, &pbTest[off], off); + cb = X86_PAGE_SIZE - off - 2; + if ( off < X86_PAGE_SIZE - 2 + && !ASMMemIsAllU8(&pbTest[off + 2], cb, bFiller)) + Bs3TestFailedF("Wrote partial base on #PF (#15): bFiller=%#x, got %.*Rhxs; off=%#x\n", + bFiller, cb, &pbTest[off + 2], off); + if (off == X86_PAGE_SIZE - 1 && pbTest[off] != bFiller) + Bs3TestFailedF("Wrote partial limit on #PF (#15): Expected %02x, got %02x\n", bFiller, pbTest[off]); + } + } + else if (off + 2 <= cbLimit + 1) + { + /* [ig]tr.limit writing does not cause #GP, but may cause #PG, if not writing the base causes #GP. */ + if (off <= X86_PAGE_SIZE - 2) + { + if (pWorker->fSs) + bs3CpuBasic2_CompareSsCtx(&TrapCtx, &Ctx, 0, false /*f486ResumeFlagHint*/); + else + bs3CpuBasic2_CompareGpCtx(&TrapCtx, &Ctx, 0); + if (Bs3MemCmp(&pbTest[off], pbExpected, 2) != 0) + Bs3TestFailedF("Mismatch (#16): Expected limit %.2Rhxs, got %.2Rhxs; off=%#x\n", + pbExpected, &pbTest[off], off); + cb = X86_PAGE_SIZE - off - 2; + if ( off < X86_PAGE_SIZE - 2 + && !ASMMemIsAllU8(&pbTest[off + 2], cb, bFiller)) + Bs3TestFailedF("Wrote partial base with limit (#16): bFiller=%#x, got %.*Rhxs; off=%#x\n", + bFiller, cb, &pbTest[off + 2], off); + } + else + { + bs3CpuBasic2_ComparePfCtx(&TrapCtx, &Ctx, X86_TRAP_PF_RW | (Ctx.bCpl == 3 ? X86_TRAP_PF_US : 0), + uFlatTest + RT_MAX(off, X86_PAGE_SIZE)); + if ( off < X86_PAGE_SIZE + && !ASMMemIsAllU8(&pbTest[off], X86_PAGE_SIZE - off, bFiller)) + Bs3TestFailedF("Mismatch (#16): Partial limit write on #PF: bFiller=%#x, got %.*Rhxs\n", + bFiller, X86_PAGE_SIZE - off, &pbTest[off]); + } + } + else + { + /* #GP/#SS on limit. */ + if (pWorker->fSs) + bs3CpuBasic2_CompareSsCtx(&TrapCtx, &Ctx, 0, false /*f486ResumeFlagHint*/); + else + bs3CpuBasic2_CompareGpCtx(&TrapCtx, &Ctx, 0); + if ( off < X86_PAGE_SIZE + && !ASMMemIsAllU8(&pbTest[off], X86_PAGE_SIZE - off, bFiller)) + Bs3TestFailedF("Mismatch (#17): Partial write on #GP: bFiller=%#x, got %.*Rhxs\n", + bFiller, X86_PAGE_SIZE - off, &pbTest[off]); + } + + cb = RT_MIN(cbIdtr * 2, off - (X86_PAGE_SIZE - cbIdtr*2)); + if (!ASMMemIsAllU8(&pbTest[X86_PAGE_SIZE - cbIdtr * 2], cb, bFiller)) + Bs3TestFailedF("Leading bytes touched (#18): cbIdtr=%u off=%u cbLimit=%u bFiller=%#x pbTest=%.*Rhxs\n", + cbIdtr, off, cbLimit, bFiller, cb, pbTest[X86_PAGE_SIZE - cbIdtr * 2]); + + g_usBs3TestStep++; + + /* Set DS to 0 and check that we get #GP(0). */ + if (!pWorker->fSs) + { + Ctx.ds = 0; + Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx); + bs3CpuBasic2_CompareGpCtx(&TrapCtx, &Ctx, 0); + Ctx.ds = BS3_SEL_TEST_PAGE_00 | bRing; + g_usBs3TestStep++; + } + } + } + + /* Expand down. */ + pbTest -= X86_PAGE_SIZE; /* Note! we're backing up a page to simplify things */ + uFlatTest -= X86_PAGE_SIZE; + + Bs3GdteTestPage00.Gen.u4Type = X86_SEL_TYPE_RW_DOWN_ACC; + Bs3GdteTestPage00.Gen.u16BaseLow = (uint16_t)uFlatTest; + Bs3GdteTestPage00.Gen.u8BaseHigh1 = (uint8_t)(uFlatTest >> 16); + Bs3GdteTestPage00.Gen.u8BaseHigh2 = (uint8_t)(uFlatTest >> 24); + + for (off = X86_PAGE_SIZE - cbIdtr - 4; off < X86_PAGE_SIZE + 4; off++) + { + CtxUdExpected.rbx.u = Ctx.rbx.u = off; + for (cbLimit = X86_PAGE_SIZE - cbIdtr*2; cbLimit < X86_PAGE_SIZE + cbIdtr*2; cbLimit++) + { + Bs3GdteTestPage00.Gen.u16LimitLow = cbLimit; + Bs3MemSet(&pbTest[X86_PAGE_SIZE], bFiller, cbIdtr * 2); + Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx); + if (cbLimit < off && off >= X86_PAGE_SIZE) + { + bs3CpuBasic2_CompareUdCtx(&TrapCtx, &CtxUdExpected); + if (Bs3MemCmp(&pbTest[off], pbExpected, cbIdtr) != 0) + Bs3TestFailedF("Mismatch (#19): expected %.*Rhxs, got %.*Rhxs\n", + cbIdtr, pbExpected, cbIdtr, &pbTest[off]); + cb = X86_PAGE_SIZE + cbIdtr*2 - off; + if (!ASMMemIsAllU8(&pbTest[off + cbIdtr], cb, bFiller)) + Bs3TestFailedF("Trailing bytes touched (#20): cbIdtr=%u off=%u cbLimit=%u bFiller=%#x pbTest=%.*Rhxs\n", + cbIdtr, off, cbLimit, bFiller, cb, pbTest[off + cbIdtr]); + } + else + { + if (cbLimit < off && off < X86_PAGE_SIZE) + bs3CpuBasic2_ComparePfCtx(&TrapCtx, &Ctx, X86_TRAP_PF_RW | (Ctx.bCpl == 3 ? X86_TRAP_PF_US : 0), + uFlatTest + off); + else if (pWorker->fSs) + bs3CpuBasic2_CompareSsCtx(&TrapCtx, &Ctx, 0, false /*f486ResumeFlagHint*/); + else + bs3CpuBasic2_CompareGpCtx(&TrapCtx, &Ctx, 0); + cb = cbIdtr*2; + if (!ASMMemIsAllU8(&pbTest[X86_PAGE_SIZE], cb, bFiller)) + Bs3TestFailedF("Trailing bytes touched (#20): cbIdtr=%u off=%u cbLimit=%u bFiller=%#x pbTest=%.*Rhxs\n", + cbIdtr, off, cbLimit, bFiller, cb, pbTest[X86_PAGE_SIZE]); + } + g_usBs3TestStep++; + } + } + + pbTest += X86_PAGE_SIZE; + uFlatTest += X86_PAGE_SIZE; + } + + Bs3MemGuardedTestPageFree(pbTest); + } + + /* + * Check non-canonical 64-bit space. + */ + if ( BS3_MODE_IS_64BIT_CODE(bTestMode) + && (pbTest = (uint8_t BS3_FAR *)Bs3PagingSetupCanonicalTraps()) != NULL) + { + /* Make our references relative to the gap. */ + pbTest += g_cbBs3PagingOneCanonicalTrap; + + /* Hit it from below. */ + for (off = -cbIdtr - 8; off < cbIdtr + 8; off++) + { + Ctx.rbx.u = CtxUdExpected.rbx.u = UINT64_C(0x0000800000000000) + off; + Bs3MemSet(&pbTest[-64], bFiller, 64*2); + Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx); + if (off + cbIdtr <= 0) + { + bs3CpuBasic2_CompareUdCtx(&TrapCtx, &CtxUdExpected); + if (Bs3MemCmp(&pbTest[off], pbExpected, cbIdtr) != 0) + Bs3TestFailedF("Mismatch (#21): expected %.*Rhxs, got %.*Rhxs\n", cbIdtr, pbExpected, cbIdtr, &pbTest[off]); + } + else + { + bs3CpuBasic2_CompareGpCtx(&TrapCtx, &Ctx, 0); + if (off <= -2 && Bs3MemCmp(&pbTest[off], pbExpected, 2) != 0) + Bs3TestFailedF("Mismatch (#21): expected limit %.2Rhxs, got %.2Rhxs\n", pbExpected, &pbTest[off]); + off2 = off <= -2 ? 2 : 0; + cb = cbIdtr - off2; + if (!ASMMemIsAllU8(&pbTest[off + off2], cb, bFiller)) + Bs3TestFailedF("Mismatch (#21): touched base %.*Rhxs, got %.*Rhxs\n", + cb, &pbExpected[off], cb, &pbTest[off + off2]); + } + if (!ASMMemIsAllU8(&pbTest[off - 16], 16, bFiller)) + Bs3TestFailedF("Leading bytes touched (#21): bFiller=%#x, got %.16Rhxs\n", bFiller, &pbTest[off]); + if (!ASMMemIsAllU8(&pbTest[off + cbIdtr], 16, bFiller)) + Bs3TestFailedF("Trailing bytes touched (#21): bFiller=%#x, got %.16Rhxs\n", bFiller, &pbTest[off + cbIdtr]); + } + + /* Hit it from above. */ + for (off = -cbIdtr - 8; off < cbIdtr + 8; off++) + { + Ctx.rbx.u = CtxUdExpected.rbx.u = UINT64_C(0xffff800000000000) + off; + Bs3MemSet(&pbTest[-64], bFiller, 64*2); + Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx); + if (off >= 0) + { + bs3CpuBasic2_CompareUdCtx(&TrapCtx, &CtxUdExpected); + if (Bs3MemCmp(&pbTest[off], pbExpected, cbIdtr) != 0) + Bs3TestFailedF("Mismatch (#22): expected %.*Rhxs, got %.*Rhxs\n", cbIdtr, pbExpected, cbIdtr, &pbTest[off]); + } + else + { + bs3CpuBasic2_CompareGpCtx(&TrapCtx, &Ctx, 0); + if (!ASMMemIsAllU8(&pbTest[off], cbIdtr, bFiller)) + Bs3TestFailedF("Mismatch (#22): touched base %.*Rhxs, got %.*Rhxs\n", + cbIdtr, &pbExpected[off], cbIdtr, &pbTest[off]); + } + if (!ASMMemIsAllU8(&pbTest[off - 16], 16, bFiller)) + Bs3TestFailedF("Leading bytes touched (#22): bFiller=%#x, got %.16Rhxs\n", bFiller, &pbTest[off]); + if (!ASMMemIsAllU8(&pbTest[off + cbIdtr], 16, bFiller)) + Bs3TestFailedF("Trailing bytes touched (#22): bFiller=%#x, got %.16Rhxs\n", bFiller, &pbTest[off + cbIdtr]); + } + + } +} + + +static void bs3CpuBasic2_sidt_sgdt_Common(uint8_t bTestMode, BS3CB2SIDTSGDT const BS3_FAR *paWorkers, unsigned cWorkers, + uint8_t const *pbExpected) +{ + unsigned idx; + unsigned bRing; + unsigned iStep = 0; + + /* Note! We skip the SS checks for ring-0 since we badly mess up SS in the + test and don't want to bother with double faults. */ + for (bRing = 0; bRing <= 3; bRing++) + { + for (idx = 0; idx < cWorkers; idx++) + if ( (paWorkers[idx].bMode & (bTestMode & BS3_MODE_CODE_MASK)) + && (!paWorkers[idx].fSs || bRing != 0 /** @todo || BS3_MODE_IS_64BIT_SYS(bTestMode)*/ )) + { + g_usBs3TestStep = iStep; + bs3CpuBasic2_sidt_sgdt_One(&paWorkers[idx], bTestMode, bRing, pbExpected); + iStep += 1000; + } + if (BS3_MODE_IS_RM_OR_V86(bTestMode)) + break; + } +} + + +BS3_DECL_FAR(uint8_t) BS3_CMN_FAR_NM(bs3CpuBasic2_sidt)(uint8_t bMode) +{ + union + { + RTIDTR Idtr; + uint8_t ab[16]; + } Expected; + + //if (bMode != BS3_MODE_LM64) return BS3TESTDOMODE_SKIPPED; + bs3CpuBasic2_SetGlobals(bMode); + + /* + * Pass to common worker which is only compiled once per mode. + */ + Bs3MemZero(&Expected, sizeof(Expected)); + ASMGetIDTR(&Expected.Idtr); + bs3CpuBasic2_sidt_sgdt_Common(bMode, g_aSidtWorkers, RT_ELEMENTS(g_aSidtWorkers), Expected.ab); + + /* + * Re-initialize the IDT. + */ + Bs3TrapReInit(); + return 0; +} + + +BS3_DECL_FAR(uint8_t) BS3_CMN_FAR_NM(bs3CpuBasic2_sgdt)(uint8_t bMode) +{ + uint64_t const uOrgAddr = Bs3Lgdt_Gdt.uAddr; + uint64_t uNew = 0; + union + { + RTGDTR Gdtr; + uint8_t ab[16]; + } Expected; + + //if (bMode != BS3_MODE_LM64) return BS3TESTDOMODE_SKIPPED; + bs3CpuBasic2_SetGlobals(bMode); + + /* + * If paged mode, try push the GDT way up. + */ + Bs3MemZero(&Expected, sizeof(Expected)); + ASMGetGDTR(&Expected.Gdtr); + if (BS3_MODE_IS_PAGED(bMode)) + { +/** @todo loading non-canonical base addresses. */ + int rc; + uNew = BS3_MODE_IS_64BIT_SYS(bMode) ? UINT64_C(0xffff80fedcb70000) : UINT64_C(0xc2d28000); + uNew |= uOrgAddr & X86_PAGE_OFFSET_MASK; + rc = Bs3PagingAlias(uNew, uOrgAddr, Bs3Lgdt_Gdt.cb, X86_PTE_P | X86_PTE_RW | X86_PTE_US | X86_PTE_D | X86_PTE_A); + if (RT_SUCCESS(rc)) + { + Bs3Lgdt_Gdt.uAddr = uNew; + Bs3UtilSetFullGdtr(Bs3Lgdt_Gdt.cb, uNew); + ASMGetGDTR(&Expected.Gdtr); + if (BS3_MODE_IS_64BIT_SYS(bMode) && ARCH_BITS != 64) + *(uint32_t *)&Expected.ab[6] = (uint32_t)(uNew >> 32); + } + } + + /* + * Pass to common worker which is only compiled once per mode. + */ + bs3CpuBasic2_sidt_sgdt_Common(bMode, g_aSgdtWorkers, RT_ELEMENTS(g_aSgdtWorkers), Expected.ab); + + /* + * Unalias the GDT. + */ + if (uNew != 0) + { + Bs3Lgdt_Gdt.uAddr = uOrgAddr; + Bs3UtilSetFullGdtr(Bs3Lgdt_Gdt.cb, uOrgAddr); + Bs3PagingUnalias(uNew, Bs3Lgdt_Gdt.cb); + } + + /* + * Re-initialize the IDT. + */ + Bs3TrapReInit(); + return 0; +} + + + +/* + * LIDT & LGDT + */ + +/** + * Executes one round of LIDT and LGDT tests using one assembly worker. + * + * This is written with driving everything from the 16-bit or 32-bit worker in + * mind, i.e. not assuming the test bitcount is the same as the current. + */ +static void bs3CpuBasic2_lidt_lgdt_One(BS3CB2SIDTSGDT const BS3_FAR *pWorker, uint8_t bTestMode, uint8_t bRing, + uint8_t const *pbRestore, size_t cbRestore, uint8_t const *pbExpected) +{ + static const struct + { + bool fGP; + uint16_t cbLimit; + uint64_t u64Base; + } s_aValues64[] = + { + { false, 0x0000, UINT64_C(0x0000000000000000) }, + { false, 0x0001, UINT64_C(0x0000000000000001) }, + { false, 0x0002, UINT64_C(0x0000000000000010) }, + { false, 0x0003, UINT64_C(0x0000000000000123) }, + { false, 0x0004, UINT64_C(0x0000000000001234) }, + { false, 0x0005, UINT64_C(0x0000000000012345) }, + { false, 0x0006, UINT64_C(0x0000000000123456) }, + { false, 0x0007, UINT64_C(0x0000000001234567) }, + { false, 0x0008, UINT64_C(0x0000000012345678) }, + { false, 0x0009, UINT64_C(0x0000000123456789) }, + { false, 0x000a, UINT64_C(0x000000123456789a) }, + { false, 0x000b, UINT64_C(0x00000123456789ab) }, + { false, 0x000c, UINT64_C(0x0000123456789abc) }, + { false, 0x001c, UINT64_C(0x00007ffffeefefef) }, + { false, 0xffff, UINT64_C(0x00007fffffffffff) }, + { true, 0xf3f1, UINT64_C(0x0000800000000000) }, + { true, 0x0000, UINT64_C(0x0000800000000000) }, + { true, 0x0000, UINT64_C(0x0000800000000333) }, + { true, 0x00f0, UINT64_C(0x0001000000000000) }, + { true, 0x0ff0, UINT64_C(0x0012000000000000) }, + { true, 0x0eff, UINT64_C(0x0123000000000000) }, + { true, 0xe0fe, UINT64_C(0x1234000000000000) }, + { true, 0x00ad, UINT64_C(0xffff300000000000) }, + { true, 0x0000, UINT64_C(0xffff7fffffffffff) }, + { true, 0x00f0, UINT64_C(0xffff7fffffffffff) }, + { false, 0x5678, UINT64_C(0xffff800000000000) }, + { false, 0x2969, UINT64_C(0xffffffffffeefefe) }, + { false, 0x1221, UINT64_C(0xffffffffffffffff) }, + { false, 0x1221, UINT64_C(0xffffffffffffffff) }, + }; + static const struct + { + uint16_t cbLimit; + uint32_t u32Base; + } s_aValues32[] = + { + { 0xdfdf, UINT32_C(0xefefefef) }, + { 0x0000, UINT32_C(0x00000000) }, + { 0x0001, UINT32_C(0x00000001) }, + { 0x0002, UINT32_C(0x00000012) }, + { 0x0003, UINT32_C(0x00000123) }, + { 0x0004, UINT32_C(0x00001234) }, + { 0x0005, UINT32_C(0x00012345) }, + { 0x0006, UINT32_C(0x00123456) }, + { 0x0007, UINT32_C(0x01234567) }, + { 0x0008, UINT32_C(0x12345678) }, + { 0x0009, UINT32_C(0x80204060) }, + { 0x000a, UINT32_C(0xddeeffaa) }, + { 0x000b, UINT32_C(0xfdecdbca) }, + { 0x000c, UINT32_C(0x6098456b) }, + { 0x000d, UINT32_C(0x98506099) }, + { 0x000e, UINT32_C(0x206950bc) }, + { 0x000f, UINT32_C(0x9740395d) }, + { 0x0334, UINT32_C(0x64a9455e) }, + { 0xb423, UINT32_C(0xd20b6eff) }, + { 0x4955, UINT32_C(0x85296d46) }, + { 0xffff, UINT32_C(0x07000039) }, + { 0xefe1, UINT32_C(0x0007fe00) }, + }; + + BS3TRAPFRAME TrapCtx; + BS3REGCTX Ctx; + BS3REGCTX CtxUdExpected; + BS3REGCTX TmpCtx; + uint8_t abBufLoad[40]; /* Test buffer w/ misalignment test space and some (cbIdtr) extra guard. */ + uint8_t abBufSave[32]; /* For saving the result after loading. */ + uint8_t abBufRestore[24]; /* For restoring sane value (same seg as abBufSave!). */ + uint8_t abExpectedFilled[32]; /* Same as pbExpected, except it's filled with bFiller2 instead of zeros. */ + uint8_t BS3_FAR *pbBufSave; /* Correctly aligned pointer into abBufSave. */ + uint8_t BS3_FAR *pbBufRestore; /* Correctly aligned pointer into abBufRestore. */ + uint8_t const cbIdtr = BS3_MODE_IS_64BIT_CODE(bTestMode) ? 2+8 : 2+4; + uint8_t const cbBaseLoaded = BS3_MODE_IS_64BIT_CODE(bTestMode) ? 8 + : BS3_MODE_IS_16BIT_CODE(bTestMode) == !(pWorker->fFlags & BS3CB2SIDTSGDT_F_OPSIZE) + ? 3 : 4; + bool const f286 = (g_uBs3CpuDetected & BS3CPU_TYPE_MASK) == BS3CPU_80286; + uint8_t const bTop16BitBase = f286 ? 0xff : 0x00; + uint8_t bFiller1; /* For filling abBufLoad. */ + uint8_t bFiller2; /* For filling abBufSave and expectations. */ + int off; + uint8_t BS3_FAR *pbTest; + unsigned i; + + /* make sure they're allocated */ + Bs3MemZero(&Ctx, sizeof(Ctx)); + Bs3MemZero(&CtxUdExpected, sizeof(CtxUdExpected)); + Bs3MemZero(&TmpCtx, sizeof(TmpCtx)); + Bs3MemZero(&TrapCtx, sizeof(TrapCtx)); + Bs3MemZero(abBufSave, sizeof(abBufSave)); + Bs3MemZero(abBufLoad, sizeof(abBufLoad)); + Bs3MemZero(abBufRestore, sizeof(abBufRestore)); + + /* + * Create a context, giving this routine some more stack space. + * - Point the context at our LIDT [xBX] + SIDT [xDI] + LIDT [xSI] + UD2 combo. + * - Point DS/SS:xBX at abBufLoad. + * - Point ES:xDI at abBufSave. + * - Point ES:xSI at abBufRestore. + */ + Bs3RegCtxSaveEx(&Ctx, bTestMode, 256 /*cbExtraStack*/); + Bs3RegCtxSetRipCsFromLnkPtr(&Ctx, pWorker->fpfnWorker); + if (BS3_MODE_IS_16BIT_SYS(bTestMode)) + g_uBs3TrapEipHint = Ctx.rip.u32; + Ctx.rflags.u16 &= ~X86_EFL_IF; + Bs3RegCtxSetGrpSegFromCurPtr(&Ctx, &Ctx.rbx, pWorker->fSs ? &Ctx.ss : &Ctx.ds, abBufLoad); + + pbBufSave = abBufSave; + if ((BS3_FP_OFF(pbBufSave) + 2) & 7) + pbBufSave += 8 - ((BS3_FP_OFF(pbBufSave) + 2) & 7); + Bs3RegCtxSetGrpSegFromCurPtr(&Ctx, &Ctx.rdi, &Ctx.es, pbBufSave); + + pbBufRestore = abBufRestore; + if ((BS3_FP_OFF(pbBufRestore) + 2) & 7) + pbBufRestore += 8 - ((BS3_FP_OFF(pbBufRestore) + 2) & 7); + Bs3RegCtxSetGrpSegFromCurPtr(&Ctx, &Ctx.rsi, &Ctx.es, pbBufRestore); + Bs3MemCpy(pbBufRestore, pbRestore, cbRestore); + + if (!BS3_MODE_IS_RM_OR_V86(bTestMode)) + Bs3RegCtxConvertToRingX(&Ctx, bRing); + + /* For successful SIDT attempts, we'll stop at the UD2. */ + Bs3MemCpy(&CtxUdExpected, &Ctx, sizeof(Ctx)); + CtxUdExpected.rip.u += pWorker->cbInstr; + + /* + * Check that it works at all. + */ + Bs3MemZero(abBufLoad, sizeof(abBufLoad)); + Bs3MemCpy(abBufLoad, pbBufRestore, cbIdtr); + Bs3MemZero(abBufSave, sizeof(abBufSave)); + Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx); + if (bRing != 0) + bs3CpuBasic2_CompareGpCtx(&TrapCtx, &Ctx, 0); + else + { + bs3CpuBasic2_CompareUdCtx(&TrapCtx, &CtxUdExpected); + if (Bs3MemCmp(pbBufSave, pbExpected, cbIdtr * 2) != 0) + Bs3TestFailedF("Mismatch (%s, #1): expected %.*Rhxs, got %.*Rhxs\n", + pWorker->pszDesc, cbIdtr*2, pbExpected, cbIdtr*2, pbBufSave); + } + g_usBs3TestStep++; + + /* Determine two filler bytes that doesn't appear in the previous result or our expectations. */ + bFiller1 = ~0x55; + while ( Bs3MemChr(pbBufSave, bFiller1, cbIdtr) != NULL + || Bs3MemChr(pbRestore, bFiller1, cbRestore) != NULL + || bFiller1 == 0xff) + bFiller1++; + bFiller2 = 0x33; + while ( Bs3MemChr(pbBufSave, bFiller2, cbIdtr) != NULL + || Bs3MemChr(pbRestore, bFiller2, cbRestore) != NULL + || bFiller2 == 0xff + || bFiller2 == bFiller1) + bFiller2++; + Bs3MemSet(abExpectedFilled, bFiller2, sizeof(abExpectedFilled)); + Bs3MemCpy(abExpectedFilled, pbExpected, cbIdtr); + + /* Again with a buffer filled with a byte not occuring in the previous result. */ + Bs3MemSet(abBufLoad, bFiller1, sizeof(abBufLoad)); + Bs3MemCpy(abBufLoad, pbBufRestore, cbIdtr); + Bs3MemSet(abBufSave, bFiller2, sizeof(abBufSave)); + Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx); + if (bRing != 0) + bs3CpuBasic2_CompareGpCtx(&TrapCtx, &Ctx, 0); + else + { + bs3CpuBasic2_CompareUdCtx(&TrapCtx, &CtxUdExpected); + if (Bs3MemCmp(pbBufSave, abExpectedFilled, cbIdtr * 2) != 0) + Bs3TestFailedF("Mismatch (%s, #2): expected %.*Rhxs, got %.*Rhxs\n", + pWorker->pszDesc, cbIdtr*2, abExpectedFilled, cbIdtr*2, pbBufSave); + } + g_usBs3TestStep++; + + /* + * Try loading a bunch of different limit+base value to check what happens, + * especially what happens wrt the top part of the base in 16-bit mode. + */ + if (BS3_MODE_IS_64BIT_CODE(bTestMode)) + { + for (i = 0; i < RT_ELEMENTS(s_aValues64); i++) + { + Bs3MemSet(abBufLoad, bFiller1, sizeof(abBufLoad)); + Bs3MemCpy(&abBufLoad[0], &s_aValues64[i].cbLimit, 2); + Bs3MemCpy(&abBufLoad[2], &s_aValues64[i].u64Base, 8); + Bs3MemSet(abBufSave, bFiller2, sizeof(abBufSave)); + Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx); + if (bRing != 0 || s_aValues64[i].fGP) + bs3CpuBasic2_CompareGpCtx(&TrapCtx, &Ctx, 0); + else + { + bs3CpuBasic2_CompareUdCtx(&TrapCtx, &CtxUdExpected); + if ( Bs3MemCmp(&pbBufSave[0], &s_aValues64[i].cbLimit, 2) != 0 + || Bs3MemCmp(&pbBufSave[2], &s_aValues64[i].u64Base, 8) != 0 + || !ASMMemIsAllU8(&pbBufSave[10], cbIdtr, bFiller2)) + Bs3TestFailedF("Mismatch (%s, #2): expected %04RX16:%016RX64, fillers %#x %#x, got %.*Rhxs\n", + pWorker->pszDesc, s_aValues64[i].cbLimit, s_aValues64[i].u64Base, + bFiller1, bFiller2, cbIdtr*2, pbBufSave); + } + g_usBs3TestStep++; + } + } + else + { + for (i = 0; i < RT_ELEMENTS(s_aValues32); i++) + { + Bs3MemSet(abBufLoad, bFiller1, sizeof(abBufLoad)); + Bs3MemCpy(&abBufLoad[0], &s_aValues32[i].cbLimit, 2); + Bs3MemCpy(&abBufLoad[2], &s_aValues32[i].u32Base, cbBaseLoaded); + Bs3MemSet(abBufSave, bFiller2, sizeof(abBufSave)); + Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx); + if (bRing != 0) + bs3CpuBasic2_CompareGpCtx(&TrapCtx, &Ctx, 0); + else + { + bs3CpuBasic2_CompareUdCtx(&TrapCtx, &CtxUdExpected); + if ( Bs3MemCmp(&pbBufSave[0], &s_aValues32[i].cbLimit, 2) != 0 + || Bs3MemCmp(&pbBufSave[2], &s_aValues32[i].u32Base, cbBaseLoaded) != 0 + || ( cbBaseLoaded != 4 + && pbBufSave[2+3] != bTop16BitBase) + || !ASMMemIsAllU8(&pbBufSave[8], cbIdtr, bFiller2)) + Bs3TestFailedF("Mismatch (%s,#3): loaded %04RX16:%08RX32, fillers %#x %#x%s, got %.*Rhxs\n", + pWorker->pszDesc, s_aValues32[i].cbLimit, s_aValues32[i].u32Base, bFiller1, bFiller2, + f286 ? ", 286" : "", cbIdtr*2, pbBufSave); + } + g_usBs3TestStep++; + } + } + + /* + * Slide the buffer along 8 bytes to cover misalignment. + */ + for (off = 0; off < 8; off++) + { + Bs3RegCtxSetGrpSegFromCurPtr(&Ctx, &Ctx.rbx, pWorker->fSs ? &Ctx.ss : &Ctx.ds, &abBufLoad[off]); + CtxUdExpected.rbx.u = Ctx.rbx.u; + + Bs3MemSet(abBufLoad, bFiller1, sizeof(abBufLoad)); + Bs3MemCpy(&abBufLoad[off], pbBufRestore, cbIdtr); + Bs3MemSet(abBufSave, bFiller2, sizeof(abBufSave)); + Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx); + if (bRing != 0) + bs3CpuBasic2_CompareGpCtx(&TrapCtx, &Ctx, 0); + else + { + bs3CpuBasic2_CompareUdCtx(&TrapCtx, &CtxUdExpected); + if (Bs3MemCmp(pbBufSave, abExpectedFilled, cbIdtr * 2) != 0) + Bs3TestFailedF("Mismatch (%s, #4): expected %.*Rhxs, got %.*Rhxs\n", + pWorker->pszDesc, cbIdtr*2, abExpectedFilled, cbIdtr*2, pbBufSave); + } + g_usBs3TestStep++; + } + Bs3RegCtxSetGrpSegFromCurPtr(&Ctx, &Ctx.rbx, pWorker->fSs ? &Ctx.ss : &Ctx.ds, abBufLoad); + CtxUdExpected.rbx.u = Ctx.rbx.u; + + /* + * Play with the selector limit if the target mode supports limit checking + * We use BS3_SEL_TEST_PAGE_00 for this + */ + if ( !BS3_MODE_IS_RM_OR_V86(bTestMode) + && !BS3_MODE_IS_64BIT_CODE(bTestMode)) + { + uint16_t cbLimit; + uint32_t uFlatBuf = Bs3SelPtrToFlat(abBufLoad); + Bs3GdteTestPage00 = Bs3Gdte_DATA16; + Bs3GdteTestPage00.Gen.u2Dpl = bRing; + Bs3GdteTestPage00.Gen.u16BaseLow = (uint16_t)uFlatBuf; + Bs3GdteTestPage00.Gen.u8BaseHigh1 = (uint8_t)(uFlatBuf >> 16); + Bs3GdteTestPage00.Gen.u8BaseHigh2 = (uint8_t)(uFlatBuf >> 24); + + if (pWorker->fSs) + CtxUdExpected.ss = Ctx.ss = BS3_SEL_TEST_PAGE_00 | bRing; + else + CtxUdExpected.ds = Ctx.ds = BS3_SEL_TEST_PAGE_00 | bRing; + + /* Expand up (normal). */ + for (off = 0; off < 8; off++) + { + CtxUdExpected.rbx.u = Ctx.rbx.u = off; + for (cbLimit = 0; cbLimit < cbIdtr*2; cbLimit++) + { + Bs3GdteTestPage00.Gen.u16LimitLow = cbLimit; + + Bs3MemSet(abBufLoad, bFiller1, sizeof(abBufLoad)); + Bs3MemCpy(&abBufLoad[off], pbBufRestore, cbIdtr); + Bs3MemSet(abBufSave, bFiller2, sizeof(abBufSave)); + Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx); + if (bRing != 0) + bs3CpuBasic2_CompareGpCtx(&TrapCtx, &Ctx, 0); + else if (off + cbIdtr <= cbLimit + 1) + { + bs3CpuBasic2_CompareUdCtx(&TrapCtx, &CtxUdExpected); + if (Bs3MemCmp(pbBufSave, abExpectedFilled, cbIdtr * 2) != 0) + Bs3TestFailedF("Mismatch (%s, #5): expected %.*Rhxs, got %.*Rhxs\n", + pWorker->pszDesc, cbIdtr*2, abExpectedFilled, cbIdtr*2, pbBufSave); + } + else if (pWorker->fSs) + bs3CpuBasic2_CompareSsCtx(&TrapCtx, &Ctx, 0, false /*f486ResumeFlagHint*/); + else + bs3CpuBasic2_CompareGpCtx(&TrapCtx, &Ctx, 0); + g_usBs3TestStep++; + + /* Again with zero limit and messed up base (should trigger tripple fault if partially loaded). */ + abBufLoad[off] = abBufLoad[off + 1] = 0; + abBufLoad[off + 2] |= 1; + abBufLoad[off + cbIdtr - 2] ^= 0x5a; + abBufLoad[off + cbIdtr - 1] ^= 0xa5; + Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx); + if (bRing != 0) + bs3CpuBasic2_CompareGpCtx(&TrapCtx, &Ctx, 0); + else if (off + cbIdtr <= cbLimit + 1) + bs3CpuBasic2_CompareUdCtx(&TrapCtx, &CtxUdExpected); + else if (pWorker->fSs) + bs3CpuBasic2_CompareSsCtx(&TrapCtx, &Ctx, 0, false /*f486ResumeFlagHint*/); + else + bs3CpuBasic2_CompareGpCtx(&TrapCtx, &Ctx, 0); + } + } + + /* Expand down (weird). Inverted valid area compared to expand up, + so a limit of zero give us a valid range for 0001..0ffffh (instead of + a segment with one valid byte at 0000h). Whereas a limit of 0fffeh + means one valid byte at 0ffffh, and a limit of 0ffffh means none + (because in a normal expand up the 0ffffh means all 64KB are + accessible). */ + Bs3GdteTestPage00.Gen.u4Type = X86_SEL_TYPE_RW_DOWN_ACC; + for (off = 0; off < 8; off++) + { + CtxUdExpected.rbx.u = Ctx.rbx.u = off; + for (cbLimit = 0; cbLimit < cbIdtr*2; cbLimit++) + { + Bs3GdteTestPage00.Gen.u16LimitLow = cbLimit; + + Bs3MemSet(abBufLoad, bFiller1, sizeof(abBufLoad)); + Bs3MemCpy(&abBufLoad[off], pbBufRestore, cbIdtr); + Bs3MemSet(abBufSave, bFiller2, sizeof(abBufSave)); + Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx); + if (bRing != 0) + bs3CpuBasic2_CompareGpCtx(&TrapCtx, &Ctx, 0); + else if (off > cbLimit) + { + bs3CpuBasic2_CompareUdCtx(&TrapCtx, &CtxUdExpected); + if (Bs3MemCmp(pbBufSave, abExpectedFilled, cbIdtr * 2) != 0) + Bs3TestFailedF("Mismatch (%s, #6): expected %.*Rhxs, got %.*Rhxs\n", + pWorker->pszDesc, cbIdtr*2, abExpectedFilled, cbIdtr*2, pbBufSave); + } + else if (pWorker->fSs) + bs3CpuBasic2_CompareSsCtx(&TrapCtx, &Ctx, 0, false /*f486ResumeFlagHint*/); + else + bs3CpuBasic2_CompareGpCtx(&TrapCtx, &Ctx, 0); + g_usBs3TestStep++; + + /* Again with zero limit and messed up base (should trigger triple fault if partially loaded). */ + abBufLoad[off] = abBufLoad[off + 1] = 0; + abBufLoad[off + 2] |= 3; + abBufLoad[off + cbIdtr - 2] ^= 0x55; + abBufLoad[off + cbIdtr - 1] ^= 0xaa; + Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx); + if (bRing != 0) + bs3CpuBasic2_CompareGpCtx(&TrapCtx, &Ctx, 0); + else if (off > cbLimit) + bs3CpuBasic2_CompareUdCtx(&TrapCtx, &CtxUdExpected); + else if (pWorker->fSs) + bs3CpuBasic2_CompareSsCtx(&TrapCtx, &Ctx, 0, false /*f486ResumeFlagHint*/); + else + bs3CpuBasic2_CompareGpCtx(&TrapCtx, &Ctx, 0); + } + } + + Bs3RegCtxSetGrpSegFromCurPtr(&Ctx, &Ctx.rbx, pWorker->fSs ? &Ctx.ss : &Ctx.ds, abBufLoad); + CtxUdExpected.rbx.u = Ctx.rbx.u; + CtxUdExpected.ss = Ctx.ss; + CtxUdExpected.ds = Ctx.ds; + } + + /* + * Play with the paging. + */ + if ( BS3_MODE_IS_PAGED(bTestMode) + && (!pWorker->fSs || bRing == 3) /* SS.DPL == CPL, we'll get some tiled ring-3 selector here. */ + && (pbTest = (uint8_t BS3_FAR *)Bs3MemGuardedTestPageAlloc(BS3MEMKIND_TILED)) != NULL) + { + RTCCUINTXREG uFlatTest = Bs3SelPtrToFlat(pbTest); + + /* + * Slide the load buffer towards the trailing guard page. + */ + Bs3RegCtxSetGrpSegFromCurPtr(&Ctx, &Ctx.rbx, pWorker->fSs ? &Ctx.ss : &Ctx.ds, &pbTest[X86_PAGE_SIZE]); + CtxUdExpected.ss = Ctx.ss; + CtxUdExpected.ds = Ctx.ds; + for (off = X86_PAGE_SIZE - cbIdtr - 4; off < X86_PAGE_SIZE + 4; off++) + { + Bs3MemSet(&pbTest[X86_PAGE_SIZE - cbIdtr * 2], bFiller1, cbIdtr*2); + if (off < X86_PAGE_SIZE) + Bs3MemCpy(&pbTest[off], pbBufRestore, RT_MIN(X86_PAGE_SIZE - off, cbIdtr)); + Bs3RegCtxSetGrpSegFromCurPtr(&Ctx, &Ctx.rbx, pWorker->fSs ? &Ctx.ss : &Ctx.ds, &pbTest[off]); + Bs3MemSet(abBufSave, bFiller2, sizeof(abBufSave)); + Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx); + if (bRing != 0) + bs3CpuBasic2_CompareGpCtx(&TrapCtx, &Ctx, 0); + else if (off + cbIdtr <= X86_PAGE_SIZE) + { + CtxUdExpected.rbx = Ctx.rbx; + bs3CpuBasic2_CompareUdCtx(&TrapCtx, &CtxUdExpected); + if (Bs3MemCmp(pbBufSave, abExpectedFilled, cbIdtr*2) != 0) + Bs3TestFailedF("Mismatch (%s, #7): expected %.*Rhxs, got %.*Rhxs\n", + pWorker->pszDesc, cbIdtr*2, abExpectedFilled, cbIdtr*2, pbBufSave); + } + else + bs3CpuBasic2_ComparePfCtx(&TrapCtx, &Ctx, 0, uFlatTest + RT_MAX(off, X86_PAGE_SIZE)); + g_usBs3TestStep++; + + /* Again with zero limit and maybe messed up base as well (triple fault if buggy). + The 386DX-40 here triple faults (or something) with off == 0xffe, nothing else. */ + if ( off < X86_PAGE_SIZE && off + cbIdtr > X86_PAGE_SIZE + && ( off != X86_PAGE_SIZE - 2 + || (g_uBs3CpuDetected & BS3CPU_TYPE_MASK) != BS3CPU_80386) + ) + { + pbTest[off] = 0; + if (off + 1 < X86_PAGE_SIZE) + pbTest[off + 1] = 0; + if (off + 2 < X86_PAGE_SIZE) + pbTest[off + 2] |= 7; + Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx); + if (bRing != 0) + bs3CpuBasic2_CompareGpCtx(&TrapCtx, &Ctx, 0); + else + bs3CpuBasic2_ComparePfCtx(&TrapCtx, &Ctx, 0, uFlatTest + RT_MAX(off, X86_PAGE_SIZE)); + g_usBs3TestStep++; + } + } + + /* + * Now, do it the other way around. It should look normal now since writing + * the limit will #PF first and nothing should be written. + */ + for (off = cbIdtr + 4; off >= -cbIdtr - 4; off--) + { + Bs3MemSet(pbTest, bFiller1, 48); + if (off >= 0) + Bs3MemCpy(&pbTest[off], pbBufRestore, cbIdtr); + else if (off + cbIdtr > 0) + Bs3MemCpy(pbTest, &pbBufRestore[-off], cbIdtr + off); + Bs3RegCtxSetGrpSegFromCurPtr(&Ctx, &Ctx.rbx, pWorker->fSs ? &Ctx.ss : &Ctx.ds, &pbTest[off]); + Bs3MemSet(abBufSave, bFiller2, sizeof(abBufSave)); + Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx); + if (bRing != 0) + bs3CpuBasic2_CompareGpCtx(&TrapCtx, &Ctx, 0); + else if (off >= 0) + { + CtxUdExpected.rbx = Ctx.rbx; + bs3CpuBasic2_CompareUdCtx(&TrapCtx, &CtxUdExpected); + if (Bs3MemCmp(pbBufSave, abExpectedFilled, cbIdtr*2) != 0) + Bs3TestFailedF("Mismatch (%s, #8): expected %.*Rhxs, got %.*Rhxs\n", + pWorker->pszDesc, cbIdtr*2, abExpectedFilled, cbIdtr*2, pbBufSave); + } + else + bs3CpuBasic2_ComparePfCtx(&TrapCtx, &Ctx, 0, uFlatTest + off); + g_usBs3TestStep++; + + /* Again with messed up base as well (triple fault if buggy). */ + if (off < 0 && off > -cbIdtr) + { + if (off + 2 >= 0) + pbTest[off + 2] |= 15; + pbTest[off + cbIdtr - 1] ^= 0xaa; + Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx); + if (bRing != 0) + bs3CpuBasic2_CompareGpCtx(&TrapCtx, &Ctx, 0); + else + bs3CpuBasic2_ComparePfCtx(&TrapCtx, &Ctx, 0, uFlatTest + off); + g_usBs3TestStep++; + } + } + + /* + * Combine paging and segment limit and check ordering. + * This is kind of interesting here since it the instruction seems to + * actually be doing two separate read, just like it's S[IG]DT counterpart. + * + * Note! My 486DX4 does a DWORD limit read when the operand size is 32-bit, + * that's what f486Weirdness deals with. + */ + if ( !BS3_MODE_IS_RM_OR_V86(bTestMode) + && !BS3_MODE_IS_64BIT_CODE(bTestMode)) + { + bool const f486Weirdness = (g_uBs3CpuDetected & BS3CPU_TYPE_MASK) == BS3CPU_80486 + && BS3_MODE_IS_32BIT_CODE(bTestMode) == !(pWorker->fFlags & BS3CB2SIDTSGDT_F_OPSIZE); + uint16_t cbLimit; + + Bs3GdteTestPage00 = Bs3Gdte_DATA16; + Bs3GdteTestPage00.Gen.u2Dpl = bRing; + Bs3GdteTestPage00.Gen.u16BaseLow = (uint16_t)uFlatTest; + Bs3GdteTestPage00.Gen.u8BaseHigh1 = (uint8_t)(uFlatTest >> 16); + Bs3GdteTestPage00.Gen.u8BaseHigh2 = (uint8_t)(uFlatTest >> 24); + + if (pWorker->fSs) + CtxUdExpected.ss = Ctx.ss = BS3_SEL_TEST_PAGE_00 | bRing; + else + CtxUdExpected.ds = Ctx.ds = BS3_SEL_TEST_PAGE_00 | bRing; + + /* Expand up (normal), approaching tail guard page. */ + for (off = X86_PAGE_SIZE - cbIdtr - 4; off < X86_PAGE_SIZE + 4; off++) + { + CtxUdExpected.rbx.u = Ctx.rbx.u = off; + for (cbLimit = X86_PAGE_SIZE - cbIdtr*2; cbLimit < X86_PAGE_SIZE + cbIdtr*2; cbLimit++) + { + Bs3GdteTestPage00.Gen.u16LimitLow = cbLimit; + Bs3MemSet(&pbTest[X86_PAGE_SIZE - cbIdtr * 2], bFiller1, cbIdtr * 2); + if (off < X86_PAGE_SIZE) + Bs3MemCpy(&pbTest[off], pbBufRestore, RT_MIN(cbIdtr, X86_PAGE_SIZE - off)); + Bs3MemSet(abBufSave, bFiller2, sizeof(abBufSave)); + Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx); + if (bRing != 0) + bs3CpuBasic2_CompareGpCtx(&TrapCtx, &Ctx, 0); + else if (off + cbIdtr <= cbLimit + 1) + { + /* No #GP, but maybe #PF. */ + if (off + cbIdtr <= X86_PAGE_SIZE) + { + bs3CpuBasic2_CompareUdCtx(&TrapCtx, &CtxUdExpected); + if (Bs3MemCmp(pbBufSave, abExpectedFilled, cbIdtr * 2) != 0) + Bs3TestFailedF("Mismatch (%s, #9): expected %.*Rhxs, got %.*Rhxs\n", + pWorker->pszDesc, cbIdtr*2, abExpectedFilled, cbIdtr*2, pbBufSave); + } + else + bs3CpuBasic2_ComparePfCtx(&TrapCtx, &Ctx, 0, uFlatTest + RT_MAX(off, X86_PAGE_SIZE)); + } + /* No #GP/#SS on limit, but instead #PF? */ + else if ( !f486Weirdness + ? off < cbLimit && off >= 0xfff + : off + 2 < cbLimit && off >= 0xffd) + bs3CpuBasic2_ComparePfCtx(&TrapCtx, &Ctx, 0, uFlatTest + RT_MAX(off, X86_PAGE_SIZE)); + /* #GP/#SS on limit or base. */ + else if (pWorker->fSs) + bs3CpuBasic2_CompareSsCtx(&TrapCtx, &Ctx, 0, false /*f486ResumeFlagHint*/); + else + bs3CpuBasic2_CompareGpCtx(&TrapCtx, &Ctx, 0); + + g_usBs3TestStep++; + + /* Set DS to 0 and check that we get #GP(0). */ + if (!pWorker->fSs) + { + Ctx.ds = 0; + Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx); + bs3CpuBasic2_CompareGpCtx(&TrapCtx, &Ctx, 0); + Ctx.ds = BS3_SEL_TEST_PAGE_00 | bRing; + g_usBs3TestStep++; + } + } + } + + /* Expand down. */ + pbTest -= X86_PAGE_SIZE; /* Note! we're backing up a page to simplify things */ + uFlatTest -= X86_PAGE_SIZE; + + Bs3GdteTestPage00.Gen.u4Type = X86_SEL_TYPE_RW_DOWN_ACC; + Bs3GdteTestPage00.Gen.u16BaseLow = (uint16_t)uFlatTest; + Bs3GdteTestPage00.Gen.u8BaseHigh1 = (uint8_t)(uFlatTest >> 16); + Bs3GdteTestPage00.Gen.u8BaseHigh2 = (uint8_t)(uFlatTest >> 24); + + for (off = X86_PAGE_SIZE - cbIdtr - 4; off < X86_PAGE_SIZE + 4; off++) + { + CtxUdExpected.rbx.u = Ctx.rbx.u = off; + for (cbLimit = X86_PAGE_SIZE - cbIdtr*2; cbLimit < X86_PAGE_SIZE + cbIdtr*2; cbLimit++) + { + Bs3GdteTestPage00.Gen.u16LimitLow = cbLimit; + Bs3MemSet(&pbTest[X86_PAGE_SIZE], bFiller1, cbIdtr * 2); + if (off >= X86_PAGE_SIZE) + Bs3MemCpy(&pbTest[off], pbBufRestore, cbIdtr); + else if (off > X86_PAGE_SIZE - cbIdtr) + Bs3MemCpy(&pbTest[X86_PAGE_SIZE], &pbBufRestore[X86_PAGE_SIZE - off], cbIdtr - (X86_PAGE_SIZE - off)); + Bs3MemSet(abBufSave, bFiller2, sizeof(abBufSave)); + Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx); + if (bRing != 0) + bs3CpuBasic2_CompareGpCtx(&TrapCtx, &Ctx, 0); + else if (cbLimit < off && off >= X86_PAGE_SIZE) + { + bs3CpuBasic2_CompareUdCtx(&TrapCtx, &CtxUdExpected); + if (Bs3MemCmp(pbBufSave, abExpectedFilled, cbIdtr * 2) != 0) + Bs3TestFailedF("Mismatch (%s, #10): expected %.*Rhxs, got %.*Rhxs\n", + pWorker->pszDesc, cbIdtr*2, abExpectedFilled, cbIdtr*2, pbBufSave); + } + else if (cbLimit < off && off < X86_PAGE_SIZE) + bs3CpuBasic2_ComparePfCtx(&TrapCtx, &Ctx, 0, uFlatTest + off); + else if (pWorker->fSs) + bs3CpuBasic2_CompareSsCtx(&TrapCtx, &Ctx, 0, false /*f486ResumeFlagHint*/); + else + bs3CpuBasic2_CompareGpCtx(&TrapCtx, &Ctx, 0); + g_usBs3TestStep++; + } + } + + pbTest += X86_PAGE_SIZE; + uFlatTest += X86_PAGE_SIZE; + } + + Bs3MemGuardedTestPageFree(pbTest); + } + + /* + * Check non-canonical 64-bit space. + */ + if ( BS3_MODE_IS_64BIT_CODE(bTestMode) + && (pbTest = (uint8_t BS3_FAR *)Bs3PagingSetupCanonicalTraps()) != NULL) + { + /* Make our references relative to the gap. */ + pbTest += g_cbBs3PagingOneCanonicalTrap; + + /* Hit it from below. */ + for (off = -cbIdtr - 8; off < cbIdtr + 8; off++) + { + Ctx.rbx.u = CtxUdExpected.rbx.u = UINT64_C(0x0000800000000000) + off; + Bs3MemSet(&pbTest[-64], bFiller1, 64*2); + Bs3MemCpy(&pbTest[off], pbBufRestore, cbIdtr); + Bs3MemSet(abBufSave, bFiller2, sizeof(abBufSave)); + Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx); + if (off + cbIdtr > 0 || bRing != 0) + bs3CpuBasic2_CompareGpCtx(&TrapCtx, &Ctx, 0); + else + { + bs3CpuBasic2_CompareUdCtx(&TrapCtx, &CtxUdExpected); + if (Bs3MemCmp(pbBufSave, abExpectedFilled, cbIdtr * 2) != 0) + Bs3TestFailedF("Mismatch (%s, #11): expected %.*Rhxs, got %.*Rhxs\n", + pWorker->pszDesc, cbIdtr*2, abExpectedFilled, cbIdtr*2, pbBufSave); + } + } + + /* Hit it from above. */ + for (off = -cbIdtr - 8; off < cbIdtr + 8; off++) + { + Ctx.rbx.u = CtxUdExpected.rbx.u = UINT64_C(0xffff800000000000) + off; + Bs3MemSet(&pbTest[-64], bFiller1, 64*2); + Bs3MemCpy(&pbTest[off], pbBufRestore, cbIdtr); + Bs3MemSet(abBufSave, bFiller2, sizeof(abBufSave)); + Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx); + if (off < 0 || bRing != 0) + bs3CpuBasic2_CompareGpCtx(&TrapCtx, &Ctx, 0); + else + { + bs3CpuBasic2_CompareUdCtx(&TrapCtx, &CtxUdExpected); + if (Bs3MemCmp(pbBufSave, abExpectedFilled, cbIdtr * 2) != 0) + Bs3TestFailedF("Mismatch (%s, #19): expected %.*Rhxs, got %.*Rhxs\n", + pWorker->pszDesc, cbIdtr*2, abExpectedFilled, cbIdtr*2, pbBufSave); + } + } + + } +} + + +static void bs3CpuBasic2_lidt_lgdt_Common(uint8_t bTestMode, BS3CB2SIDTSGDT const BS3_FAR *paWorkers, unsigned cWorkers, + void const *pvRestore, size_t cbRestore, uint8_t const *pbExpected) +{ + unsigned idx; + unsigned bRing; + unsigned iStep = 0; + + /* Note! We skip the SS checks for ring-0 since we badly mess up SS in the + test and don't want to bother with double faults. */ + for (bRing = BS3_MODE_IS_V86(bTestMode) ? 3 : 0; bRing <= 3; bRing++) + { + for (idx = 0; idx < cWorkers; idx++) + if ( (paWorkers[idx].bMode & (bTestMode & BS3_MODE_CODE_MASK)) + && (!paWorkers[idx].fSs || bRing != 0 /** @todo || BS3_MODE_IS_64BIT_SYS(bTestMode)*/ ) + && ( !(paWorkers[idx].fFlags & BS3CB2SIDTSGDT_F_386PLUS) + || ( bTestMode > BS3_MODE_PE16 + || ( bTestMode == BS3_MODE_PE16 + && (g_uBs3CpuDetected & BS3CPU_TYPE_MASK) >= BS3CPU_80386)) ) ) + { + //Bs3TestPrintf("idx=%-2d fpfnWorker=%p fSs=%d cbInstr=%d\n", + // idx, paWorkers[idx].fpfnWorker, paWorkers[idx].fSs, paWorkers[idx].cbInstr); + g_usBs3TestStep = iStep; + bs3CpuBasic2_lidt_lgdt_One(&paWorkers[idx], bTestMode, bRing, pvRestore, cbRestore, pbExpected); + iStep += 1000; + } + if (BS3_MODE_IS_RM_SYS(bTestMode)) + break; + } +} + + +BS3_DECL_FAR(uint8_t) BS3_CMN_FAR_NM(bs3CpuBasic2_lidt)(uint8_t bMode) +{ + union + { + RTIDTR Idtr; + uint8_t ab[32]; /* At least cbIdtr*2! */ + } Expected; + + //if (bMode != BS3_MODE_LM64) return 0; + bs3CpuBasic2_SetGlobals(bMode); + + /* + * Pass to common worker which is only compiled once per mode. + */ + Bs3MemZero(&Expected, sizeof(Expected)); + ASMGetIDTR(&Expected.Idtr); + + if (BS3_MODE_IS_RM_SYS(bMode)) + bs3CpuBasic2_lidt_lgdt_Common(bMode, g_aLidtWorkers, RT_ELEMENTS(g_aLidtWorkers), + &Bs3Lidt_Ivt, sizeof(Bs3Lidt_Ivt), Expected.ab); + else if (BS3_MODE_IS_16BIT_SYS(bMode)) + bs3CpuBasic2_lidt_lgdt_Common(bMode, g_aLidtWorkers, RT_ELEMENTS(g_aLidtWorkers), + &Bs3Lidt_Idt16, sizeof(Bs3Lidt_Idt16), Expected.ab); + else if (BS3_MODE_IS_32BIT_SYS(bMode)) + bs3CpuBasic2_lidt_lgdt_Common(bMode, g_aLidtWorkers, RT_ELEMENTS(g_aLidtWorkers), + &Bs3Lidt_Idt32, sizeof(Bs3Lidt_Idt32), Expected.ab); + else + bs3CpuBasic2_lidt_lgdt_Common(bMode, g_aLidtWorkers, RT_ELEMENTS(g_aLidtWorkers), + &Bs3Lidt_Idt64, sizeof(Bs3Lidt_Idt64), Expected.ab); + + /* + * Re-initialize the IDT. + */ + Bs3TrapReInit(); + return 0; +} + + +BS3_DECL_FAR(uint8_t) BS3_CMN_FAR_NM(bs3CpuBasic2_lgdt)(uint8_t bMode) +{ + union + { + RTGDTR Gdtr; + uint8_t ab[32]; /* At least cbIdtr*2! */ + } Expected; + + //if (!BS3_MODE_IS_64BIT_SYS(bMode)) return 0; + bs3CpuBasic2_SetGlobals(bMode); + + /* + * Pass to common worker which is only compiled once per mode. + */ + if (BS3_MODE_IS_RM_SYS(bMode)) + ASMSetGDTR((PRTGDTR)&Bs3LgdtDef_Gdt); + Bs3MemZero(&Expected, sizeof(Expected)); + ASMGetGDTR(&Expected.Gdtr); + + bs3CpuBasic2_lidt_lgdt_Common(bMode, g_aLgdtWorkers, RT_ELEMENTS(g_aLgdtWorkers), + &Bs3LgdtDef_Gdt, sizeof(Bs3LgdtDef_Gdt), Expected.ab); + + /* + * Re-initialize the IDT. + */ + Bs3TrapReInit(); + return 0; +} + +typedef union IRETBUF +{ + uint64_t au64[6]; /* max req is 5 */ + uint32_t au32[12]; /* max req is 9 */ + uint16_t au16[24]; /* max req is 5 */ + uint8_t ab[48]; +} IRETBUF; +typedef IRETBUF BS3_FAR *PIRETBUF; + + +static void iretbuf_SetupFrame(PIRETBUF pIretBuf, unsigned const cbPop, + uint16_t uCS, uint64_t uPC, uint32_t fEfl, uint16_t uSS, uint64_t uSP) +{ + if (cbPop == 2) + { + pIretBuf->au16[0] = (uint16_t)uPC; + pIretBuf->au16[1] = uCS; + pIretBuf->au16[2] = (uint16_t)fEfl; + pIretBuf->au16[3] = (uint16_t)uSP; + pIretBuf->au16[4] = uSS; + } + else if (cbPop != 8) + { + pIretBuf->au32[0] = (uint32_t)uPC; + pIretBuf->au16[1*2] = uCS; + pIretBuf->au32[2] = (uint32_t)fEfl; + pIretBuf->au32[3] = (uint32_t)uSP; + pIretBuf->au16[4*2] = uSS; + } + else + { + pIretBuf->au64[0] = uPC; + pIretBuf->au16[1*4] = uCS; + pIretBuf->au64[2] = fEfl; + pIretBuf->au64[3] = uSP; + pIretBuf->au16[4*4] = uSS; + } +} + +uint32_t ASMGetESP(void); +#pragma aux ASMGetESP = \ + ".386" \ + "mov ax, sp" \ + "mov edx, esp" \ + "shr edx, 16" \ + value [ax dx] \ + modify exact [ax dx]; + + +static void bs3CpuBasic2_iret_Worker(uint8_t bTestMode, FPFNBS3FAR pfnIret, unsigned const cbPop, + PIRETBUF pIretBuf, const char BS3_FAR *pszDesc) +{ + BS3TRAPFRAME TrapCtx; + BS3REGCTX Ctx; + BS3REGCTX CtxUdExpected; + BS3REGCTX TmpCtx; + BS3REGCTX TmpCtxExpected; + uint8_t abLowUd[8]; + uint8_t abLowIret[8]; + FPFNBS3FAR pfnUdLow = (FPFNBS3FAR)abLowUd; + FPFNBS3FAR pfnIretLow = (FPFNBS3FAR)abLowIret; + unsigned const cbSameCplFrame = BS3_MODE_IS_64BIT_CODE(bTestMode) ? 5*cbPop : 3*cbPop; + bool const fUseLowCode = cbPop == 2 && !BS3_MODE_IS_16BIT_CODE(bTestMode); + int iRingDst; + int iRingSrc; + uint16_t uDplSs; + uint16_t uRplCs; + uint16_t uRplSs; +// int i; + uint8_t BS3_FAR *pbTest; + + NOREF(abLowUd); +#define IRETBUF_SET_SEL(a_idx, a_uValue) \ + do { *(uint16_t)&pIretBuf->ab[a_idx * cbPop] = (a_uValue); } while (0) +#define IRETBUF_SET_REG(a_idx, a_uValue) \ + do { uint8_t const BS3_FAR *pbTmp = &pIretBuf->ab[a_idx * cbPop]; \ + if (cbPop == 2) *(uint16_t)pbTmp = (uint16_t)(a_uValue); \ + else if (cbPop != 8) *(uint32_t)pbTmp = (uint32_t)(a_uValue); \ + else *(uint64_t)pbTmp = (a_uValue); \ + } while (0) + + /* make sure they're allocated */ + Bs3MemZero(&Ctx, sizeof(Ctx)); + Bs3MemZero(&CtxUdExpected, sizeof(CtxUdExpected)); + Bs3MemZero(&TmpCtx, sizeof(TmpCtx)); + Bs3MemZero(&TmpCtxExpected, sizeof(TmpCtxExpected)); + Bs3MemZero(&TrapCtx, sizeof(TrapCtx)); + + /* + * When dealing with 16-bit irets in 32-bit or 64-bit mode, we must have + * copies of both iret and ud in the first 64KB of memory. The stack is + * below 64KB, so we'll just copy the instructions onto the stack. + */ + Bs3MemCpy(abLowUd, bs3CpuBasic2_ud2, 4); + Bs3MemCpy(abLowIret, pfnIret, 4); + + /* + * Create a context (stack is irrelevant, we'll mainly be using pIretBuf). + * - Point the context at our iret instruction. + * - Point SS:xSP at pIretBuf. + */ + Bs3RegCtxSaveEx(&Ctx, bTestMode, 0); + if (!fUseLowCode) + Bs3RegCtxSetRipCsFromLnkPtr(&Ctx, pfnIret); + else + Bs3RegCtxSetRipCsFromCurPtr(&Ctx, pfnIretLow); + if (BS3_MODE_IS_16BIT_SYS(bTestMode)) + g_uBs3TrapEipHint = Ctx.rip.u32; + Bs3RegCtxSetGrpSegFromCurPtr(&Ctx, &Ctx.rsp, &Ctx.ss, pIretBuf); + + /* + * The first success (UD) context keeps the same code bit-count as the iret. + */ + Bs3MemCpy(&CtxUdExpected, &Ctx, sizeof(Ctx)); + if (!fUseLowCode) + Bs3RegCtxSetRipCsFromLnkPtr(&CtxUdExpected, bs3CpuBasic2_ud2); + else + Bs3RegCtxSetRipCsFromCurPtr(&CtxUdExpected, pfnUdLow); + CtxUdExpected.rsp.u += cbSameCplFrame; + + /* + * Check that it works at all. + */ + iretbuf_SetupFrame(pIretBuf, cbPop, CtxUdExpected.cs, CtxUdExpected.rip.u, + CtxUdExpected.rflags.u32, CtxUdExpected.ss, CtxUdExpected.rsp.u); + + Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx); + bs3CpuBasic2_CompareUdCtx(&TrapCtx, &CtxUdExpected); + g_usBs3TestStep++; + + if (!BS3_MODE_IS_RM_OR_V86(bTestMode)) + { + /* Selectors are modified when switching rings, so we need to know + what we're dealing with there. */ + if ( !BS3_SEL_IS_IN_R0_RANGE(Ctx.cs) || !BS3_SEL_IS_IN_R0_RANGE(Ctx.ss) + || !BS3_SEL_IS_IN_R0_RANGE(Ctx.ds) || !BS3_SEL_IS_IN_R0_RANGE(Ctx.es)) + Bs3TestFailedF("Expected R0 CS, SS, DS and ES; not %#x, %#x, %#x and %#x\n", Ctx.cs, Ctx.ss, Ctx.ds, Ctx.es); + if (Ctx.fs || Ctx.gs) + Bs3TestFailed("Expected R0 FS and GS to be 0!\n"); + + /* + * Test returning to outer rings if protected mode. + */ + Bs3MemCpy(&TmpCtx, &Ctx, sizeof(TmpCtx)); + Bs3MemCpy(&TmpCtxExpected, &CtxUdExpected, sizeof(TmpCtxExpected)); + for (iRingDst = 3; iRingDst >= 0; iRingDst--) + { + Bs3RegCtxConvertToRingX(&TmpCtxExpected, iRingDst); + TmpCtxExpected.ds = iRingDst ? 0 : TmpCtx.ds; + TmpCtx.es = TmpCtxExpected.es; + iretbuf_SetupFrame(pIretBuf, cbPop, TmpCtxExpected.cs, TmpCtxExpected.rip.u, + TmpCtxExpected.rflags.u32, TmpCtxExpected.ss, TmpCtxExpected.rsp.u); + Bs3TrapSetJmpAndRestore(&TmpCtx, &TrapCtx); + bs3CpuBasic2_CompareUdCtx(&TrapCtx, &TmpCtxExpected); + g_usBs3TestStep++; + } + + /* + * Check CS.RPL and SS.RPL. + */ + for (iRingDst = 3; iRingDst >= 0; iRingDst--) + { + uint16_t const uDstSsR0 = (CtxUdExpected.ss & BS3_SEL_RING_SUB_MASK) + BS3_SEL_R0_FIRST; + Bs3MemCpy(&TmpCtxExpected, &CtxUdExpected, sizeof(TmpCtxExpected)); + Bs3RegCtxConvertToRingX(&TmpCtxExpected, iRingDst); + for (iRingSrc = 3; iRingSrc >= 0; iRingSrc--) + { + Bs3MemCpy(&TmpCtx, &Ctx, sizeof(TmpCtx)); + Bs3RegCtxConvertToRingX(&TmpCtx, iRingSrc); + TmpCtx.es = TmpCtxExpected.es; + TmpCtxExpected.ds = iRingDst != iRingSrc ? 0 : TmpCtx.ds; + for (uRplCs = 0; uRplCs <= 3; uRplCs++) + { + uint16_t const uSrcEs = TmpCtx.es; + uint16_t const uDstCs = (TmpCtxExpected.cs & X86_SEL_MASK_OFF_RPL) | uRplCs; + //Bs3TestPrintf("dst=%d src=%d rplCS=%d\n", iRingDst, iRingSrc, uRplCs); + + /* CS.RPL */ + iretbuf_SetupFrame(pIretBuf, cbPop, uDstCs, TmpCtxExpected.rip.u, TmpCtxExpected.rflags.u32, + TmpCtxExpected.ss, TmpCtxExpected.rsp.u); + Bs3TrapSetJmpAndRestore(&TmpCtx, &TrapCtx); + if (uRplCs == iRingDst && iRingDst >= iRingSrc) + bs3CpuBasic2_CompareUdCtx(&TrapCtx, &TmpCtxExpected); + else + { + if (iRingDst < iRingSrc) + TmpCtx.es = 0; + bs3CpuBasic2_CompareGpCtx(&TrapCtx, &TmpCtx, uDstCs & X86_SEL_MASK_OFF_RPL); + TmpCtx.es = uSrcEs; + } + g_usBs3TestStep++; + + /* SS.RPL */ + if (iRingDst != iRingSrc || BS3_MODE_IS_64BIT_CODE(bTestMode)) + { + uint16_t uSavedDstSs = TmpCtxExpected.ss; + for (uRplSs = 0; uRplSs <= 3; uRplSs++) + { + /* SS.DPL (iRingDst == CS.DPL) */ + for (uDplSs = 0; uDplSs <= 3; uDplSs++) + { + uint16_t const uDstSs = ((uDplSs << BS3_SEL_RING_SHIFT) | uRplSs) + uDstSsR0; + //Bs3TestPrintf("dst=%d src=%d rplCS=%d rplSS=%d dplSS=%d dst %04x:%08RX64 %08RX32 %04x:%08RX64\n", + // iRingDst, iRingSrc, uRplCs, uRplSs, uDplSs, uDstCs, TmpCtxExpected.rip.u, + // TmpCtxExpected.rflags.u32, uDstSs, TmpCtxExpected.rsp.u); + + iretbuf_SetupFrame(pIretBuf, cbPop, uDstCs, TmpCtxExpected.rip.u, + TmpCtxExpected.rflags.u32, uDstSs, TmpCtxExpected.rsp.u); + Bs3TrapSetJmpAndRestore(&TmpCtx, &TrapCtx); + if (uRplCs != iRingDst || iRingDst < iRingSrc) + { + if (iRingDst < iRingSrc) + TmpCtx.es = 0; + bs3CpuBasic2_CompareGpCtx(&TrapCtx, &TmpCtx, uDstCs & X86_SEL_MASK_OFF_RPL); + } + else if (uRplSs != iRingDst || uDplSs != iRingDst) + bs3CpuBasic2_CompareGpCtx(&TrapCtx, &TmpCtx, uDstSs & X86_SEL_MASK_OFF_RPL); + else + bs3CpuBasic2_CompareUdCtx(&TrapCtx, &TmpCtxExpected); + TmpCtx.es = uSrcEs; + g_usBs3TestStep++; + } + } + + TmpCtxExpected.ss = uSavedDstSs; + } + } + } + } + } + + /* + * Special 64-bit checks. + */ + if (BS3_MODE_IS_64BIT_CODE(bTestMode)) + { + /* The VM flag is completely ignored. */ + iretbuf_SetupFrame(pIretBuf, cbPop, CtxUdExpected.cs, CtxUdExpected.rip.u, + CtxUdExpected.rflags.u32 | X86_EFL_VM, CtxUdExpected.ss, CtxUdExpected.rsp.u); + Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx); + bs3CpuBasic2_CompareUdCtx(&TrapCtx, &CtxUdExpected); + g_usBs3TestStep++; + + /* The NT flag can be loaded just fine. */ + CtxUdExpected.rflags.u32 |= X86_EFL_NT; + iretbuf_SetupFrame(pIretBuf, cbPop, CtxUdExpected.cs, CtxUdExpected.rip.u, + CtxUdExpected.rflags.u32, CtxUdExpected.ss, CtxUdExpected.rsp.u); + Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx); + bs3CpuBasic2_CompareUdCtx(&TrapCtx, &CtxUdExpected); + CtxUdExpected.rflags.u32 &= ~X86_EFL_NT; + g_usBs3TestStep++; + + /* However, we'll #GP(0) if it's already set (in RFLAGS) when executing IRET. */ + Ctx.rflags.u32 |= X86_EFL_NT; + iretbuf_SetupFrame(pIretBuf, cbPop, CtxUdExpected.cs, CtxUdExpected.rip.u, + CtxUdExpected.rflags.u32, CtxUdExpected.ss, CtxUdExpected.rsp.u); + Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx); + bs3CpuBasic2_CompareGpCtx(&TrapCtx, &Ctx, 0); + g_usBs3TestStep++; + + /* The NT flag #GP(0) should trump all other exceptions - pit it against #PF. */ + pbTest = (uint8_t BS3_FAR *)Bs3MemGuardedTestPageAlloc(BS3MEMKIND_TILED); + if (pbTest != NULL) + { + Bs3RegCtxSetGrpSegFromCurPtr(&Ctx, &Ctx.rsp, &Ctx.ss, &pbTest[X86_PAGE_SIZE]); + iretbuf_SetupFrame(pIretBuf, cbPop, CtxUdExpected.cs, CtxUdExpected.rip.u, + CtxUdExpected.rflags.u32, CtxUdExpected.ss, CtxUdExpected.rsp.u); + Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx); + bs3CpuBasic2_CompareGpCtx(&TrapCtx, &Ctx, 0); + g_usBs3TestStep++; + + Bs3RegCtxSetGrpSegFromCurPtr(&Ctx, &Ctx.rsp, &Ctx.ss, pIretBuf); + Bs3MemGuardedTestPageFree(pbTest); + } + Ctx.rflags.u32 &= ~X86_EFL_NT; + } +} + + +BS3_DECL_FAR(uint8_t) BS3_CMN_FAR_NM(bs3CpuBasic2_iret)(uint8_t bMode) +{ + struct + { + uint8_t abExtraStack[4096]; /**< we've got ~30KB of stack, so 4KB for the trap handlers++ is not a problem. */ + IRETBUF IRetBuf; + uint8_t abGuard[32]; + } uBuf; + size_t cbUnused; + + //if (bMode != BS3_MODE_LM64) return BS3TESTDOMODE_SKIPPED; + bs3CpuBasic2_SetGlobals(bMode); + + /* + * Primary instruction form. + */ + Bs3MemSet(&uBuf, 0xaa, sizeof(uBuf)); + Bs3MemSet(uBuf.abGuard, 0x88, sizeof(uBuf.abGuard)); + if (BS3_MODE_IS_16BIT_CODE(bMode)) + bs3CpuBasic2_iret_Worker(bMode, bs3CpuBasic2_iret, 2, &uBuf.IRetBuf, "iret"); + else if (BS3_MODE_IS_32BIT_CODE(bMode)) + bs3CpuBasic2_iret_Worker(bMode, bs3CpuBasic2_iret, 4, &uBuf.IRetBuf, "iretd"); + else + bs3CpuBasic2_iret_Worker(bMode, bs3CpuBasic2_iret_rexw, 8, &uBuf.IRetBuf, "o64 iret"); + + BS3_ASSERT(ASMMemIsAllU8(uBuf.abGuard, sizeof(uBuf.abGuard), 0x88)); + cbUnused = (uintptr_t)ASMMemFirstMismatchingU8(uBuf.abExtraStack, sizeof(uBuf.abExtraStack) + sizeof(uBuf.IRetBuf), 0xaa) + - (uintptr_t)uBuf.abExtraStack; + if (cbUnused < 2048) + Bs3TestFailedF("cbUnused=%u #%u\n", cbUnused, 1); + + /* + * Secondary variation: opsize prefixed. + */ + Bs3MemSet(&uBuf, 0xaa, sizeof(uBuf)); + Bs3MemSet(uBuf.abGuard, 0x88, sizeof(uBuf.abGuard)); + if (BS3_MODE_IS_16BIT_CODE(bMode) && (g_uBs3CpuDetected & BS3CPU_TYPE_MASK) >= BS3CPU_80386) + bs3CpuBasic2_iret_Worker(bMode, bs3CpuBasic2_iret_opsize, 4, &uBuf.IRetBuf, "o32 iret"); + else if (BS3_MODE_IS_32BIT_CODE(bMode)) + bs3CpuBasic2_iret_Worker(bMode, bs3CpuBasic2_iret_opsize, 2, &uBuf.IRetBuf, "o16 iret"); + else if (BS3_MODE_IS_64BIT_CODE(bMode)) + bs3CpuBasic2_iret_Worker(bMode, bs3CpuBasic2_iret, 4, &uBuf.IRetBuf, "iretd"); + BS3_ASSERT(ASMMemIsAllU8(uBuf.abGuard, sizeof(uBuf.abGuard), 0x88)); + cbUnused = (uintptr_t)ASMMemFirstMismatchingU8(uBuf.abExtraStack, sizeof(uBuf.abExtraStack) + sizeof(uBuf.IRetBuf), 0xaa) + - (uintptr_t)uBuf.abExtraStack; + if (cbUnused < 2048) + Bs3TestFailedF("cbUnused=%u #%u\n", cbUnused, 2); + + /* + * Third variation: 16-bit in 64-bit mode (truly unlikely) + */ + if (BS3_MODE_IS_64BIT_CODE(bMode)) + { + Bs3MemSet(&uBuf, 0xaa, sizeof(uBuf)); + Bs3MemSet(uBuf.abGuard, 0x88, sizeof(uBuf.abGuard)); + bs3CpuBasic2_iret_Worker(bMode, bs3CpuBasic2_iret_opsize, 2, &uBuf.IRetBuf, "o16 iret"); + BS3_ASSERT(ASMMemIsAllU8(uBuf.abGuard, sizeof(uBuf.abGuard), 0x88)); + cbUnused = (uintptr_t)ASMMemFirstMismatchingU8(uBuf.abExtraStack, sizeof(uBuf.abExtraStack) + sizeof(uBuf.IRetBuf), 0xaa) + - (uintptr_t)uBuf.abExtraStack; + if (cbUnused < 2048) + Bs3TestFailedF("cbUnused=%u #%u\n", cbUnused, 3); + } + + return 0; +} + diff --git a/src/VBox/ValidationKit/bootsectors/bs3-cpu-basic-2.c b/src/VBox/ValidationKit/bootsectors/bs3-cpu-basic-2.c new file mode 100644 index 00000000..242d3377 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3-cpu-basic-2.c @@ -0,0 +1,92 @@ +/* $Id: bs3-cpu-basic-2.c $ */ +/** @file + * BS3Kit - bs3-cpu-basic-2, 16-bit C code. + */ + +/* + * Copyright (C) 2007-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include <bs3kit.h> +#include <iprt/asm-amd64-x86.h> + + +/********************************************************************************************************************************* +* Internal Functions * +*********************************************************************************************************************************/ +BS3TESTMODE_PROTOTYPES_MODE(bs3CpuBasic2_TssGateEsp); +BS3TESTMODE_PROTOTYPES_MODE(bs3CpuBasic2_RaiseXcpt1); + +FNBS3TESTDOMODE bs3CpuBasic2_sidt_f16; +FNBS3TESTDOMODE bs3CpuBasic2_sgdt_f16; +FNBS3TESTDOMODE bs3CpuBasic2_lidt_f16; +FNBS3TESTDOMODE bs3CpuBasic2_lgdt_f16; +FNBS3TESTDOMODE bs3CpuBasic2_iret_f16; + +BS3_DECL_CALLBACK(void) bs3CpuBasic2_Do32BitTests_pe32(); + + +/********************************************************************************************************************************* +* Global Variables * +*********************************************************************************************************************************/ +static const BS3TESTMODEENTRY g_aModeTest[] = +{ + BS3TESTMODEENTRY_MODE("tss / gate / esp", bs3CpuBasic2_TssGateEsp), + //BS3TESTMODEENTRY_MODE("raise xcpt #1", bs3CpuBasic2_RaiseXcpt1), // !long mode is broken! +}; + +static const BS3TESTMODEBYONEENTRY g_aModeByOneTests[] = +{ + { "iret", bs3CpuBasic2_iret_f16, 0 }, + { "sidt", bs3CpuBasic2_sidt_f16, 0 }, + { "sgdt", bs3CpuBasic2_sgdt_f16, 0 }, + { "lidt", bs3CpuBasic2_lidt_f16, 0 }, + { "lgdt", bs3CpuBasic2_lgdt_f16, 0 }, +}; + + +BS3_DECL(void) Main_rm() +{ + Bs3InitAll_rm(); + Bs3TestInit("bs3-cpu-basic-2"); + Bs3TestPrintf("g_uBs3CpuDetected=%#x\n", g_uBs3CpuDetected); + + /* + * Do tests driven from 16-bit code. + */ + NOREF(g_aModeTest); NOREF(g_aModeByOneTests); /* for when commenting out bits */ +#if 0 + Bs3TestDoModes_rm(g_aModeTest, RT_ELEMENTS(g_aModeTest)); + Bs3TestDoModesByOne_rm(g_aModeByOneTests, RT_ELEMENTS(g_aModeByOneTests), 0); +#endif + + /* + * Do tests driven from 32-bit code (bs3-cpu-basic-2-32.c32 via assembly). + */ + Bs3SwitchTo32BitAndCallC_rm(bs3CpuBasic2_Do32BitTests_pe32, 0); + + Bs3TestTerm(); +//for (;;) { ASMHalt(); } +} + diff --git a/src/VBox/ValidationKit/bootsectors/bs3-cpu-decoding-1-asm.asm b/src/VBox/ValidationKit/bootsectors/bs3-cpu-decoding-1-asm.asm new file mode 100644 index 00000000..19d62ad8 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3-cpu-decoding-1-asm.asm @@ -0,0 +1,39 @@ +; $Id: bs3-cpu-decoding-1-asm.asm $ +;; @file +; BS3Kit - bs3-cpu-decoding-1, assembly helpers and template instantiation. +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + + +;********************************************************************************************************************************* +;* Header Files * +;********************************************************************************************************************************* +%include "bs3kit.mac" + + +; +; Instantiate code templates. +; +BS3_INSTANTIATE_TEMPLATE_ESSENTIALS "bs3-cpu-decoding-1-template.mac" +BS3_INSTANTIATE_COMMON_TEMPLATE "bs3-cpu-decoding-1-template.mac" + diff --git a/src/VBox/ValidationKit/bootsectors/bs3-cpu-decoding-1-template.c b/src/VBox/ValidationKit/bootsectors/bs3-cpu-decoding-1-template.c new file mode 100644 index 00000000..f5d47641 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3-cpu-decoding-1-template.c @@ -0,0 +1,58 @@ +/* $Id: bs3-cpu-decoding-1-template.c $ */ +/** @file + * BS3Kit - bs3-cpu-decoding-1, C code template. + */ + +/* + * Copyright (C) 2007-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include <iprt/asm.h> +#include <iprt/asm-amd64-x86.h> +#include <VBox/VMMDevTesting.h> + + +/********************************************************************************************************************************* +* Defined Constants And Macros * +*********************************************************************************************************************************/ + +/* + * Common code. + * Common code. + * Common code. + */ +#ifdef BS3_INSTANTIATING_CMN + +#endif /* BS3_INSTANTIATING_CMN */ + + +/* + * Mode specific code. + * Mode specific code. + * Mode specific code. + */ +#ifdef BS3_INSTANTIATING_MODE + +#endif /* BS3_INSTANTIATING_MODE */ + diff --git a/src/VBox/ValidationKit/bootsectors/bs3-cpu-decoding-1-template.mac b/src/VBox/ValidationKit/bootsectors/bs3-cpu-decoding-1-template.mac new file mode 100644 index 00000000..74ea1e6a --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3-cpu-decoding-1-template.mac @@ -0,0 +1,114 @@ +; $Id: bs3-cpu-decoding-1-template.mac $ +;; @file +; BS3Kit - bs3-cpu-decoding-1, assembly template. +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + + +;********************************************************************************************************************************* +;* Header Files * +;********************************************************************************************************************************* +%include "bs3kit-template-header.mac" ; setup environment + + +;********************************************************************************************************************************* +;* External Symbols * +;********************************************************************************************************************************* +TMPL_BEGIN_TEXT + + +%ifdef BS3_INSTANTIATING_CMN + +BS3_PROC_BEGIN_CMN bs3CpuDecoding1_LoadXmm0, BS3_PBC_NEAR + BS3_CALL_CONV_PROLOG 1 + push xBP + mov xBP, xSP + +%if TMPL_BITS == 16 + push es + push bx + les bx, [xBP + xCB + cbCurRetAddr] + movupd xmm0, [es:bx] + pop bx + pop es +%else + mov xAX, [xBP + xCB + cbCurRetAddr] + movupd xmm0, [xAX] +%endif + + leave + BS3_CALL_CONV_EPILOG 1 + BS3_HYBRID_RET +BS3_PROC_END_CMN bs3CpuDecoding1_LoadXmm0 + + +BS3_PROC_BEGIN_CMN bs3CpuDecoding1_LoadXmm1, BS3_PBC_NEAR + BS3_CALL_CONV_PROLOG 1 + push xBP + mov xBP, xSP + +%if TMPL_BITS == 16 + push es + push bx + les bx, [xBP + xCB + cbCurRetAddr] + movupd xmm1, [es:bx] + pop bx + pop es +%else + mov xAX, [xBP + xCB + cbCurRetAddr] + movupd xmm1, [xAX] +%endif + + leave + BS3_CALL_CONV_EPILOG 1 + BS3_HYBRID_RET +BS3_PROC_END_CMN bs3CpuDecoding1_LoadXmm1 + + +BS3_PROC_BEGIN_CMN bs3CpuDecoding1_SaveXmm0, BS3_PBC_NEAR + BS3_CALL_CONV_PROLOG 1 + push xBP + mov xBP, xSP + +%if TMPL_BITS == 16 + push es + push bx + les bx, [xBP + xCB + cbCurRetAddr] + movupd [es:bx], xmm0 + pop bx + pop es +%else + mov xAX, [xBP + xCB + cbCurRetAddr] + movupd [xAX], xmm0 +%endif + + leave + BS3_CALL_CONV_EPILOG 1 + BS3_HYBRID_RET +BS3_PROC_END_CMN bs3CpuDecoding1_SaveXmm0 + + +%endif + +%include "bs3kit-template-footer.mac" ; reset environment + diff --git a/src/VBox/ValidationKit/bootsectors/bs3-cpu-decoding-1.c32 b/src/VBox/ValidationKit/bootsectors/bs3-cpu-decoding-1.c32 new file mode 100644 index 00000000..27ec128a --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3-cpu-decoding-1.c32 @@ -0,0 +1,1726 @@ +/* $Id: bs3-cpu-decoding-1.c32 $ */ +/** @file + * BS3Kit - bs3-cpu-decoding-1, 32-bit C code. + */ + +/* + * Copyright (C) 2007-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include <bs3kit.h> +#include <iprt/asm-amd64-x86.h> + + +/* bs3-cpu-decoding-1-template.mac: */ +BS3_DECL_NEAR(void) BS3_CMN_NM(bs3CpuDecoding1_LoadXmm0)(PCRTUINT128U); +BS3_DECL_NEAR(void) BS3_CMN_NM(bs3CpuDecoding1_LoadXmm1)(PCRTUINT128U); +BS3_DECL_NEAR(void) BS3_CMN_NM(bs3CpuDecoding1_SaveXmm0)(PRTUINT128U); + + +/********************************************************************************************************************************* +* Structures and Typedefs * +*********************************************************************************************************************************/ +/** + * Simple test. + */ +typedef struct CPUDECODE1TST +{ + uint16_t fFlags; + uint8_t cbOpcodes; + uint8_t abOpcodes[20]; + uint8_t cbUd; +} CPUDECODE1TST; +typedef CPUDECODE1TST BS3_FAR *PCPUDECODE1TST; + +#define P_CS X86_OP_PRF_CS +#define P_SS X86_OP_PRF_SS +#define P_DS X86_OP_PRF_DS +#define P_ES X86_OP_PRF_ES +#define P_FS X86_OP_PRF_FS +#define P_GS X86_OP_PRF_GS +#define P_OZ X86_OP_PRF_SIZE_OP +#define P_AZ X86_OP_PRF_SIZE_ADDR +#define P_LK X86_OP_PRF_LOCK +#define P_RN X86_OP_PRF_REPNZ +#define P_RZ X86_OP_PRF_REPZ + +#define RM_EAX_EAX ((3 << X86_MODRM_MOD_SHIFT) | (X86_GREG_xAX << X86_MODRM_REG_SHIFT) | (X86_GREG_xAX)) +#define RM_ECX_EAX ((3 << X86_MODRM_MOD_SHIFT) | (X86_GREG_xCX << X86_MODRM_REG_SHIFT) | (X86_GREG_xAX)) +#define RM_EDX_EAX ((3 << X86_MODRM_MOD_SHIFT) | (X86_GREG_xDX << X86_MODRM_REG_SHIFT) | (X86_GREG_xAX)) +#define RM_EBX_EAX ((3 << X86_MODRM_MOD_SHIFT) | (X86_GREG_xBX << X86_MODRM_REG_SHIFT) | (X86_GREG_xAX)) +#define RM_ESP_EAX ((3 << X86_MODRM_MOD_SHIFT) | (X86_GREG_xSP << X86_MODRM_REG_SHIFT) | (X86_GREG_xAX)) +#define RM_EBP_EAX ((3 << X86_MODRM_MOD_SHIFT) | (X86_GREG_xBP << X86_MODRM_REG_SHIFT) | (X86_GREG_xAX)) +#define RM_ESI_EAX ((3 << X86_MODRM_MOD_SHIFT) | (X86_GREG_xSI << X86_MODRM_REG_SHIFT) | (X86_GREG_xAX)) +#define RM_EDI_EAX ((3 << X86_MODRM_MOD_SHIFT) | (X86_GREG_xDI << X86_MODRM_REG_SHIFT) | (X86_GREG_xAX)) + +#define RM_EAX_DEREF_EBX ((0 << X86_MODRM_MOD_SHIFT) | (X86_GREG_xAX << X86_MODRM_REG_SHIFT) | (X86_GREG_xBX)) +#define RM_ECX_DEREF_EBX ((0 << X86_MODRM_MOD_SHIFT) | (X86_GREG_xCX << X86_MODRM_REG_SHIFT) | (X86_GREG_xBX)) +#define RM_EDX_DEREF_EBX ((0 << X86_MODRM_MOD_SHIFT) | (X86_GREG_xDX << X86_MODRM_REG_SHIFT) | (X86_GREG_xBX)) +#define RM_EBX_DEREF_EBX ((0 << X86_MODRM_MOD_SHIFT) | (X86_GREG_xBX << X86_MODRM_REG_SHIFT) | (X86_GREG_xBX)) +#define RM_ESP_DEREF_EBX ((0 << X86_MODRM_MOD_SHIFT) | (X86_GREG_xSP << X86_MODRM_REG_SHIFT) | (X86_GREG_xBX)) +#define RM_EBP_DEREF_EBX ((0 << X86_MODRM_MOD_SHIFT) | (X86_GREG_xBP << X86_MODRM_REG_SHIFT) | (X86_GREG_xBX)) +#define RM_ESI_DEREF_EBX ((0 << X86_MODRM_MOD_SHIFT) | (X86_GREG_xSI << X86_MODRM_REG_SHIFT) | (X86_GREG_xBX)) +#define RM_EDI_DEREF_EBX ((0 << X86_MODRM_MOD_SHIFT) | (X86_GREG_xDI << X86_MODRM_REG_SHIFT) | (X86_GREG_xBX)) + +#define RM_EAX_DEREF_EBX_DISP8 ((1 << X86_MODRM_MOD_SHIFT) | (X86_GREG_xAX << X86_MODRM_REG_SHIFT) | (X86_GREG_xBX)) +#define RM_ECX_DEREF_EBX_DISP8 ((1 << X86_MODRM_MOD_SHIFT) | (X86_GREG_xCX << X86_MODRM_REG_SHIFT) | (X86_GREG_xBX)) +#define RM_EDX_DEREF_EBX_DISP8 ((1 << X86_MODRM_MOD_SHIFT) | (X86_GREG_xDX << X86_MODRM_REG_SHIFT) | (X86_GREG_xBX)) +#define RM_EBX_DEREF_EBX_DISP8 ((1 << X86_MODRM_MOD_SHIFT) | (X86_GREG_xBX << X86_MODRM_REG_SHIFT) | (X86_GREG_xBX)) +#define RM_ESP_DEREF_EBX_DISP8 ((1 << X86_MODRM_MOD_SHIFT) | (X86_GREG_xSP << X86_MODRM_REG_SHIFT) | (X86_GREG_xBX)) +#define RM_EBP_DEREF_EBX_DISP8 ((1 << X86_MODRM_MOD_SHIFT) | (X86_GREG_xBP << X86_MODRM_REG_SHIFT) | (X86_GREG_xBX)) +#define RM_ESI_DEREF_EBX_DISP8 ((1 << X86_MODRM_MOD_SHIFT) | (X86_GREG_xSI << X86_MODRM_REG_SHIFT) | (X86_GREG_xBX)) +#define RM_EDI_DEREF_EBX_DISP8 ((1 << X86_MODRM_MOD_SHIFT) | (X86_GREG_xDI << X86_MODRM_REG_SHIFT) | (X86_GREG_xBX)) + +#define RM_EAX_DEREF_EBX_DISP32 ((2 << X86_MODRM_MOD_SHIFT) | (X86_GREG_xAX << X86_MODRM_REG_SHIFT) | (X86_GREG_xBX)) +#define RM_ECX_DEREF_EBX_DISP32 ((2 << X86_MODRM_MOD_SHIFT) | (X86_GREG_xCX << X86_MODRM_REG_SHIFT) | (X86_GREG_xBX)) +#define RM_EDX_DEREF_EBX_DISP32 ((2 << X86_MODRM_MOD_SHIFT) | (X86_GREG_xDX << X86_MODRM_REG_SHIFT) | (X86_GREG_xBX)) +#define RM_EBX_DEREF_EBX_DISP32 ((2 << X86_MODRM_MOD_SHIFT) | (X86_GREG_xBX << X86_MODRM_REG_SHIFT) | (X86_GREG_xBX)) +#define RM_ESP_DEREF_EBX_DISP32 ((2 << X86_MODRM_MOD_SHIFT) | (X86_GREG_xSP << X86_MODRM_REG_SHIFT) | (X86_GREG_xBX)) +#define RM_EBP_DEREF_EBX_DISP32 ((2 << X86_MODRM_MOD_SHIFT) | (X86_GREG_xBP << X86_MODRM_REG_SHIFT) | (X86_GREG_xBX)) +#define RM_ESI_DEREF_EBX_DISP32 ((2 << X86_MODRM_MOD_SHIFT) | (X86_GREG_xSI << X86_MODRM_REG_SHIFT) | (X86_GREG_xBX)) +#define RM_EDI_DEREF_EBX_DISP32 ((2 << X86_MODRM_MOD_SHIFT) | (X86_GREG_xDI << X86_MODRM_REG_SHIFT) | (X86_GREG_xBX)) + +#define RM_EAX_SIB ((0 << X86_MODRM_MOD_SHIFT) | (X86_GREG_xAX << X86_MODRM_REG_SHIFT) | 4) +#define RM_ECX_SIB ((0 << X86_MODRM_MOD_SHIFT) | (X86_GREG_xCX << X86_MODRM_REG_SHIFT) | 4) +#define RM_EDX_SIB ((0 << X86_MODRM_MOD_SHIFT) | (X86_GREG_xDX << X86_MODRM_REG_SHIFT) | 4) +#define RM_EBX_SIB ((0 << X86_MODRM_MOD_SHIFT) | (X86_GREG_xBX << X86_MODRM_REG_SHIFT) | 4) +#define RM_ESP_SIB ((0 << X86_MODRM_MOD_SHIFT) | (X86_GREG_xSP << X86_MODRM_REG_SHIFT) | 4) +#define RM_EBP_SIB ((0 << X86_MODRM_MOD_SHIFT) | (X86_GREG_xBP << X86_MODRM_REG_SHIFT) | 4) +#define RM_ESI_SIB ((0 << X86_MODRM_MOD_SHIFT) | (X86_GREG_xSI << X86_MODRM_REG_SHIFT) | 4) +#define RM_EDI_SIB ((0 << X86_MODRM_MOD_SHIFT) | (X86_GREG_xDI << X86_MODRM_REG_SHIFT) | 4) + +#define RM_EAX_SIB_DISP8 ((1 << X86_MODRM_MOD_SHIFT) | (X86_GREG_xAX << X86_MODRM_REG_SHIFT) | 4) +#define RM_ECX_SIB_DISP8 ((1 << X86_MODRM_MOD_SHIFT) | (X86_GREG_xCX << X86_MODRM_REG_SHIFT) | 4) +#define RM_EDX_SIB_DISP8 ((1 << X86_MODRM_MOD_SHIFT) | (X86_GREG_xDX << X86_MODRM_REG_SHIFT) | 4) +#define RM_EBX_SIB_DISP8 ((1 << X86_MODRM_MOD_SHIFT) | (X86_GREG_xBX << X86_MODRM_REG_SHIFT) | 4) +#define RM_ESP_SIB_DISP8 ((1 << X86_MODRM_MOD_SHIFT) | (X86_GREG_xSP << X86_MODRM_REG_SHIFT) | 4) +#define RM_EBP_SIB_DISP8 ((1 << X86_MODRM_MOD_SHIFT) | (X86_GREG_xBP << X86_MODRM_REG_SHIFT) | 4) +#define RM_ESI_SIB_DISP8 ((1 << X86_MODRM_MOD_SHIFT) | (X86_GREG_xSI << X86_MODRM_REG_SHIFT) | 4) +#define RM_EDI_SIB_DISP8 ((1 << X86_MODRM_MOD_SHIFT) | (X86_GREG_xDI << X86_MODRM_REG_SHIFT) | 4) + +#define RM_EAX_SIB_DISP32 ((2 << X86_MODRM_MOD_SHIFT) | (X86_GREG_xAX << X86_MODRM_REG_SHIFT) | 4) +#define RM_ECX_SIB_DISP32 ((2 << X86_MODRM_MOD_SHIFT) | (X86_GREG_xCX << X86_MODRM_REG_SHIFT) | 4) +#define RM_EDX_SIB_DISP32 ((2 << X86_MODRM_MOD_SHIFT) | (X86_GREG_xDX << X86_MODRM_REG_SHIFT) | 4) +#define RM_EBX_SIB_DISP32 ((2 << X86_MODRM_MOD_SHIFT) | (X86_GREG_xBX << X86_MODRM_REG_SHIFT) | 4) +#define RM_ESP_SIB_DISP32 ((2 << X86_MODRM_MOD_SHIFT) | (X86_GREG_xSP << X86_MODRM_REG_SHIFT) | 4) +#define RM_EBP_SIB_DISP32 ((2 << X86_MODRM_MOD_SHIFT) | (X86_GREG_xBP << X86_MODRM_REG_SHIFT) | 4) +#define RM_ESI_SIB_DISP32 ((2 << X86_MODRM_MOD_SHIFT) | (X86_GREG_xSI << X86_MODRM_REG_SHIFT) | 4) +#define RM_EDI_SIB_DISP32 ((2 << X86_MODRM_MOD_SHIFT) | (X86_GREG_xDI << X86_MODRM_REG_SHIFT) | 4) + +#define RM_XMM0_XMM1 ((3 << X86_MODRM_MOD_SHIFT) | (0 << X86_MODRM_REG_SHIFT) | 1) + +#define SIB_EBX_X1_NONE ((0 << X86_SIB_SCALE_SHIFT) | (4 << X86_SIB_INDEX_SHIFT) | (X86_GREG_xBX)) +#define SIB_EBX_X2_NONE ((1 << X86_SIB_SCALE_SHIFT) | (4 << X86_SIB_INDEX_SHIFT) | (X86_GREG_xBX)) +#define SIB_EBX_X4_NONE ((2 << X86_SIB_SCALE_SHIFT) | (4 << X86_SIB_INDEX_SHIFT) | (X86_GREG_xBX)) +#define SIB_EBX_X8_NONE ((3 << X86_SIB_SCALE_SHIFT) | (4 << X86_SIB_INDEX_SHIFT) | (X86_GREG_xBX)) + +#define F_486 UINT16_C(0x0000) +#define F_SSE2 UINT16_C(0x0001) +#define F_SSE3 UINT16_C(0x0002) +#define F_SSE42 UINT16_C(0x0004) +#define F_MOVBE UINT16_C(0x0080) +#define F_CBUD UINT16_C(0x4000) +#define F_UD UINT16_C(0x8000) +#define F_OK UINT16_C(0x0000) + + +/** + * This is an exploratory testcase. It tries to figure out how exactly the + * different Intel and AMD CPUs implements SSE and similar instructions that + * uses the size, repz, repnz and lock prefixes in the encoding. + */ +CPUDECODE1TST const g_aSimpleTests[] = +{ + /* + * fFlags, cbUd, cbOpcodes, abOpcodes + */ +#if 0 + /* Using currently undefined 0x0f 0x7a sequences. */ + { F_UD, 3, { 0x0f, 0x7a, RM_EAX_EAX, } }, + { F_UD, 3+1, { P_LK, 0x0f, 0x7a, RM_EAX_EAX, } }, + { F_UD, 3+1, { P_RZ, 0x0f, 0x7a, RM_EAX_EAX, } }, + { F_UD, 3+1, { P_RN, 0x0f, 0x7a, RM_EAX_EAX, } }, + { F_UD, 3+2, { P_LK, P_LK, 0x0f, 0x7a, RM_EAX_EAX, } }, + { F_UD, 4, { 0x0f, 0x7a, RM_EAX_DEREF_EBX_DISP8, 0 } }, + { F_UD, 4+1, { P_LK, 0x0f, 0x7a, RM_EAX_DEREF_EBX_DISP8, 0 } }, + { F_UD, 4+1, { P_RZ, 0x0f, 0x7a, RM_EAX_DEREF_EBX_DISP8, 0 } }, + { F_UD, 4+1, { P_RN, 0x0f, 0x7a, RM_EAX_DEREF_EBX_DISP8, 0 } }, + { F_UD, 4+2, { P_LK, P_LK, 0x0f, 0x7a, RM_EAX_DEREF_EBX_DISP8, 0 } }, + { F_UD, 7, { 0x0f, 0x7a, RM_EAX_DEREF_EBX_DISP32, 0, 0, 0, 0 } }, + { F_UD, 7+1, { P_LK, 0x0f, 0x7a, RM_EAX_DEREF_EBX_DISP32, 0, 0, 0, 0 } }, + { F_UD, 7+1, { P_RZ, 0x0f, 0x7a, RM_EAX_DEREF_EBX_DISP32, 0, 0, 0, 0 } }, + { F_UD, 7+1, { P_RN, 0x0f, 0x7a, RM_EAX_DEREF_EBX_DISP32, 0, 0, 0, 0 } }, + { F_UD, 7+2, { P_LK, P_LK, 0x0f, 0x7a, RM_EAX_DEREF_EBX_DISP32, 0, 0, 0, 0 } }, +#endif +#if 0 + /* Ditto for currently undefined sequence: 0x0f 0x7b */ + { F_UD, 3, { 0x0f, 0x7b, RM_EAX_EAX, } }, + { F_UD, 3+1, { P_LK, 0x0f, 0x7b, RM_EAX_EAX, } }, + { F_UD, 3+1, { P_RZ, 0x0f, 0x7b, RM_EAX_EAX, } }, + { F_UD, 3+1, { P_RN, 0x0f, 0x7b, RM_EAX_EAX, } }, + { F_UD, 3+2, { P_LK, P_LK, 0x0f, 0x7b, RM_EAX_EAX, } }, +#endif +#if 1 + /* Ditto for currently undefined sequence: 0x0f 0x24 */ + { F_UD, 3, { 0x0f, 0x24, RM_EAX_EAX, } }, + { F_UD, 3+1, { P_LK, 0x0f, 0x24, RM_EAX_EAX, } }, + { F_UD, 3+1, { P_RZ, 0x0f, 0x24, RM_EAX_EAX, } }, + { F_UD, 3+1, { P_RN, 0x0f, 0x24, RM_EAX_EAX, } }, + { F_UD, 3+2, { P_LK, P_LK, 0x0f, 0x24, RM_EAX_EAX, } }, +#endif +#if 0 + /* The XADD instruction has empty lines for 66, f3 and f2 prefixes. + AMD doesn't do anything special for XADD Ev,Gv as the intel table would indicate. */ + { F_486 | F_OK, 3, { 0x0f, 0xc1, RM_EAX_EAX, } }, + { F_486 | F_OK, 4, { P_OZ, 0x0f, 0xc1, RM_EAX_EAX, } }, + { F_486 | F_OK, 4, { P_RZ, 0x0f, 0xc1, RM_EAX_EAX, } }, + { F_486 | F_OK, 5, { P_OZ, P_RZ, 0x0f, 0xc1, RM_EAX_EAX, } }, + { F_486 | F_OK, 5, { P_RZ, P_OZ, 0x0f, 0xc1, RM_EAX_EAX, } }, + { F_486 | F_OK, 4, { P_RN, 0x0f, 0xc1, RM_EAX_EAX, } }, + { F_486 | F_OK, 5, { P_OZ, P_RN, 0x0f, 0xc1, RM_EAX_EAX, } }, + { F_486 | F_OK, 5, { P_RN, P_OZ, 0x0f, 0xc1, RM_EAX_EAX, } }, +#endif +#if 0 + /* The movnti instruction is confined to the unprefixed lined in the intel manuals. Check how the other lines work. */ + { F_SSE2 | F_UD, 3, { 0x0f, 0xc3, RM_EAX_EAX, } }, /* invalid - reg,reg */ + { F_SSE2 | F_OK, 3, { 0x0f, 0xc3, RM_EAX_DEREF_EBX, } }, + { F_SSE2 | F_UD, 4, { P_OZ, 0x0f, 0xc3, RM_EAX_DEREF_EBX, } }, /* invalid */ + { F_SSE2 | F_UD, 4, { P_RZ, 0x0f, 0xc3, RM_EAX_DEREF_EBX, } }, /* invalid */ + { F_SSE2 | F_UD, 4, { P_RN, 0x0f, 0xc3, RM_EAX_DEREF_EBX, } }, /* invalid */ + { F_SSE2 | F_UD, 4, { P_LK, 0x0f, 0xc3, RM_EAX_DEREF_EBX, } }, /* invalid */ + { F_SSE2 | F_UD, 5, { P_RN, P_LK, 0x0f, 0xc3, RM_EAX_DEREF_EBX, } }, /* invalid */ +#endif +#if 0 + /* The lddqu instruction requires a 0xf2 prefix, intel only lists 0x66 and empty + prefix for it. Check what they really mean by that*/ + { F_SSE3 | F_UD, 4, { P_RN, 0x0f, 0xf0, RM_EAX_EAX, } }, /* invalid - reg, reg */ + { F_SSE3 | F_OK, 4, { P_RN, 0x0f, 0xf0, RM_EAX_DEREF_EBX, } }, + { F_SSE3 | F_OK, 5, { P_RN, P_RN, 0x0f, 0xf0, RM_EAX_DEREF_EBX, } }, + { F_SSE3 | F_UD, 3, { 0x0f, 0xf0, RM_EAX_DEREF_EBX, } }, + { F_SSE3 | F_UD, 4, { P_RZ, 0x0f, 0xf0, RM_EAX_DEREF_EBX, } }, + { F_SSE3 | F_UD, 4, { P_OZ, 0x0f, 0xf0, RM_EAX_DEREF_EBX, } }, + { F_SSE3 | F_UD, 4, { P_LK, 0x0f, 0xf0, RM_EAX_DEREF_EBX, } }, + { F_SSE3 | F_UD, 5, { P_RN, P_RZ, 0x0f, 0xf0, RM_EAX_DEREF_EBX, } }, + { F_SSE3 | F_OK, 5, { P_RN, P_OZ, 0x0f, 0xf0, RM_EAX_DEREF_EBX, } }, // AMD,why? + { F_SSE3 | F_UD, 5, { P_RN, P_LK, 0x0f, 0xf0, RM_EAX_DEREF_EBX, } }, + { F_SSE3 | F_OK, 5, { P_RZ, P_RN, 0x0f, 0xf0, RM_EAX_DEREF_EBX, } }, + { F_SSE3 | F_OK, 5, { P_OZ, P_RN, 0x0f, 0xf0, RM_EAX_DEREF_EBX, } }, + { F_SSE3 | F_UD, 5, { P_LK, P_RN, 0x0f, 0xf0, RM_EAX_DEREF_EBX, } }, + { F_SSE3 | F_OK, 5, { P_OZ, P_RN, 0x0f, 0xf0, RM_EAX_DEREF_EBX, } }, + { F_SSE3 | F_OK, 6,{ P_OZ, P_RZ, P_RN, 0x0f, 0xf0, RM_EAX_DEREF_EBX, } }, +#endif +#if 0 + { F_SSE2 | F_OK, 3, { 0x0f, 0x7e, RM_EAX_EAX, } }, + { F_SSE2 | F_OK, 4, { P_OZ, 0x0f, 0x7e, RM_EAX_EAX, } }, + { F_SSE2 | F_UD, 5,{ P_RN, P_OZ, 0x0f, 0x7e, RM_EAX_EAX, } }, // WTF? + { F_SSE2 | F_UD, 5,{ P_OZ, P_RN, 0x0f, 0x7e, RM_EAX_EAX, } }, + { F_SSE2 | F_OK, 5,{ P_RZ, P_OZ, 0x0f, 0x7e, RM_EAX_EAX, } }, + { F_SSE2 | F_OK, 4, { P_RZ, 0x0f, 0x7e, RM_EAX_EAX, } }, + { F_SSE2 | F_UD, 4, { P_RN, 0x0f, 0x7e, RM_EAX_EAX, } }, +#endif +/** @todo crc32 / movbe */ +}; + +void DecodeEdgeTest(void) +{ + /* + * Allocate and initialize a page pair + */ + uint8_t BS3_FAR *pbPages; + pbPages = Bs3MemGuardedTestPageAlloc(BS3MEMKIND_FLAT32); + if (pbPages) + { + unsigned i; + BS3REGCTX Ctx; + BS3TRAPFRAME TrapFrame; + + Bs3MemZero(&Ctx, sizeof(Ctx)); + Bs3MemZero(&TrapFrame, sizeof(TrapFrame)); + + ASMSetCR0((ASMGetCR0() & ~(X86_CR0_EM | X86_CR0_TS)) | X86_CR0_MP); + ASMSetCR4(ASMGetCR4() | X86_CR4_OSFXSR); + + Bs3RegCtxSaveEx(&Ctx, BS3_MODE_CODE_32, 512); + Ctx.rbx.u64 = (uintptr_t)pbPages; + + for (i = 0; i < RT_ELEMENTS(g_aSimpleTests); i++) + { + unsigned const cbOpcodes = g_aSimpleTests[i].cbOpcodes; + uint16_t const fFlags = g_aSimpleTests[i].fFlags; + unsigned cb; + /** @todo check if supported. */ + + /* + * Place the instruction exactly at the page boundrary and proceed to + * move it across it and check that we get #PFs then. + */ + cb = cbOpcodes; + while (cb >= 1) + { + unsigned const cErrorsBefore = Bs3TestSubErrorCount(); + uint8_t BS3_FAR *pbRip = &pbPages[X86_PAGE_SIZE - cb]; + Bs3MemCpy(pbRip, &g_aSimpleTests[i].abOpcodes[0], cb); + Bs3RegCtxSetRipCsFromFlat(&Ctx, (uintptr_t)pbRip); + Bs3TrapSetJmpAndRestore(&Ctx, &TrapFrame); +#if 1 + Bs3TestPrintf("\ni=%d cb=%#x (cbOpcodes=%#x fFlags=%#x)\n", i, cb, cbOpcodes, fFlags); +// Bs3TrapPrintFrame(&TrapFrame); +#endif + if (cb >= cbOpcodes && (g_aSimpleTests[i].fFlags & F_UD)) + { + if (TrapFrame.bXcpt != X86_XCPT_UD) + Bs3TestFailedF("i=%d cb=%d cbOp=%d fFlags=%#x: expected #UD got %#x at %RX32\n", + i, cb, cbOpcodes, fFlags, TrapFrame.bXcpt, TrapFrame.Ctx.rip.u32); + } + else if (cb < cbOpcodes) + { + if (TrapFrame.bXcpt != X86_XCPT_PF) + Bs3TestFailedF("i=%d cb=%d cbOp=%d fFlags=%#x: expected #PF (on) got %#x at %RX32\n", + i, cb, cbOpcodes, fFlags, TrapFrame.bXcpt, TrapFrame.Ctx.rip.u32); + else if (TrapFrame.Ctx.rip.u32 != (uintptr_t)pbRip) + Bs3TestFailedF("i=%d cb=%d cbOp=%d fFlags=%#x: expected #PF rip of %p (on) got %#RX32\n", + i, cb, cbOpcodes, fFlags, pbRip, TrapFrame.Ctx.rip.u32); + } + else + { + if (TrapFrame.bXcpt != X86_XCPT_PF) + Bs3TestFailedF("i=%d cb=%d cbOp=%d fFlags=%#x: expected #PF (after) got %#x at %RX32\n", + i, cb, cbOpcodes, fFlags, TrapFrame.bXcpt, TrapFrame.Ctx.rip.u32); + else if (TrapFrame.Ctx.rip.u32 != (uintptr_t)&pbPages[X86_PAGE_SIZE]) + Bs3TestFailedF("i=%d cb=%d cbOp=%d fFlags=%#x: expected #PF rip of %p (after) got %#RX32\n", + i, cb, cbOpcodes, fFlags, &pbPages[X86_PAGE_SIZE], TrapFrame.Ctx.rip.u32); + } + if (Bs3TestSubErrorCount() != cErrorsBefore) + { + Bs3TestPrintf(" %.*Rhxs", cb, &g_aSimpleTests[i].abOpcodes[0]); + if (cb < cbOpcodes) + Bs3TestPrintf("[%.*Rhxs]", cbOpcodes - cb, &g_aSimpleTests[i].abOpcodes[cb]); + Bs3TestPrintf("\n"); + } + + /* next */ + cb--; + } + } + + Bs3MemGuardedTestPageFree(pbPages); + } + else + Bs3TestFailed("Failed to allocate two pages!\n"); + + /* + * Test instruction sequences. + */ + + +} + + +/** + * Undefined opcode test. + */ +typedef struct CPUDECODE1UDTST +{ + /** Type of undefined opcode decoding logic - UD_T_XXX. */ + uint8_t enmType; + /** Core opcodes length. */ + uint8_t cbOpcodes; + /** Core opcodes. */ + uint8_t abOpcodes[5]; + /** UD_F_XXX. */ + uint8_t fFlags; +} CPUDECODE1UDTST; +typedef CPUDECODE1UDTST const BS3_FAR *PCCPUDECODE1UDTST; + +#define UD_T_EXACT 0 +#define UD_T_NOAMD 0x80 /**< AMD does not decode unnecessary bytes, Intel does. */ +#define UD_T_MODRM 1 +#define UD_T_MODRM_I8 2 +#define UD_T_MODRM_M 3 +#define UD_T_MODRM_M_I8 4 +#define UD_T_MODRM_RR0 0x10 +#define UD_T_MODRM_RR1 0x11 +#define UD_T_MODRM_RR2 0x12 +#define UD_T_MODRM_RR3 0x13 +#define UD_T_MODRM_RR4 0x14 +#define UD_T_MODRM_RR5 0x15 +#define UD_T_MODRM_RR6 0x16 +#define UD_T_MODRM_RR7 0x17 +#define UD_T_MODRM_RR0_I8 0x18 +#define UD_T_MODRM_RR1_I8 0x19 +#define UD_T_MODRM_RR2_I8 0x1a +#define UD_T_MODRM_RR3_I8 0x1b +#define UD_T_MODRM_RR4_I8 0x1c +#define UD_T_MODRM_RR5_I8 0x1d +#define UD_T_MODRM_RR6_I8 0x1e +#define UD_T_MODRM_RR7_I8 0x1f +#define UD_T_MODRM_MR0 0x20 +#define UD_T_MODRM_MR1 0x21 +#define UD_T_MODRM_MR2 0x22 +#define UD_T_MODRM_MR3 0x23 +#define UD_T_MODRM_MR4 0x24 +#define UD_T_MODRM_MR5 0x25 +#define UD_T_MODRM_MR6 0x26 +#define UD_T_MODRM_MR7 0x27 +#define UD_T_MODRM_MR0_I8 0x28 +#define UD_T_MODRM_MR1_I8 0x29 +#define UD_T_MODRM_MR2_I8 0x2a +#define UD_T_MODRM_MR3_I8 0x2b +#define UD_T_MODRM_MR4_I8 0x2c +#define UD_T_MODRM_MR5_I8 0x2d +#define UD_T_MODRM_MR6_I8 0x2e +#define UD_T_MODRM_MR7_I8 0x2f + +#define UD_F_ANY_PFX 0 +#define UD_F_NOT_NO_PFX UINT8_C(0x01) /**< Must have some kind of prefix to be \#UD. */ +#define UD_F_NOT_OZ_PFX UINT8_C(0x02) /**< Skip the size prefix. */ +#define UD_F_NOT_RZ_PFX UINT8_C(0x04) /**< Skip the REPZ prefix. */ +#define UD_F_NOT_RN_PFX UINT8_C(0x08) /**< Skip the REPNZ prefix. */ +#define UD_F_NOT_LK_PFX UINT8_C(0x10) /**< Skip the LOCK prefix. */ +#define UD_F_3BYTE_ESC UINT8_C(0x20) /**< Unused 3 byte escape table. Test all 256 entries */ + +/** + * Two byte opcodes. + */ +CPUDECODE1UDTST const g_aUdTest2Byte_0f[] = +{ +#if 0 + { UD_T_EXACT, 2, { 0x0f, 0x04 }, UD_F_ANY_PFX }, + { UD_T_EXACT, 2, { 0x0f, 0x0a }, UD_F_ANY_PFX }, + { UD_T_EXACT, 2, { 0x0f, 0x0c }, UD_F_ANY_PFX }, + { UD_T_EXACT, 2, { 0x0f, 0x0e }, UD_F_ANY_PFX }, + { UD_T_EXACT, 2, { 0x0f, 0x0f }, UD_F_ANY_PFX }, + { UD_T_MODRM, 2, { 0x0f, 0x13 }, UD_F_NOT_NO_PFX | UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 2, { 0x0f, 0x14 }, UD_F_NOT_NO_PFX | UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 2, { 0x0f, 0x15 }, UD_F_NOT_NO_PFX | UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 2, { 0x0f, 0x16 }, UD_F_NOT_NO_PFX | UD_F_NOT_OZ_PFX | UD_F_NOT_RZ_PFX }, + { UD_T_MODRM, 2, { 0x0f, 0x17 }, UD_F_NOT_NO_PFX | UD_F_NOT_OZ_PFX }, + /** @todo figure when 0f 019 and 0f 0c-0f were made into NOPs. */ + { UD_T_EXACT, 2, { 0x0f, 0x24 }, UD_F_ANY_PFX }, + { UD_T_EXACT, 2, { 0x0f, 0x25 }, UD_F_ANY_PFX }, + { UD_T_EXACT, 2, { 0x0f, 0x26 }, UD_F_ANY_PFX }, + { UD_T_EXACT, 2, { 0x0f, 0x27 }, UD_F_ANY_PFX }, + { UD_T_MODRM, 2, { 0x0f, 0x28 }, UD_F_NOT_NO_PFX | UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 2, { 0x0f, 0x29 }, UD_F_NOT_NO_PFX | UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 2, { 0x0f, 0x2b }, UD_F_NOT_NO_PFX | UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 2, { 0x0f, 0x2e }, UD_F_NOT_NO_PFX | UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 2, { 0x0f, 0x2f }, UD_F_NOT_NO_PFX | UD_F_NOT_OZ_PFX }, + { UD_T_EXACT, 2, { 0x0f, 0x36 }, UD_F_ANY_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x39, 0x00 }, UD_F_3BYTE_ESC | UD_F_ANY_PFX }, /* Three byte escape table, just unused. */ + { UD_T_MODRM_I8, 3, { 0x0f, 0x3b, 0x00 }, UD_F_3BYTE_ESC | UD_F_ANY_PFX }, /* Three byte escape table, just unused. */ + { UD_T_MODRM, 3, { 0x0f, 0x3c, 0x00 }, UD_F_3BYTE_ESC | UD_F_ANY_PFX }, /* Three byte escape table, just unused. */ + { UD_T_MODRM, 3, { 0x0f, 0x3d, 0x00 }, UD_F_3BYTE_ESC | UD_F_ANY_PFX }, /* Three byte escape table, just unused. */ + { UD_T_MODRM_I8, 3, { 0x0f, 0x3e, 0x00 }, UD_F_3BYTE_ESC | UD_F_ANY_PFX }, /* Three byte escape table, just unused. */ + { UD_T_MODRM_I8, 3, { 0x0f, 0x3f, 0x00 }, UD_F_3BYTE_ESC | UD_F_ANY_PFX }, /* Three byte escape table, just unused. */ + { UD_T_MODRM, 2, { 0x0f, 0x50 }, UD_F_NOT_NO_PFX | UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 2, { 0x0f, 0x52 }, UD_F_NOT_NO_PFX | UD_F_NOT_RZ_PFX }, + { UD_T_MODRM, 2, { 0x0f, 0x53 }, UD_F_NOT_NO_PFX | UD_F_NOT_RZ_PFX }, + { UD_T_MODRM, 2, { 0x0f, 0x54 }, UD_F_NOT_NO_PFX | UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 2, { 0x0f, 0x55 }, UD_F_NOT_NO_PFX | UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 2, { 0x0f, 0x56 }, UD_F_NOT_NO_PFX | UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 2, { 0x0f, 0x57 }, UD_F_NOT_NO_PFX | UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 2, { 0x0f, 0x5b }, UD_F_NOT_NO_PFX | UD_F_NOT_OZ_PFX | UD_F_NOT_RZ_PFX }, + { UD_T_MODRM, 2, { 0x0f, 0x60 }, UD_F_NOT_NO_PFX | UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 2, { 0x0f, 0x61 }, UD_F_NOT_NO_PFX | UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 2, { 0x0f, 0x62 }, UD_F_NOT_NO_PFX | UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 2, { 0x0f, 0x63 }, UD_F_NOT_NO_PFX | UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 2, { 0x0f, 0x64 }, UD_F_NOT_NO_PFX | UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 2, { 0x0f, 0x65 }, UD_F_NOT_NO_PFX | UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 2, { 0x0f, 0x66 }, UD_F_NOT_NO_PFX | UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 2, { 0x0f, 0x67 }, UD_F_NOT_NO_PFX | UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 2, { 0x0f, 0x68 }, UD_F_NOT_NO_PFX | UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 2, { 0x0f, 0x69 }, UD_F_NOT_NO_PFX | UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 2, { 0x0f, 0x6a }, UD_F_NOT_NO_PFX | UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 2, { 0x0f, 0x6b }, UD_F_NOT_NO_PFX | UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 2, { 0x0f, 0x6c }, UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 2, { 0x0f, 0x6d }, UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 2, { 0x0f, 0x6e }, UD_F_NOT_NO_PFX | UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 2, { 0x0f, 0x6f }, UD_F_NOT_NO_PFX | UD_F_NOT_OZ_PFX | UD_F_NOT_RZ_PFX }, + { UD_T_MODRM_M_I8, 2, { 0x0f, 0x71 }, UD_F_ANY_PFX }, + { UD_T_MODRM_RR0_I8, 2, { 0x0f, 0x71 }, UD_F_ANY_PFX }, + { UD_T_MODRM_RR1_I8, 2, { 0x0f, 0x71 }, UD_F_ANY_PFX }, + { UD_T_MODRM_RR2_I8, 2, { 0x0f, 0x71 }, UD_F_NOT_NO_PFX | UD_F_NOT_OZ_PFX }, + { UD_T_MODRM_RR3_I8, 2, { 0x0f, 0x71 }, UD_F_ANY_PFX }, + { UD_T_MODRM_RR4_I8, 2, { 0x0f, 0x71 }, UD_F_NOT_NO_PFX | UD_F_NOT_OZ_PFX }, + { UD_T_MODRM_RR5_I8, 2, { 0x0f, 0x71 }, UD_F_ANY_PFX }, + { UD_T_MODRM_RR6_I8, 2, { 0x0f, 0x71 }, UD_F_NOT_NO_PFX | UD_F_NOT_OZ_PFX }, + { UD_T_MODRM_RR7_I8, 2, { 0x0f, 0x71 }, UD_F_ANY_PFX }, + { UD_T_MODRM_M_I8, 2, { 0x0f, 0x72 }, UD_F_ANY_PFX }, + { UD_T_MODRM_RR0_I8, 2, { 0x0f, 0x72 }, UD_F_ANY_PFX }, + { UD_T_MODRM_RR1_I8, 2, { 0x0f, 0x72 }, UD_F_ANY_PFX }, + { UD_T_MODRM_RR2_I8, 2, { 0x0f, 0x72 }, UD_F_NOT_NO_PFX | UD_F_NOT_OZ_PFX }, + { UD_T_MODRM_RR3_I8, 2, { 0x0f, 0x72 }, UD_F_ANY_PFX }, + { UD_T_MODRM_RR4_I8, 2, { 0x0f, 0x72 }, UD_F_NOT_NO_PFX | UD_F_NOT_OZ_PFX }, + { UD_T_MODRM_RR5_I8, 2, { 0x0f, 0x72 }, UD_F_ANY_PFX }, + { UD_T_MODRM_RR6_I8, 2, { 0x0f, 0x72 }, UD_F_NOT_NO_PFX | UD_F_NOT_OZ_PFX }, + { UD_T_MODRM_RR7_I8, 2, { 0x0f, 0x72 }, UD_F_ANY_PFX }, + { UD_T_MODRM_M_I8, 2, { 0x0f, 0x73 }, UD_F_ANY_PFX }, + { UD_T_MODRM_RR0_I8, 2, { 0x0f, 0x73 }, UD_F_ANY_PFX }, + { UD_T_MODRM_RR1_I8, 2, { 0x0f, 0x73 }, UD_F_ANY_PFX }, + { UD_T_MODRM_RR2_I8, 2, { 0x0f, 0x73 }, UD_F_NOT_NO_PFX | UD_F_NOT_OZ_PFX }, + { UD_T_MODRM_RR3_I8, 2, { 0x0f, 0x73 }, UD_F_NOT_OZ_PFX }, + { UD_T_MODRM_RR4_I8, 2, { 0x0f, 0x73 }, UD_F_ANY_PFX }, + { UD_T_MODRM_RR5_I8, 2, { 0x0f, 0x73 }, UD_F_ANY_PFX }, + { UD_T_MODRM_RR6_I8, 2, { 0x0f, 0x73 }, UD_F_NOT_NO_PFX | UD_F_NOT_OZ_PFX }, + { UD_T_MODRM_RR7_I8, 2, { 0x0f, 0x73 }, UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 2, { 0x0f, 0x74 }, UD_F_NOT_NO_PFX | UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 2, { 0x0f, 0x75 }, UD_F_NOT_NO_PFX | UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 2, { 0x0f, 0x76 }, UD_F_NOT_NO_PFX | UD_F_NOT_OZ_PFX }, + /* 0f 77: WTF? OZ, RZ and RN are all empty in the intel tables and LK isn't metnioned at all: */ + { UD_T_MODRM, 2, { 0x0f, 0x77 }, UD_F_NOT_NO_PFX | UD_F_NOT_OZ_PFX | UD_F_NOT_RN_PFX | UD_F_NOT_RZ_PFX | UD_F_NOT_LK_PFX }, + { UD_T_MODRM, 2, { 0x0f, 0x78 }, UD_F_NOT_NO_PFX }, + { UD_T_MODRM, 2, { 0x0f, 0x79 }, UD_F_NOT_NO_PFX }, + { UD_T_MODRM, 2, { 0x0f, 0x7a }, UD_F_ANY_PFX }, + { UD_T_MODRM, 2, { 0x0f, 0x7b }, UD_F_ANY_PFX }, + { UD_T_MODRM, 2, { 0x0f, 0x7c }, UD_F_NOT_OZ_PFX | UD_F_NOT_RN_PFX }, + { UD_T_MODRM, 2, { 0x0f, 0x7d }, UD_F_NOT_OZ_PFX | UD_F_NOT_RN_PFX }, + { UD_T_MODRM, 2, { 0x0f, 0x7e }, UD_F_NOT_NO_PFX | UD_F_NOT_OZ_PFX | UD_F_NOT_RZ_PFX }, + { UD_T_MODRM, 2, { 0x0f, 0x7f }, UD_F_NOT_NO_PFX | UD_F_NOT_OZ_PFX | UD_F_NOT_RZ_PFX }, + { UD_T_MODRM, 2, { 0x0f, 0xa6 }, UD_F_ANY_PFX }, + { UD_T_MODRM, 2, { 0x0f, 0xa7 }, UD_F_ANY_PFX }, + { UD_T_MODRM_MR0, 2, { 0x0f, 0xae }, UD_F_NOT_NO_PFX }, /* fxsave only checks REX.W */ + { UD_T_MODRM_MR1, 2, { 0x0f, 0xae }, UD_F_NOT_NO_PFX }, /* frstor ditto */ + { UD_T_MODRM_MR2, 2, { 0x0f, 0xae }, UD_F_NOT_NO_PFX }, /* ldmxcsr */ + { UD_T_MODRM_MR3, 2, { 0x0f, 0xae }, UD_F_NOT_NO_PFX }, /* stmxcsr */ + { UD_T_MODRM_MR4, 2, { 0x0f, 0xae }, UD_F_NOT_NO_PFX }, /* xsave */ + { UD_T_MODRM_MR5, 2, { 0x0f, 0xae }, UD_F_NOT_NO_PFX }, /* xrstor */ + { UD_T_MODRM_MR6, 2, { 0x0f, 0xae }, UD_F_NOT_NO_PFX }, /* xsaveopt */ + { UD_T_MODRM_MR7, 2, { 0x0f, 0xae }, UD_F_NOT_NO_PFX | UD_F_NOT_OZ_PFX }, /* clflush (none) and clflushopt (66) */ + { UD_T_MODRM_RR0, 2, { 0x0f, 0xae }, UD_F_ANY_PFX }, /* f3=rdfsbase is 64-bit */ + { UD_T_MODRM_RR1, 2, { 0x0f, 0xae }, UD_F_ANY_PFX }, /* f3=rdfsbase is 64-bit */ + { UD_T_MODRM_RR2, 2, { 0x0f, 0xae }, UD_F_ANY_PFX }, /* f3=rdfsbase is 64-bit */ + { UD_T_MODRM_RR3, 2, { 0x0f, 0xae }, UD_F_ANY_PFX }, /* f3=rdfsbase is 64-bit */ + { UD_T_MODRM_RR4, 2, { 0x0f, 0xae }, UD_F_ANY_PFX }, /* unused */ + { UD_T_MODRM_RR5, 2, { 0x0f, 0xae }, UD_F_NOT_NO_PFX }, /* 00=lfence */ + { UD_T_MODRM_RR6, 2, { 0x0f, 0xae }, UD_F_NOT_NO_PFX }, /* 00=mfence */ + { UD_T_MODRM_RR7, 2, { 0x0f, 0xae }, UD_F_NOT_NO_PFX }, /* 00=sfence */ + { UD_T_MODRM, 2, { 0x0f, 0xb8 }, UD_F_NOT_RZ_PFX }, + { UD_T_MODRM | UD_T_NOAMD, 2, { 0x0f, 0xb9 }, UD_F_ANY_PFX }, /* UD1 */ + { UD_T_MODRM_MR0_I8, 2, { 0x0f, 0xba }, UD_F_ANY_PFX }, /* grp8 */ + { UD_T_MODRM_MR1_I8, 2, { 0x0f, 0xba }, UD_F_ANY_PFX }, /* grp8 */ + { UD_T_MODRM_MR2_I8, 2, { 0x0f, 0xba }, UD_F_ANY_PFX }, /* grp8 */ + { UD_T_MODRM_MR3_I8, 2, { 0x0f, 0xba }, UD_F_ANY_PFX }, /* grp8 */ + /** @todo f3 0f bb rm and f2 0f bb rm does stuff on skylake even if their are blank in intel and AMD tables! */ + //{ UD_T_MODRM, 2, { 0x0f, 0xbb }, UD_F_NOT_NO_PFX | UD_F_NOT_OZ_PFX }, + /** @todo AMD tables indicates that f2 0f bc rm is invalid, but on skylake it works differently (BSF?) */ + { UD_T_MODRM, 2, { 0x0f, 0xbc }, UD_F_NOT_NO_PFX | UD_F_NOT_OZ_PFX | UD_F_NOT_RZ_PFX /* figure: */ | UD_F_NOT_RN_PFX }, + /** @todo AMD tables indicates that f3 0f bc rm is invalid, but on skylake it works differently (BSR?) */ + { UD_T_MODRM, 2, { 0x0f, 0xbd }, UD_F_NOT_NO_PFX | UD_F_NOT_OZ_PFX | UD_F_NOT_RZ_PFX /* figure: */ | UD_F_NOT_RN_PFX }, + /* Note! Intel incorrectly states that XADD (0f c0 and 0f c1) are sensitive to OZ, RN and RZ. AMD and skylake hw disagrees. */ + { UD_T_MODRM, 2, { 0x0f, 0xc3 }, UD_F_NOT_NO_PFX }, + { UD_T_MODRM_I8, 2, { 0x0f, 0xc4 }, UD_F_NOT_NO_PFX | UD_F_NOT_OZ_PFX }, + { UD_T_MODRM_I8, 2, { 0x0f, 0xc5 }, UD_F_NOT_NO_PFX | UD_F_NOT_OZ_PFX }, + { UD_T_MODRM_I8, 2, { 0x0f, 0xc6 }, UD_F_NOT_NO_PFX | UD_F_NOT_OZ_PFX }, +#endif + { UD_T_MODRM_MR0, 2, { 0x0f, 0xc7 }, UD_F_ANY_PFX }, + { UD_T_MODRM_RR0, 2, { 0x0f, 0xc7 }, UD_F_ANY_PFX }, + //{ UD_T_MODRM_MR1, 2, { 0x0f, 0xc7 }, UD_F_NOT_NO_PFX | UD_F_NOT_OZ_PFX | UD_F_NOT_RN_PFX | UD_F_NOT_RZ_PFX | UD_F_NOT_LK_PFX }, - cmpxchg8b ignores everything. @ + { UD_T_MODRM_RR1, 2, { 0x0f, 0xc7 }, UD_F_ANY_PFX }, + { UD_T_MODRM_MR2, 2, { 0x0f, 0xc7 }, UD_F_ANY_PFX }, + { UD_T_MODRM_RR2, 2, { 0x0f, 0xc7 }, UD_F_ANY_PFX }, + { UD_T_MODRM_MR3, 2, { 0x0f, 0xc7 }, UD_F_ANY_PFX }, + { UD_T_MODRM_RR3, 2, { 0x0f, 0xc7 }, UD_F_ANY_PFX }, + { UD_T_MODRM_MR4, 2, { 0x0f, 0xc7 }, UD_F_ANY_PFX }, + { UD_T_MODRM_RR4, 2, { 0x0f, 0xc7 }, UD_F_ANY_PFX }, + { UD_T_MODRM_MR5, 2, { 0x0f, 0xc7 }, UD_F_ANY_PFX }, + { UD_T_MODRM_RR5, 2, { 0x0f, 0xc7 }, UD_F_ANY_PFX }, + { UD_T_MODRM_MR6, 2, { 0x0f, 0xc7 }, UD_F_NOT_NO_PFX | UD_F_NOT_OZ_PFX | UD_F_NOT_RZ_PFX }, /* f2? */ + { UD_T_MODRM_RR6, 2, { 0x0f, 0xc7 }, UD_F_NOT_NO_PFX | UD_F_NOT_OZ_PFX }, /* (rdrand Rv) */ + { UD_T_MODRM_MR7, 2, { 0x0f, 0xc7 }, UD_F_NOT_NO_PFX }, /* vmptrst Mq (f2?); */ + { UD_T_MODRM_RR7, 2, { 0x0f, 0xc7 }, UD_F_NOT_NO_PFX | UD_F_NOT_OZ_PFX | UD_F_NOT_RZ_PFX }, /* rdrand Rv; rdpid Rd/q (f2,66??); */ +#if 0 + { UD_T_MODRM, 2, { 0x0f, 0xd0 }, UD_F_NOT_OZ_PFX | UD_F_NOT_RN_PFX }, + { UD_T_MODRM, 2, { 0x0f, 0xd1 }, UD_F_NOT_NO_PFX | UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 2, { 0x0f, 0xd2 }, UD_F_NOT_NO_PFX | UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 2, { 0x0f, 0xd3 }, UD_F_NOT_NO_PFX | UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 2, { 0x0f, 0xd4 }, UD_F_NOT_NO_PFX | UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 2, { 0x0f, 0xd5 }, UD_F_NOT_NO_PFX | UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 2, { 0x0f, 0xd6 }, UD_F_NOT_OZ_PFX | UD_F_NOT_RN_PFX | UD_F_NOT_RZ_PFX }, + { UD_T_MODRM, 2, { 0x0f, 0xd7 }, UD_F_NOT_NO_PFX | UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 2, { 0x0f, 0xd8 }, UD_F_NOT_NO_PFX | UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 2, { 0x0f, 0xd9 }, UD_F_NOT_NO_PFX | UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 2, { 0x0f, 0xda }, UD_F_NOT_NO_PFX | UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 2, { 0x0f, 0xdb }, UD_F_NOT_NO_PFX | UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 2, { 0x0f, 0xdc }, UD_F_NOT_NO_PFX | UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 2, { 0x0f, 0xdd }, UD_F_NOT_NO_PFX | UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 2, { 0x0f, 0xde }, UD_F_NOT_NO_PFX | UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 2, { 0x0f, 0xdf }, UD_F_NOT_NO_PFX | UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 2, { 0x0f, 0xe0 }, UD_F_NOT_NO_PFX | UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 2, { 0x0f, 0xe1 }, UD_F_NOT_NO_PFX | UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 2, { 0x0f, 0xe2 }, UD_F_NOT_NO_PFX | UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 2, { 0x0f, 0xe3 }, UD_F_NOT_NO_PFX | UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 2, { 0x0f, 0xe4 }, UD_F_NOT_NO_PFX | UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 2, { 0x0f, 0xe5 }, UD_F_NOT_NO_PFX | UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 2, { 0x0f, 0xe6 }, UD_F_NOT_OZ_PFX | UD_F_NOT_RN_PFX | UD_F_NOT_RZ_PFX }, + { UD_T_MODRM, 2, { 0x0f, 0xe7 }, UD_F_NOT_NO_PFX | UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 2, { 0x0f, 0xe8 }, UD_F_NOT_NO_PFX | UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 2, { 0x0f, 0xe9 }, UD_F_NOT_NO_PFX | UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 2, { 0x0f, 0xea }, UD_F_NOT_NO_PFX | UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 2, { 0x0f, 0xeb }, UD_F_NOT_NO_PFX | UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 2, { 0x0f, 0xec }, UD_F_NOT_NO_PFX | UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 2, { 0x0f, 0xed }, UD_F_NOT_NO_PFX | UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 2, { 0x0f, 0xee }, UD_F_NOT_NO_PFX | UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 2, { 0x0f, 0xef }, UD_F_NOT_NO_PFX | UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 2, { 0x0f, 0xf0 }, UD_F_NOT_RN_PFX }, + { UD_T_MODRM, 2, { 0x0f, 0xf1 }, UD_F_NOT_NO_PFX | UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 2, { 0x0f, 0xf2 }, UD_F_NOT_NO_PFX | UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 2, { 0x0f, 0xf3 }, UD_F_NOT_NO_PFX | UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 2, { 0x0f, 0xf4 }, UD_F_NOT_NO_PFX | UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 2, { 0x0f, 0xf5 }, UD_F_NOT_NO_PFX | UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 2, { 0x0f, 0xf6 }, UD_F_NOT_NO_PFX | UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 2, { 0x0f, 0xf7 }, UD_F_NOT_NO_PFX | UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 2, { 0x0f, 0xf8 }, UD_F_NOT_NO_PFX | UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 2, { 0x0f, 0xf9 }, UD_F_NOT_NO_PFX | UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 2, { 0x0f, 0xfa }, UD_F_NOT_NO_PFX | UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 2, { 0x0f, 0xfb }, UD_F_NOT_NO_PFX | UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 2, { 0x0f, 0xfc }, UD_F_NOT_NO_PFX | UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 2, { 0x0f, 0xfd }, UD_F_NOT_NO_PFX | UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 2, { 0x0f, 0xfe }, UD_F_NOT_NO_PFX | UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 2, { 0x0f, 0xff }, UD_F_ANY_PFX }, +#endif +}; + + +/** + * Three byte opcodes. + */ +CPUDECODE1UDTST const g_aUdTest3Byte_0f_38[] = +{ + { UD_T_MODRM, 3, { 0x0f, 0x38, 0x00 }, UD_F_NOT_NO_PFX | UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0x01 }, UD_F_NOT_NO_PFX | UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0x02 }, UD_F_NOT_NO_PFX | UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0x03 }, UD_F_NOT_NO_PFX | UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0x04 }, UD_F_NOT_NO_PFX | UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0x05 }, UD_F_NOT_NO_PFX | UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0x06 }, UD_F_NOT_NO_PFX | UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0x07 }, UD_F_NOT_NO_PFX | UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0x08 }, UD_F_NOT_NO_PFX | UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0x09 }, UD_F_NOT_NO_PFX | UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0x0a }, UD_F_NOT_NO_PFX | UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0x0b }, UD_F_NOT_NO_PFX | UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0x0c }, UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0x0d }, UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0x0e }, UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0x0f }, UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0x10 }, UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0x11 }, UD_F_ANY_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0x12 }, UD_F_ANY_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0x13 }, UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0x14 }, UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0x15 }, UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0x16 }, UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0x17 }, UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0x18 }, UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0x19 }, UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0x1a }, UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0x1b }, UD_F_ANY_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0x1c }, UD_F_NOT_NO_PFX | UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0x1d }, UD_F_NOT_NO_PFX | UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0x1e }, UD_F_NOT_NO_PFX | UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0x1f }, UD_F_ANY_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0x20 }, UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0x21 }, UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0x22 }, UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0x23 }, UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0x24 }, UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0x25 }, UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0x26 }, UD_F_ANY_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0x27 }, UD_F_ANY_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0x28 }, UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0x29 }, UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0x2a }, UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0x2b }, UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0x2c }, UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0x2d }, UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0x2e }, UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0x2f }, UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0x30 }, UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0x31 }, UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0x32 }, UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0x33 }, UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0x34 }, UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0x35 }, UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0x36 }, UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0x37 }, UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0x38 }, UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0x39 }, UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0x3a }, UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0x3b }, UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0x3c }, UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0x3d }, UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0x3e }, UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0x3f }, UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0x40 }, UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0x41 }, UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0x42 }, UD_F_ANY_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0x43 }, UD_F_ANY_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0x44 }, UD_F_ANY_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0x45 }, UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0x46 }, UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0x47 }, UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0x48 }, UD_F_ANY_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0x49 }, UD_F_ANY_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0x4a }, UD_F_ANY_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0x4b }, UD_F_ANY_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0x4c }, UD_F_ANY_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0x4d }, UD_F_ANY_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0x4e }, UD_F_ANY_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0x4f }, UD_F_ANY_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0x50 }, UD_F_ANY_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0x51 }, UD_F_ANY_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0x52 }, UD_F_ANY_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0x53 }, UD_F_ANY_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0x54 }, UD_F_ANY_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0x55 }, UD_F_ANY_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0x56 }, UD_F_ANY_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0x57 }, UD_F_ANY_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0x58 }, UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0x59 }, UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0x5a }, UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0x5b }, UD_F_ANY_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0x5c }, UD_F_ANY_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0x5e }, UD_F_ANY_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0x5d }, UD_F_ANY_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0x5f }, UD_F_ANY_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0x60 }, UD_F_ANY_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0x61 }, UD_F_ANY_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0x62 }, UD_F_ANY_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0x63 }, UD_F_ANY_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0x64 }, UD_F_ANY_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0x65 }, UD_F_ANY_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0x66 }, UD_F_ANY_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0x67 }, UD_F_ANY_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0x68 }, UD_F_ANY_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0x69 }, UD_F_ANY_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0x6a }, UD_F_ANY_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0x6b }, UD_F_ANY_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0x6c }, UD_F_ANY_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0x6d }, UD_F_ANY_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0x6e }, UD_F_ANY_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0x6f }, UD_F_ANY_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0x70 }, UD_F_ANY_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0x71 }, UD_F_ANY_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0x72 }, UD_F_ANY_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0x73 }, UD_F_ANY_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0x74 }, UD_F_ANY_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0x75 }, UD_F_ANY_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0x76 }, UD_F_ANY_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0x77 }, UD_F_ANY_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0x78 }, UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0x79 }, UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0x7a }, UD_F_ANY_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0x7b }, UD_F_ANY_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0x7c }, UD_F_ANY_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0x7d }, UD_F_ANY_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0x7e }, UD_F_ANY_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0x7f }, UD_F_ANY_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0x80 }, UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0x81 }, UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0x82 }, UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0x83 }, UD_F_ANY_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0x84 }, UD_F_ANY_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0x85 }, UD_F_ANY_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0x86 }, UD_F_ANY_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0x87 }, UD_F_ANY_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0x88 }, UD_F_ANY_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0x89 }, UD_F_ANY_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0x8a }, UD_F_ANY_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0x8b }, UD_F_ANY_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0x8c }, UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0x8d }, UD_F_ANY_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0x8e }, UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0x8f }, UD_F_ANY_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0x90 }, UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0x91 }, UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0x92 }, UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0x93 }, UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0x94 }, UD_F_ANY_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0x95 }, UD_F_ANY_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0x96 }, UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0x97 }, UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0x98 }, UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0x99 }, UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0x9a }, UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0x9b }, UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0x9c }, UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0x9d }, UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0x9e }, UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0x9f }, UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0xa0 }, UD_F_ANY_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0xa1 }, UD_F_ANY_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0xa2 }, UD_F_ANY_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0xa3 }, UD_F_ANY_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0xa4 }, UD_F_ANY_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0xa5 }, UD_F_ANY_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0xa6 }, UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0xa7 }, UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0xa8 }, UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0xa9 }, UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0xaa }, UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0xab }, UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0xac }, UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0xad }, UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0xae }, UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0xaf }, UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0xb0 }, UD_F_ANY_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0xb1 }, UD_F_ANY_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0xb2 }, UD_F_ANY_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0xb3 }, UD_F_ANY_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0xb4 }, UD_F_ANY_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0xb5 }, UD_F_ANY_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0xb6 }, UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0xb7 }, UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0xb8 }, UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0xb9 }, UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0xba }, UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0xbb }, UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0xbc }, UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0xbd }, UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0xbe }, UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0xbf }, UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0xc0 }, UD_F_ANY_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0xc1 }, UD_F_ANY_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0xc2 }, UD_F_ANY_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0xc3 }, UD_F_ANY_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0xc4 }, UD_F_ANY_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0xc5 }, UD_F_ANY_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0xc6 }, UD_F_ANY_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0xc7 }, UD_F_ANY_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0xc8 }, UD_F_NOT_NO_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0xc9 }, UD_F_NOT_NO_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0xca }, UD_F_NOT_NO_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0xcb }, UD_F_NOT_NO_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0xcc }, UD_F_NOT_NO_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0xcd }, UD_F_NOT_NO_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0xce }, UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0xcf }, UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0xd0 }, UD_F_ANY_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0xd1 }, UD_F_ANY_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0xd2 }, UD_F_ANY_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0xd3 }, UD_F_ANY_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0xd4 }, UD_F_ANY_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0xd5 }, UD_F_ANY_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0xd6 }, UD_F_ANY_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0xd7 }, UD_F_ANY_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0xd8 }, UD_F_ANY_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0xd9 }, UD_F_ANY_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0xda }, UD_F_ANY_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0xdb }, UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0xdc }, UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0xdd }, UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0xde }, UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0xdf }, UD_F_NOT_OZ_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0xe0 }, UD_F_ANY_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0xe1 }, UD_F_ANY_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0xe2 }, UD_F_ANY_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0xe3 }, UD_F_ANY_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0xe4 }, UD_F_ANY_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0xe5 }, UD_F_ANY_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0xe6 }, UD_F_ANY_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0xe7 }, UD_F_ANY_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0xe8 }, UD_F_ANY_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0xe9 }, UD_F_ANY_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0xea }, UD_F_ANY_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0xeb }, UD_F_ANY_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0xec }, UD_F_ANY_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0xed }, UD_F_ANY_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0xee }, UD_F_ANY_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0xef }, UD_F_ANY_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0xf0 }, UD_F_NOT_NO_PFX | UD_F_NOT_OZ_PFX | UD_F_NOT_RN_PFX }, /// @todo crc32 weirdness + { UD_T_MODRM, 3, { 0x0f, 0x38, 0xf1 }, UD_F_NOT_NO_PFX | UD_F_NOT_OZ_PFX | UD_F_NOT_RN_PFX }, /// @todo crc32 weirdness + { UD_T_MODRM, 3, { 0x0f, 0x38, 0xf2 }, UD_F_NOT_NO_PFX }, + + { UD_T_MODRM, 3, { 0x0f, 0x38, 0xf4 }, UD_F_ANY_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0xf5 }, UD_F_NOT_NO_PFX | UD_F_NOT_RZ_PFX | UD_F_NOT_RN_PFX }, + + { UD_T_MODRM, 3, { 0x0f, 0x38, 0xf7 }, UD_F_ANY_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0xf8 }, UD_F_ANY_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0xf9 }, UD_F_ANY_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0xfa }, UD_F_ANY_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0xfb }, UD_F_ANY_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0xfc }, UD_F_ANY_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0xfd }, UD_F_ANY_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0xfe }, UD_F_ANY_PFX }, + { UD_T_MODRM, 3, { 0x0f, 0x38, 0xff }, UD_F_ANY_PFX }, + + /* This is going to be interesting: */ + { UD_T_MODRM, 5, { 0x66, 0xf2, 0x0f, 0x38, 0xf5 }, UD_F_ANY_PFX }, + { UD_T_MODRM, 5, { 0x66, 0xf3, 0x0f, 0x38, 0xf5 }, UD_F_ANY_PFX }, + { UD_T_MODRM, 5, { 0x66, 0xf2, 0x0f, 0x38, 0xf6 }, UD_F_ANY_PFX }, + //{ UD_T_MODRM, 5, { 0x66, 0xf3, 0x0f, 0x38, 0xf6 }, UD_F_ANY_PFX }, - not this one. +}; + + +void DecodeUdEdgeTest(PCCPUDECODE1UDTST paTests, unsigned cTests) +{ + uint8_t BS3_FAR *pbPages; + + /* + * Detect AMD. + */ + bool fIsAmd = false; + if (g_uBs3CpuDetected & BS3CPU_F_CPUID) + fIsAmd = ASMIsAmdCpu(); + Bs3TestPrintf("fIsAmd=%d\n", fIsAmd); + + /* + * Allocate and initialize a page pair + */ + pbPages = Bs3MemGuardedTestPageAlloc(BS3MEMKIND_FLAT32); + if (pbPages) + { + unsigned iTest; + BS3REGCTX Ctx; + BS3REGCTX ExpectCtx; + BS3TRAPFRAME TrapFrame; + uint32_t iStep; + + Bs3MemZero(&Ctx, sizeof(Ctx)); + Bs3MemZero(&ExpectCtx, sizeof(ExpectCtx)); + Bs3MemZero(&TrapFrame, sizeof(TrapFrame)); + + /* Enable SSE. */ + ASMSetCR0((ASMGetCR0() & ~(X86_CR0_EM | X86_CR0_TS)) | X86_CR0_MP); + ASMSetCR4(ASMGetCR4() | X86_CR4_OSFXSR); + + /* Create a test context. */ + Bs3RegCtxSaveEx(&Ctx, BS3_MODE_CODE_32, 512); + Ctx.rbx.u = (uintptr_t)pbPages; + Ctx.rcx.u = (uintptr_t)pbPages; + Ctx.rdx.u = (uintptr_t)pbPages; + Ctx.rax.u = (uintptr_t)pbPages; + Ctx.rbp.u = (uintptr_t)pbPages; + Ctx.rsi.u = (uintptr_t)pbPages; + Ctx.rdi.u = (uintptr_t)pbPages; + + Bs3MemCpy(&ExpectCtx, &Ctx, sizeof(ExpectCtx)); + ExpectCtx.rflags.u32 |= X86_EFL_RF; + + /* Loop thru the tests. */ + iStep = g_usBs3TestStep = 0; + for (iTest = 0; iTest < cTests; iTest++) + { + typedef struct CPUDECODE1UDSEQ + { + uint8_t cb; + uint8_t ab[10]; + uint8_t fIncompatible; + } CPUDECODE1UDSEQ; + typedef CPUDECODE1UDSEQ const BS3_FAR *PCCPUDECODE1UDSEQ; + + static CPUDECODE1UDSEQ const s_aPrefixes[] = + { + { 0, { 0 }, UD_F_NOT_NO_PFX }, + { 1, { P_OZ }, UD_F_NOT_OZ_PFX }, + { 1, { P_RN }, UD_F_NOT_RN_PFX }, + { 1, { P_RZ }, UD_F_NOT_RZ_PFX }, + { 1, { P_LK }, UD_F_NOT_LK_PFX }, + { 2, { P_OZ, P_OZ }, UD_F_NOT_OZ_PFX | UD_F_NOT_OZ_PFX }, + { 2, { P_RN, P_OZ }, UD_F_NOT_RN_PFX | UD_F_NOT_OZ_PFX }, + { 2, { P_RZ, P_OZ }, UD_F_NOT_RZ_PFX | UD_F_NOT_OZ_PFX }, + { 2, { P_LK, P_OZ }, UD_F_NOT_LK_PFX | UD_F_NOT_OZ_PFX }, + { 2, { P_OZ, P_RN }, UD_F_NOT_OZ_PFX | UD_F_NOT_RN_PFX }, + { 2, { P_RN, P_RN }, UD_F_NOT_RN_PFX | UD_F_NOT_RN_PFX }, + { 2, { P_RZ, P_RN }, UD_F_NOT_RZ_PFX | UD_F_NOT_RN_PFX }, + { 2, { P_LK, P_RN }, UD_F_NOT_LK_PFX | UD_F_NOT_RN_PFX }, + { 2, { P_OZ, P_RZ }, UD_F_NOT_OZ_PFX | UD_F_NOT_RZ_PFX }, + { 2, { P_RN, P_RZ }, UD_F_NOT_RN_PFX | UD_F_NOT_RZ_PFX }, + { 2, { P_RZ, P_RZ }, UD_F_NOT_RZ_PFX | UD_F_NOT_RZ_PFX }, + { 2, { P_LK, P_RZ }, UD_F_NOT_LK_PFX | UD_F_NOT_RZ_PFX }, + { 2, { P_OZ, P_LK }, UD_F_NOT_OZ_PFX | UD_F_NOT_LK_PFX }, + { 2, { P_RN, P_LK }, UD_F_NOT_RN_PFX | UD_F_NOT_LK_PFX }, + { 2, { P_RZ, P_LK }, UD_F_NOT_RZ_PFX | UD_F_NOT_LK_PFX }, + { 2, { P_LK, P_LK }, UD_F_NOT_LK_PFX | UD_F_NOT_LK_PFX }, + }; + + static CPUDECODE1UDSEQ const s_aExact[] = { { 0, { 0 }, 0 } }; + static CPUDECODE1UDSEQ const s_aModRm[] = + { + { 1, { RM_EAX_EAX, }, 0 }, + /* Mem forms (hardcoded indexed later): */ + { 2, { RM_EAX_DEREF_EBX_DISP8, 0 }, 0 }, + { 5, { RM_EAX_DEREF_EBX_DISP32, 0, 0, 0, 0 }, 0 }, + { 2, { RM_EAX_SIB, SIB_EBX_X1_NONE, }, 0 }, + { 3, { RM_EAX_SIB_DISP8, SIB_EBX_X1_NONE, 0 }, 0 }, + { 6, { RM_EAX_SIB_DISP32, SIB_EBX_X1_NONE, 0, 0, 0, 0 }, 0 }, + }; + static CPUDECODE1UDSEQ const s_aModRmImm8[] = + { + { 1 + 1, { RM_EAX_EAX, 0x11 }, 0 }, + /* Mem forms (hardcoded indexed later): */ + { 2 + 1, { RM_EAX_DEREF_EBX_DISP8, 0, 0x11 }, 0 }, + { 5 + 1, { RM_EAX_DEREF_EBX_DISP32, 0, 0, 0, 0, 0x11 }, 0 }, + { 2 + 1, { RM_EAX_SIB, SIB_EBX_X1_NONE, 0x11 }, 0 }, + { 3 + 1, { RM_EAX_SIB_DISP8, SIB_EBX_X1_NONE, 0, 0x11 }, 0 }, + { 6 + 1, { RM_EAX_SIB_DISP32, SIB_EBX_X1_NONE, 0, 0, 0, 0, 0x11 }, 0 }, + }; + static CPUDECODE1UDSEQ const s_aModRmRRx[] = + { + { 1, { RM_EAX_EAX, }, 0 }, + { 1, { RM_ECX_EAX, }, 0 }, + { 1, { RM_EDX_EAX, }, 0 }, + { 1, { RM_EBX_EAX, }, 0 }, + { 1, { RM_ESP_EAX, }, 0 }, + { 1, { RM_EBP_EAX, }, 0 }, + { 1, { RM_ESI_EAX, }, 0 }, + { 1, { RM_EDI_EAX, }, 0 }, + }; + static CPUDECODE1UDSEQ const s_aModRmRRxImm8[] = + { + { 2, { RM_EAX_EAX, 0x11 }, 0 }, + { 2, { RM_ECX_EAX, 0x11 }, 0 }, + { 2, { RM_EDX_EAX, 0x11 }, 0 }, + { 2, { RM_EBX_EAX, 0x11 }, 0 }, + { 2, { RM_ESP_EAX, 0x11 }, 0 }, + { 2, { RM_EBP_EAX, 0x11 }, 0 }, + { 2, { RM_ESI_EAX, 0x11 }, 0 }, + { 2, { RM_EDI_EAX, 0x11 }, 0 }, + }; + static CPUDECODE1UDSEQ const s_aModRmMRx[] = /* index*5 */ + { + { 2, { RM_EAX_DEREF_EBX_DISP8, 0 }, 0 }, + { 5, { RM_EAX_DEREF_EBX_DISP32, 0, 0, 0, 0 }, 0 }, + { 2, { RM_EAX_SIB, SIB_EBX_X1_NONE, }, 0 }, + { 3, { RM_EAX_SIB_DISP8, SIB_EBX_X1_NONE, 0 }, 0 }, + { 6, { RM_EAX_SIB_DISP32, SIB_EBX_X1_NONE, 0, 0, 0, 0 }, 0 }, + + { 2, { RM_ECX_DEREF_EBX_DISP8, 0 }, 0 }, + { 5, { RM_ECX_DEREF_EBX_DISP32, 0, 0, 0, 0 }, 0 }, + { 2, { RM_ECX_SIB, SIB_EBX_X1_NONE, }, 0 }, + { 3, { RM_ECX_SIB_DISP8, SIB_EBX_X1_NONE, 0 }, 0 }, + { 6, { RM_ECX_SIB_DISP32, SIB_EBX_X1_NONE, 0, 0, 0, 0 }, 0 }, + + { 2, { RM_EDX_DEREF_EBX_DISP8, 0 }, 0 }, + { 5, { RM_EDX_DEREF_EBX_DISP32, 0, 0, 0, 0 }, 0 }, + { 2, { RM_EDX_SIB, SIB_EBX_X1_NONE, }, 0 }, + { 3, { RM_EDX_SIB_DISP8, SIB_EBX_X1_NONE, 0 }, 0 }, + { 6, { RM_EDX_SIB_DISP32, SIB_EBX_X1_NONE, 0, 0, 0, 0 }, 0 }, + + { 2, { RM_EBX_DEREF_EBX_DISP8, 0 }, 0 }, + { 5, { RM_EBX_DEREF_EBX_DISP32, 0, 0, 0, 0 }, 0 }, + { 2, { RM_EBX_SIB, SIB_EBX_X1_NONE, }, 0 }, + { 3, { RM_EBX_SIB_DISP8, SIB_EBX_X1_NONE, 0 }, 0 }, + { 6, { RM_EBX_SIB_DISP32, SIB_EBX_X1_NONE, 0, 0, 0, 0 }, 0 }, + + { 2, { RM_ESP_DEREF_EBX_DISP8, 0 }, 0 }, + { 5, { RM_ESP_DEREF_EBX_DISP32, 0, 0, 0, 0 }, 0 }, + { 2, { RM_ESP_SIB, SIB_EBX_X1_NONE, }, 0 }, + { 3, { RM_ESP_SIB_DISP8, SIB_EBX_X1_NONE, 0 }, 0 }, + { 6, { RM_ESP_SIB_DISP32, SIB_EBX_X1_NONE, 0, 0, 0, 0 }, 0 }, + + { 2, { RM_EBP_DEREF_EBX_DISP8, 0 }, 0 }, + { 5, { RM_EBP_DEREF_EBX_DISP32, 0, 0, 0, 0 }, 0 }, + { 2, { RM_EBP_SIB, SIB_EBX_X1_NONE, }, 0 }, + { 3, { RM_EBP_SIB_DISP8, SIB_EBX_X1_NONE, 0 }, 0 }, + { 6, { RM_EBP_SIB_DISP32, SIB_EBX_X1_NONE, 0, 0, 0, 0 }, 0 }, + + { 2, { RM_ESI_DEREF_EBX_DISP8, 0 }, 0 }, + { 5, { RM_ESI_DEREF_EBX_DISP32, 0, 0, 0, 0 }, 0 }, + { 2, { RM_ESI_SIB, SIB_EBX_X1_NONE, }, 0 }, + { 3, { RM_ESI_SIB_DISP8, SIB_EBX_X1_NONE, 0 }, 0 }, + { 6, { RM_ESI_SIB_DISP32, SIB_EBX_X1_NONE, 0, 0, 0, 0 }, 0 }, + + { 2, { RM_EDI_DEREF_EBX_DISP8, 0 }, 0 }, + { 5, { RM_EDI_DEREF_EBX_DISP32, 0, 0, 0, 0 }, 0 }, + { 2, { RM_EDI_SIB, SIB_EBX_X1_NONE, }, 0 }, + { 3, { RM_EDI_SIB_DISP8, SIB_EBX_X1_NONE, 0 }, 0 }, + { 6, { RM_EDI_SIB_DISP32, SIB_EBX_X1_NONE, 0, 0, 0, 0 }, 0 }, + }; + static CPUDECODE1UDSEQ const s_aModRmMRxImm8[] = /* index*5 */ + { + { 2+1, { RM_EAX_DEREF_EBX_DISP8, 0, 0x11 }, 0 }, + { 5+1, { RM_EAX_DEREF_EBX_DISP32, 0, 0, 0, 0, 0x11 }, 0 }, + { 2+1, { RM_EAX_SIB, SIB_EBX_X1_NONE, 0x11 }, 0 }, + { 3+1, { RM_EAX_SIB_DISP8, SIB_EBX_X1_NONE, 0, 0x11 }, 0 }, + { 6+1, { RM_EAX_SIB_DISP32, SIB_EBX_X1_NONE, 0, 0, 0, 0, 0x11 }, 0 }, + + { 2+1, { RM_ECX_DEREF_EBX_DISP8, 0, 0x11 }, 0 }, + { 5+1, { RM_ECX_DEREF_EBX_DISP32, 0, 0, 0, 0, 0x11 }, 0 }, + { 2+1, { RM_ECX_SIB, SIB_EBX_X1_NONE, 0x11 }, 0 }, + { 3+1, { RM_ECX_SIB_DISP8, SIB_EBX_X1_NONE, 0, 0x11 }, 0 }, + { 6+1, { RM_ECX_SIB_DISP32, SIB_EBX_X1_NONE, 0, 0, 0, 0, 0x11 }, 0 }, + + { 2+1, { RM_EDX_DEREF_EBX_DISP8, 0, 0x11 }, 0 }, + { 5+1, { RM_EDX_DEREF_EBX_DISP32, 0, 0, 0, 0, 0x11 }, 0 }, + { 2+1, { RM_EDX_SIB, SIB_EBX_X1_NONE, 0x11 }, 0 }, + { 3+1, { RM_EDX_SIB_DISP8, SIB_EBX_X1_NONE, 0, 0x11 }, 0 }, + { 6+1, { RM_EDX_SIB_DISP32, SIB_EBX_X1_NONE, 0, 0, 0, 0, 0x11 }, 0 }, + + { 2+1, { RM_EBX_DEREF_EBX_DISP8, 0, 0x11 }, 0 }, + { 5+1, { RM_EBX_DEREF_EBX_DISP32, 0, 0, 0, 0, 0x11 }, 0 }, + { 2+1, { RM_EBX_SIB, SIB_EBX_X1_NONE, 0x11 }, 0 }, + { 3+1, { RM_EBX_SIB_DISP8, SIB_EBX_X1_NONE, 0, 0x11 }, 0 }, + { 6+1, { RM_EBX_SIB_DISP32, SIB_EBX_X1_NONE, 0, 0, 0, 0, 0x11 }, 0 }, + + { 2+1, { RM_ESP_DEREF_EBX_DISP8, 0, 0x11 }, 0 }, + { 5+1, { RM_ESP_DEREF_EBX_DISP32, 0, 0, 0, 0, 0x11 }, 0 }, + { 2+1, { RM_ESP_SIB, SIB_EBX_X1_NONE, 0x11 }, 0 }, + { 3+1, { RM_ESP_SIB_DISP8, SIB_EBX_X1_NONE, 0, 0x11 }, 0 }, + { 6+1, { RM_ESP_SIB_DISP32, SIB_EBX_X1_NONE, 0, 0, 0, 0, 0x11 }, 0 }, + + { 2+1, { RM_EBP_DEREF_EBX_DISP8, 0, 0x11 }, 0 }, + { 5+1, { RM_EBP_DEREF_EBX_DISP32, 0, 0, 0, 0, 0x11 }, 0 }, + { 2+1, { RM_EBP_SIB, SIB_EBX_X1_NONE, 0x11 }, 0 }, + { 3+1, { RM_EBP_SIB_DISP8, SIB_EBX_X1_NONE, 0, 0x11 }, 0 }, + { 6+1, { RM_EBP_SIB_DISP32, SIB_EBX_X1_NONE, 0, 0, 0, 0, 0x11 }, 0 }, + + { 2+1, { RM_ESI_DEREF_EBX_DISP8, 0, 0x11 }, 0 }, + { 5+1, { RM_ESI_DEREF_EBX_DISP32, 0, 0, 0, 0, 0x11 }, 0 }, + { 2+1, { RM_ESI_SIB, SIB_EBX_X1_NONE, 0x11 }, 0 }, + { 3+1, { RM_ESI_SIB_DISP8, SIB_EBX_X1_NONE, 0, 0x11 }, 0 }, + { 6+1, { RM_ESI_SIB_DISP32, SIB_EBX_X1_NONE, 0, 0, 0, 0, 0x11 }, 0 }, + + { 2+1, { RM_EDI_DEREF_EBX_DISP8, 0, 0x11 }, 0 }, + { 5+1, { RM_EDI_DEREF_EBX_DISP32, 0, 0, 0, 0, 0x11 }, 0 }, + { 2+1, { RM_EDI_SIB, SIB_EBX_X1_NONE, 0x11 }, 0 }, + { 3+1, { RM_EDI_SIB_DISP8, SIB_EBX_X1_NONE, 0, 0x11 }, 0 }, + { 6+1, { RM_EDI_SIB_DISP32, SIB_EBX_X1_NONE, 0, 0, 0, 0, 0x11 }, 0 }, + }; + unsigned iPrefix; + unsigned cSuffixes; + PCCPUDECODE1UDSEQ paSuffixes; + unsigned const cSubTabEntries = paTests[iTest].fFlags & UD_F_3BYTE_ESC ? 256 : 1; + unsigned cImmEntries = 1; + + /* + * Skip if implemented. + */ + + /* + * Produce a number of opcode sequences by varying the prefixes and + * ModR/M parts. Each opcode sequence is then treated to the edge test. + */ + switch (paTests[iTest].enmType) + { + case UD_T_EXACT: + l_case_exact: + cSuffixes = RT_ELEMENTS(s_aExact); + paSuffixes = s_aExact; + break; + case UD_T_MODRM | UD_T_NOAMD: + if (fIsAmd) + goto l_case_exact; + case UD_T_MODRM: + cSuffixes = RT_ELEMENTS(s_aModRm); + paSuffixes = s_aModRm; + break; + case UD_T_MODRM_I8: + cSuffixes = RT_ELEMENTS(s_aModRmImm8); + paSuffixes = s_aModRmImm8; + cImmEntries = 256; + break; + case UD_T_MODRM_M: + cSuffixes = RT_ELEMENTS(s_aModRm) - 1; + paSuffixes = &s_aModRm[1]; + break; + case UD_T_MODRM_M_I8: + cSuffixes = RT_ELEMENTS(s_aModRmImm8) - 1; + paSuffixes = &s_aModRmImm8[1]; + break; + case UD_T_MODRM_RR0: + case UD_T_MODRM_RR1: + case UD_T_MODRM_RR2: + case UD_T_MODRM_RR3: + case UD_T_MODRM_RR4: + case UD_T_MODRM_RR5: + case UD_T_MODRM_RR6: + case UD_T_MODRM_RR7: + cSuffixes = 1; + paSuffixes = &s_aModRmRRx[paTests[iTest].enmType - UD_T_MODRM_RR0]; + break; + case UD_T_MODRM_RR0_I8: + case UD_T_MODRM_RR1_I8: + case UD_T_MODRM_RR2_I8: + case UD_T_MODRM_RR3_I8: + case UD_T_MODRM_RR4_I8: + case UD_T_MODRM_RR5_I8: + case UD_T_MODRM_RR6_I8: + case UD_T_MODRM_RR7_I8: + cSuffixes = 1; + paSuffixes = &s_aModRmRRxImm8[paTests[iTest].enmType - UD_T_MODRM_RR0_I8]; + break; + case UD_T_MODRM_MR0: + case UD_T_MODRM_MR1: + case UD_T_MODRM_MR2: + case UD_T_MODRM_MR3: + case UD_T_MODRM_MR4: + case UD_T_MODRM_MR5: + case UD_T_MODRM_MR6: + case UD_T_MODRM_MR7: + cSuffixes = 5; + paSuffixes = &s_aModRmMRx[(paTests[iTest].enmType - UD_T_MODRM_MR0) * 5]; + break; + case UD_T_MODRM_MR0_I8: + case UD_T_MODRM_MR1_I8: + case UD_T_MODRM_MR2_I8: + case UD_T_MODRM_MR3_I8: + case UD_T_MODRM_MR4_I8: + case UD_T_MODRM_MR5_I8: + case UD_T_MODRM_MR6_I8: + case UD_T_MODRM_MR7_I8: + cSuffixes = 5; + paSuffixes = &s_aModRmMRxImm8[(paTests[iTest].enmType - UD_T_MODRM_MR0_I8) * 5]; + break; + default: + Bs3TestPrintf("#%u: enmType=%d\n", paTests[iTest].enmType); + continue; + } + + for (iPrefix = 0; iPrefix < RT_ELEMENTS(s_aPrefixes); iPrefix++) + if (!(s_aPrefixes[iPrefix].fIncompatible & paTests[iTest].fFlags)) + { + unsigned iSubTab; + unsigned cbOpcodesLead; + uint8_t abOpcodes[32]; + + Bs3MemCpy(&abOpcodes[0], &s_aPrefixes[iPrefix].ab[0], s_aPrefixes[iPrefix].cb); + cbOpcodesLead = s_aPrefixes[iPrefix].cb; + Bs3MemCpy(&abOpcodes[cbOpcodesLead], &paTests[iTest].abOpcodes[0], paTests[iTest].cbOpcodes); + cbOpcodesLead += paTests[iTest].cbOpcodes; + + for (iSubTab = 0; iSubTab < cSubTabEntries; iSubTab++) + { + unsigned iSuffix; + + if (cSubTabEntries > 1) + abOpcodes[cbOpcodesLead - 1] = iSubTab; + + for (iSuffix = 0; iSuffix < cSuffixes; iSuffix++) + if (!(paSuffixes[iSuffix].fIncompatible & paTests[iTest].fFlags)) + { + unsigned const cbOpcodes = cbOpcodesLead + paSuffixes[iSuffix].cb; + unsigned cbOpcodesMin = 1; + unsigned iImm; + Bs3MemCpy(&abOpcodes[cbOpcodesLead], paSuffixes[iSuffix].ab, paSuffixes[iSuffix].cb); + + for (iImm = 0; iImm < cImmEntries; iImm++) + { + unsigned cb; + + if (cImmEntries > 1) + abOpcodes[cbOpcodes - 1] = iImm; + + /* + * Do the edge thing. + */ + cb = cbOpcodes; + while (cb >= cbOpcodesMin) + { + uint8_t BS3_FAR *pbRip = &pbPages[X86_PAGE_SIZE - cb]; + uint8_t bXcptExpected; + + Bs3RegCtxSetRipCsFromFlat(&Ctx, (uintptr_t)pbRip); + ExpectCtx.rip = Ctx.rip; + ExpectCtx.cs = Ctx.cs; + if (cb >= cbOpcodes) + { + ExpectCtx.cr2 = Ctx.cr2; + bXcptExpected = X86_XCPT_UD; + } + else + { + ExpectCtx.cr2.u = (uintptr_t)&pbPages[X86_PAGE_SIZE]; + bXcptExpected = X86_XCPT_PF; + } + + Bs3MemCpy(pbRip, &abOpcodes[0], cb); + Bs3TrapSetJmpAndRestore(&Ctx, &TrapFrame); +#if 0 + Bs3TestPrintf("iTest=%d iPrefix=%d (%d/%#x) iSubTab=%d iSuffix=%d (%d/%#x) iImm=%d cb=%d cbOp=%d: %.*Rhxs\n", + iTest, iPrefix, s_aPrefixes[iPrefix].cb, s_aPrefixes[iPrefix].fIncompatible, + iSubTab, iSuffix, paSuffixes[iSuffix].cb, paSuffixes[iSuffix].fIncompatible, iImm, + cb, cbOpcodes, + cbOpcodes, abOpcodes); +#endif + + if ( !Bs3TestCheckRegCtxEx(&TrapFrame.Ctx, &ExpectCtx, 0 /*cbPcAdjust*/, + 0 /*cbSpAdjust*/, 0 /*fExtraEfl*/, "mode", 0) + || TrapFrame.bXcpt != bXcptExpected) + { + Bs3TestFailedF("iTest=%d iPrefix=%d (%d/%#x) iSubTab=%u iSuffix=%d (%d/%#x) cb=%d cbOp=%d: %.*Rhxs\n", + iTest, iPrefix, s_aPrefixes[iPrefix].cb, s_aPrefixes[iPrefix].fIncompatible, + iSubTab, iSuffix, paSuffixes[iSuffix].cb, paSuffixes[iSuffix].fIncompatible, + cb, cbOpcodes, + cbOpcodes, abOpcodes); + if (TrapFrame.bXcpt != bXcptExpected) + Bs3TestFailedF("Expected bXcpt=%#x got %#x\n", bXcptExpected, TrapFrame.bXcpt); + Bs3TrapPrintFrame(&TrapFrame); + Bs3Shutdown(); + } + + /* next */ + g_usBs3TestStep++; + iStep++; + cb--; + } + + /* For iImm > 0 only test cb == cbOpcode since the byte isn't included when cb < cbOpcode. */ + cbOpcodesMin = cbOpcodes; + } + } + } + } + } + Bs3TestPrintf("%RI32 (%#RX32) test steps\n", iStep, iStep); + + Bs3MemGuardedTestPageFree(pbPages); + } + else + Bs3TestFailed("Failed to allocate two pages!\n"); +} + + +#if 0 +/** + * Checks how prefixes affects cmpxchg8b and cmpxchg16b + * + * The thing here is that the intel opcode tables indicates that the 66 and f3 + * prefixes encodings are reserved and causes \#UD, where AMD doesn't. Seems + * though that the f2, f3 and 66 prefixes are ignored on skylake intel. Need to + * make sure this is the case, also in 64-bit mode and for the 16b version. + */ +static void DecodeCmpXchg8bVs16b(void) +{ + uint8_t BS3_FAR *pbPages; + + /* Check that the instructions are supported. */ + if ( !(g_uBs3CpuDetected & BS3CPU_F_CPUID) + || !(ASMCpuId_EDX(1) & X86_CPUID_FEATURE_EDX_CX8)) + { + Bs3TestSkipped("not supported"); + return; + } + + /* Setup a guarded page. */ + pbPages = Bs3MemGuardedTestPageAlloc(BS3MEMKIND_FLAT32); + if (pbPages) + { + + Bs3MemGuardedTestPageFree(pbPages); + } + else + Bs3TestFailed("Failed to allocate two pages!\n"); +} +#endif + + +/** + * Checks various prefix encodings with the MOVBE and CRC32 instructions to try + * figure out how they are decoded. + * + * The issue here is that both MOVBE and CRC32 are sensitive to the operand size + * prefix, which helps us identify whether the F2h and F3h prefixes takes + * precedence over 66h in this case. (As it turned out they do and it order + * doesn't matter.) + */ +static void DecodeMovbeVsCrc32(void) +{ + uint8_t BS3_FAR *pbPages; + + /* Check that the instructions are supported. */ + if ( !(g_uBs3CpuDetected & BS3CPU_F_CPUID) + || (ASMCpuId_ECX(1) & (X86_CPUID_FEATURE_ECX_MOVBE | X86_CPUID_FEATURE_ECX_SSE4_2)) + != (X86_CPUID_FEATURE_ECX_MOVBE | X86_CPUID_FEATURE_ECX_SSE4_2) ) + { + Bs3TestSkipped("not supported"); + return; + } + + /* Setup a guarded page. */ + pbPages = Bs3MemGuardedTestPageAlloc(BS3MEMKIND_FLAT32); + if (pbPages) + { + unsigned iTest; + BS3REGCTX Ctx; + BS3TRAPFRAME TrapFrame; + BS3REGCTX ExpectCtxMovbe_m32_eax; /* 0f 38 f1 /r */ + BS3REGCTX ExpectCtxMovbe_m16_ax; /* 66 0f 38 f1 /r */ + BS3REGCTX ExpectCtxCrc32_eax_m32; /* f2 0f 38 f1 /r */ + BS3REGCTX ExpectCtxCrc32_eax_m16; /* 66 f2 0f 38 f1 /r */ + BS3REGCTX ExpectCtxUd; + PBS3REGCTX apExpectCtxs[5]; + static const struct + { + uint32_t u32Stored; + uint8_t iExpectCtx; + uint8_t bXcpt; + uint8_t cbOpcodes; + uint8_t abOpcodes[18]; + } s_aTests[] = + { +#define BECRC_EAX UINT32_C(0x11223344) +#define BECRC_MEM_ORG UINT32_C(0x55667788) +#define BECRC_MEM_BE16 UINT32_C(0x55664433) +#define BECRC_MEM_BE32 UINT32_C(0x44332211) + + /* base forms. */ + { BECRC_MEM_BE32, 0, X86_XCPT_PF, 4, { 0x0f, 0x38, 0xf1, RM_EAX_DEREF_EBX } }, + { BECRC_MEM_BE16, 1, X86_XCPT_PF, 5, { P_OZ, 0x0f, 0x38, 0xf1, RM_EAX_DEREF_EBX } }, + { BECRC_MEM_ORG, 2, X86_XCPT_PF, 5, { P_RN, 0x0f, 0x38, 0xf1, RM_EAX_DEREF_EBX } }, + { BECRC_MEM_ORG, 3, X86_XCPT_PF, 6, { P_OZ, P_RN, 0x0f, 0x38, 0xf1, RM_EAX_DEREF_EBX } }, + { BECRC_MEM_ORG, 4, X86_XCPT_UD, 5, { P_RZ, 0x0f, 0x38, 0xf1, RM_EAX_DEREF_EBX } }, /* undefined F3 (P_RZ) */ + { BECRC_MEM_ORG, 4, X86_XCPT_UD, 6, { P_OZ, P_RZ, 0x0f, 0x38, 0xf1, RM_EAX_DEREF_EBX } }, /* undefined F3 (P_RZ) */ + + /* CRC32 eax, [word ebx]: Simple variations showing it doesn't matter where the prefixes are placed. */ + { BECRC_MEM_ORG, 3, X86_XCPT_PF, 6, { P_RN, P_OZ, 0x0f, 0x38, 0xf1, RM_EAX_DEREF_EBX } }, + { BECRC_MEM_ORG, 3, X86_XCPT_PF, 7, { P_RN, P_OZ, P_ES, 0x0f, 0x38, 0xf1, RM_EAX_DEREF_EBX } }, + { BECRC_MEM_ORG, 3, X86_XCPT_PF, 8, { P_RN, P_SS, P_OZ, P_ES, 0x0f, 0x38, 0xf1, RM_EAX_DEREF_EBX } }, + { BECRC_MEM_ORG, 3, X86_XCPT_PF, 8, { P_RN, P_SS, P_ES, P_OZ, 0x0f, 0x38, 0xf1, RM_EAX_DEREF_EBX } }, + { BECRC_MEM_ORG, 3, X86_XCPT_PF, 8, { P_SS, P_RN, P_ES, P_OZ, 0x0f, 0x38, 0xf1, RM_EAX_DEREF_EBX } }, + { BECRC_MEM_ORG, 3, X86_XCPT_PF, 8, { P_SS, P_ES, P_RN, P_OZ, 0x0f, 0x38, 0xf1, RM_EAX_DEREF_EBX } }, + { BECRC_MEM_ORG, 3, X86_XCPT_PF, 8, { P_SS, P_ES, P_OZ, P_RN, 0x0f, 0x38, 0xf1, RM_EAX_DEREF_EBX } }, + { BECRC_MEM_ORG, 3, X86_XCPT_PF, 8, { P_SS, P_OZ, P_ES, P_RN, 0x0f, 0x38, 0xf1, RM_EAX_DEREF_EBX } }, + { BECRC_MEM_ORG, 3, X86_XCPT_PF, 8, { P_OZ, P_SS, P_ES, P_RN, 0x0f, 0x38, 0xf1, RM_EAX_DEREF_EBX } }, + + /* CRC32 eax, [word ebx]: Throw the F3h prefix into the mix. The last of F3 and F2 wins on skylake+jaguar. */ + { BECRC_MEM_ORG, 3, X86_XCPT_PF, 7, { P_RZ, P_OZ, P_RN, 0x0f, 0x38, 0xf1, RM_EAX_DEREF_EBX } }, + { BECRC_MEM_ORG, 3, X86_XCPT_PF, 7, { P_OZ, P_RZ, P_RN, 0x0f, 0x38, 0xf1, RM_EAX_DEREF_EBX } }, + { BECRC_MEM_ORG, 4, X86_XCPT_UD, 7, { P_OZ, P_RN, P_RZ, 0x0f, 0x38, 0xf1, RM_EAX_DEREF_EBX } }, + { BECRC_MEM_ORG, 3, X86_XCPT_PF, 8, { P_OZ, P_RN, P_RZ, P_RN, 0x0f, 0x38, 0xf1, RM_EAX_DEREF_EBX } }, + { BECRC_MEM_ORG, 3, X86_XCPT_PF, 8, { P_RN, P_RZ, P_OZ, P_RN, 0x0f, 0x38, 0xf1, RM_EAX_DEREF_EBX } }, + { BECRC_MEM_ORG, 3, X86_XCPT_PF, 8, { P_RN, P_RZ, P_RN, P_OZ, 0x0f, 0x38, 0xf1, RM_EAX_DEREF_EBX } }, + + { BECRC_MEM_ORG, 4, X86_XCPT_UD, 7, { P_OZ, P_RN, P_RZ, 0x0f, 0x38, 0xf1, RM_EAX_DEREF_EBX } }, + }; + + apExpectCtxs[0] = &ExpectCtxMovbe_m32_eax; + apExpectCtxs[1] = &ExpectCtxMovbe_m16_ax; + apExpectCtxs[2] = &ExpectCtxCrc32_eax_m32; + apExpectCtxs[3] = &ExpectCtxCrc32_eax_m16; + apExpectCtxs[4] = &ExpectCtxUd; + + Bs3MemZero(&Ctx, sizeof(Ctx)); + Bs3MemZero(&ExpectCtxMovbe_m32_eax, sizeof(ExpectCtxMovbe_m32_eax)); + Bs3MemZero(&ExpectCtxMovbe_m16_ax, sizeof(ExpectCtxMovbe_m16_ax)); + Bs3MemZero(&ExpectCtxCrc32_eax_m32, sizeof(ExpectCtxCrc32_eax_m32)); + Bs3MemZero(&ExpectCtxCrc32_eax_m16, sizeof(ExpectCtxCrc32_eax_m16)); + Bs3MemZero(&ExpectCtxUd, sizeof(ExpectCtxUd)); + Bs3MemZero(&TrapFrame, sizeof(TrapFrame)); + + /* Create a test context. */ + Bs3RegCtxSaveEx(&Ctx, BS3_MODE_CODE_32, 512); + Ctx.rax.u = BECRC_EAX; + Ctx.rbx.u = (uintptr_t)pbPages; + + /* Create expected result contexts. */ + Bs3MemCpy(&ExpectCtxMovbe_m32_eax, &Ctx, sizeof(ExpectCtxMovbe_m32_eax)); + ExpectCtxMovbe_m32_eax.rflags.u32 |= X86_EFL_RF; + ExpectCtxMovbe_m32_eax.rip.u = (uintptr_t)&pbPages[X86_PAGE_SIZE]; + ExpectCtxMovbe_m32_eax.cr2.u = (uintptr_t)&pbPages[X86_PAGE_SIZE]; + + Bs3MemCpy(&ExpectCtxMovbe_m16_ax, &ExpectCtxMovbe_m32_eax, sizeof(ExpectCtxMovbe_m16_ax)); + + Bs3MemCpy(&ExpectCtxCrc32_eax_m32, &Ctx, sizeof(ExpectCtxCrc32_eax_m32)); + ExpectCtxCrc32_eax_m32.rflags.u32 |= X86_EFL_RF; + ExpectCtxCrc32_eax_m32.rip.u = (uintptr_t)&pbPages[X86_PAGE_SIZE]; + ExpectCtxCrc32_eax_m32.cr2.u = (uintptr_t)&pbPages[X86_PAGE_SIZE]; + ExpectCtxCrc32_eax_m32.rax.u32 = 0x1aa7cd75; + Bs3MemCpy(&ExpectCtxCrc32_eax_m16, &ExpectCtxCrc32_eax_m32, sizeof(ExpectCtxCrc32_eax_m16)); + ExpectCtxCrc32_eax_m16.rax.u32 = 0x51ab0518; + + Bs3MemCpy(&ExpectCtxUd, &Ctx, sizeof(ExpectCtxUd)); + ExpectCtxUd.rflags.u32 |= X86_EFL_RF; + + /* Loop thru the tests. */ + g_usBs3TestStep = 0; + for (iTest = 0; iTest < RT_ELEMENTS(s_aTests); iTest++) + { + unsigned const cbOpcodes = s_aTests[iTest].cbOpcodes; + uint8_t BS3_FAR *pbRip = &pbPages[X86_PAGE_SIZE - cbOpcodes]; + + Bs3MemCpy(pbRip, s_aTests[iTest].abOpcodes, cbOpcodes); + Bs3RegCtxSetRipCsFromFlat(&Ctx, (uintptr_t)pbRip); + *(uint32_t *)pbPages = BECRC_MEM_ORG; + +#if 0 + Bs3TestPrintf("iTest=%d pbRip=%p cbOpcodes=%d: %.*Rhxs\n", + iTest, pbRip, cbOpcodes, cbOpcodes, s_aTests[iTest].abOpcodes); + //Bs3RegCtxPrint(&Ctx); +#endif + Bs3TrapSetJmpAndRestore(&Ctx, &TrapFrame); + if (s_aTests[iTest].bXcpt == X86_XCPT_UD) + ExpectCtxUd.rip = Ctx.rip; + if ( !Bs3TestCheckRegCtxEx(&TrapFrame.Ctx, apExpectCtxs[s_aTests[iTest].iExpectCtx], + 0 /*cbPcAdjust*/, 0 /*cbSpAdjust*/, 0 /*fExtraEfl*/, "mode", iTest) + || TrapFrame.bXcpt != s_aTests[iTest].bXcpt + || *(uint32_t *)pbPages != s_aTests[iTest].u32Stored) + { + Bs3TestFailedF("iTest=%d cbOpcodes=%d: %.*Rhxs\n", iTest, cbOpcodes, cbOpcodes, s_aTests[iTest].abOpcodes); + if (TrapFrame.bXcpt != s_aTests[iTest].bXcpt) + Bs3TestFailedF("Expected bXcpt=%#x, got %#x\n", s_aTests[iTest].bXcpt, TrapFrame.bXcpt); + if (*(uint32_t *)pbPages != s_aTests[iTest].u32Stored) + Bs3TestFailedF("Expected %#RX32 stored at %p, found: %RX32\n", + s_aTests[iTest].u32Stored, pbPages, *(uint32_t *)pbPages); + } + } + + Bs3MemGuardedTestPageFree(pbPages); + } + else + Bs3TestFailed("Failed to allocate two pages!\n"); +} + + + +/** + * Checks various prefix encodings with the CMPPS, CMPPD, CMPSS and CMPSD + * instructions to try figure out how they are decoded. + * + * The important thing to check here is that unlike CRC32/MOVBE the operand size + * prefix (66h) is ignored when the F2h and F3h prefixes are used. We also + * check that the prefix ordering is irrelevant and that the last one of F2h and + * F3h wins. + */ +static void DecodeCmppsCmppdCmpssCmpsd(void) +{ + uint8_t BS3_FAR *pbPages; + + /* Check that the instructions are supported. */ + if ( !(g_uBs3CpuDetected & BS3CPU_F_CPUID) + || (ASMCpuId_EDX(1) & (X86_CPUID_FEATURE_EDX_SSE | X86_CPUID_FEATURE_EDX_SSE2)) + != (X86_CPUID_FEATURE_EDX_SSE | X86_CPUID_FEATURE_EDX_SSE2) ) + { + Bs3TestSkipped("SSE and/or SSE2 are not supported"); + return; + } + + /* Setup a guarded page. */ + pbPages = Bs3MemGuardedTestPageAlloc(BS3MEMKIND_FLAT32); + if (pbPages) + { + unsigned iTest; + BS3REGCTX Ctx; + BS3TRAPFRAME TrapFrame; + BS3REGCTX ExpectCtxPf; + BS3REGCTX ExpectCtxUd; + static const struct + { + RTUINT128U Xmm0Expect; + uint8_t bXcpt; + uint8_t cbOpcodes; + uint8_t abOpcodes[18]; + } s_aTests[] = + { +#define BECRC_IN_XMM1 RTUINT128_INIT_C(0x76547654bbaa9988, 0x7766554433221100) +#define BECRC_IN_XMM0 RTUINT128_INIT_C(0x765476549988bbaa, 0x7766554400112233) +#define BECRC_OUT_PS RTUINT128_INIT_C(0xffffffff00000000, 0xffffffff00000000) /* No prefix. */ +#define BECRC_OUT_PD RTUINT128_INIT_C(0x0000000000000000, 0x0000000000000000) /* P_OZ (66h) */ +#define BECRC_OUT_SS RTUINT128_INIT_C(0x765476549988bbaa, 0x7766554400000000) /* P_RZ (f3h) */ +#define BECRC_OUT_SD RTUINT128_INIT_C(0x765476549988bbaa, 0x0000000000000000) /* P_RN (f2h) */ + + /* We use imm8=0 which checks for equality, with the subvalue result being all + F's if equal and all zeros if not equal. The input values are choosen such + that the 4 variants produces different results in xmm0. */ + /* CMPPS xmm0, xmm1, 0: 0f c2 /r ib ; Compares four 32-bit subvalues. */ + /* CMPPD xmm0, xmm1, 0: 66 0f c2 /r ib ; Compares two 64-bit subvalues. */ + /* CMPSS xmm0, xmm1, 0: f3 0f c2 /r ib ; Compares two 32-bit subvalues, top 64-bit remains unchanged. */ + /* CMPSD xmm0, xmm1, 0: f2 0f c2 /r ib ; Compares one 64-bit subvalue, top 64-bit remains unchanged. */ + + /* base forms. */ + { BECRC_OUT_PS, X86_XCPT_PF, 4, { 0x0f, 0xc2, RM_XMM0_XMM1, 0 } }, + { BECRC_OUT_PD, X86_XCPT_PF, 5, { P_OZ, 0x0f, 0xc2, RM_XMM0_XMM1, 0 } }, + { BECRC_OUT_SS, X86_XCPT_PF, 5, { P_RZ, 0x0f, 0xc2, RM_XMM0_XMM1, 0 } }, + { BECRC_OUT_SD, X86_XCPT_PF, 5, { P_RN, 0x0f, 0xc2, RM_XMM0_XMM1, 0 } }, + + /* Skylake+jaguar ignores the 66h prefix with both f3h (P_RZ) and f2h (P_RN). */ + { BECRC_OUT_SS, X86_XCPT_PF, 6, { P_OZ, P_RZ, 0x0f, 0xc2, RM_XMM0_XMM1, 0 } }, + { BECRC_OUT_SS, X86_XCPT_PF, 6, { P_RZ, P_OZ, 0x0f, 0xc2, RM_XMM0_XMM1, 0 } }, + { BECRC_OUT_SD, X86_XCPT_PF, 6, { P_OZ, P_RN, 0x0f, 0xc2, RM_XMM0_XMM1, 0 } }, + { BECRC_OUT_SD, X86_XCPT_PF, 6, { P_RN, P_OZ, 0x0f, 0xc2, RM_XMM0_XMM1, 0 } }, + + /* Throw in segment prefixes and address size prefixes. */ + { BECRC_OUT_PS, X86_XCPT_PF, 5, { P_ES, 0x0f, 0xc2, RM_XMM0_XMM1, 0 } }, + { BECRC_OUT_PS, X86_XCPT_PF, 6, { P_ES, P_SS, 0x0f, 0xc2, RM_XMM0_XMM1, 0 } }, + { BECRC_OUT_PS, X86_XCPT_PF, 5, { P_AZ, 0x0f, 0xc2, RM_XMM0_XMM1, 0 } }, + { BECRC_OUT_PS, X86_XCPT_PF, 6, { P_AZ, P_CS, 0x0f, 0xc2, RM_XMM0_XMM1, 0 } }, + + { BECRC_OUT_PD, X86_XCPT_PF, 6, { P_ES, P_OZ, 0x0f, 0xc2, RM_XMM0_XMM1, 0 } }, + { BECRC_OUT_PD, X86_XCPT_PF, 6, { P_OZ, P_ES, 0x0f, 0xc2, RM_XMM0_XMM1, 0 } }, + { BECRC_OUT_PD, X86_XCPT_PF, 7, { P_ES, P_SS, P_OZ, 0x0f, 0xc2, RM_XMM0_XMM1, 0 } }, + { BECRC_OUT_PD, X86_XCPT_PF, 7, { P_ES, P_OZ, P_SS, 0x0f, 0xc2, RM_XMM0_XMM1, 0 } }, + { BECRC_OUT_PD, X86_XCPT_PF, 7, { P_OZ, P_ES, P_SS, 0x0f, 0xc2, RM_XMM0_XMM1, 0 } }, + { BECRC_OUT_PD, X86_XCPT_PF, 6, { P_AZ, P_OZ, 0x0f, 0xc2, RM_XMM0_XMM1, 0 } }, + { BECRC_OUT_PD, X86_XCPT_PF, 6, { P_OZ, P_AZ, 0x0f, 0xc2, RM_XMM0_XMM1, 0 } }, + { BECRC_OUT_PD, X86_XCPT_PF, 7, { P_AZ, P_CS, P_OZ, 0x0f, 0xc2, RM_XMM0_XMM1, 0 } }, + { BECRC_OUT_PD, X86_XCPT_PF, 7, { P_AZ, P_OZ, P_CS, 0x0f, 0xc2, RM_XMM0_XMM1, 0 } }, + { BECRC_OUT_PD, X86_XCPT_PF, 7, { P_OZ, P_AZ, P_CS, 0x0f, 0xc2, RM_XMM0_XMM1, 0 } }, + + { BECRC_OUT_SS, X86_XCPT_PF, 6, { P_ES, P_RZ, 0x0f, 0xc2, RM_XMM0_XMM1, 0 } }, + { BECRC_OUT_SS, X86_XCPT_PF, 6, { P_RZ, P_ES, 0x0f, 0xc2, RM_XMM0_XMM1, 0 } }, + { BECRC_OUT_SS, X86_XCPT_PF, 7, { P_ES, P_SS, P_RZ, 0x0f, 0xc2, RM_XMM0_XMM1, 0 } }, + { BECRC_OUT_SS, X86_XCPT_PF, 7, { P_ES, P_RZ, P_SS, 0x0f, 0xc2, RM_XMM0_XMM1, 0 } }, + { BECRC_OUT_SS, X86_XCPT_PF, 7, { P_RZ, P_ES, P_SS, 0x0f, 0xc2, RM_XMM0_XMM1, 0 } }, + { BECRC_OUT_SS, X86_XCPT_PF, 6, { P_AZ, P_RZ, 0x0f, 0xc2, RM_XMM0_XMM1, 0 } }, + { BECRC_OUT_SS, X86_XCPT_PF, 6, { P_RZ, P_AZ, 0x0f, 0xc2, RM_XMM0_XMM1, 0 } }, + { BECRC_OUT_SS, X86_XCPT_PF, 7, { P_AZ, P_CS, P_RZ, 0x0f, 0xc2, RM_XMM0_XMM1, 0 } }, + { BECRC_OUT_SS, X86_XCPT_PF, 7, { P_AZ, P_RZ, P_CS, 0x0f, 0xc2, RM_XMM0_XMM1, 0 } }, + { BECRC_OUT_SS, X86_XCPT_PF, 7, { P_RZ, P_AZ, P_CS, 0x0f, 0xc2, RM_XMM0_XMM1, 0 } }, + { BECRC_OUT_SS, X86_XCPT_PF, 8, { P_OZ, P_RZ, P_AZ, P_CS, 0x0f, 0xc2, RM_XMM0_XMM1, 0 } }, + { BECRC_OUT_SS, X86_XCPT_PF, 8, { P_RZ, P_OZ, P_AZ, P_CS, 0x0f, 0xc2, RM_XMM0_XMM1, 0 } }, + { BECRC_OUT_SS, X86_XCPT_PF, 8, { P_RZ, P_AZ, P_OZ, P_CS, 0x0f, 0xc2, RM_XMM0_XMM1, 0 } }, + { BECRC_OUT_SS, X86_XCPT_PF, 8, { P_RZ, P_AZ, P_CS, P_OZ, 0x0f, 0xc2, RM_XMM0_XMM1, 0 } }, + + { BECRC_OUT_SD, X86_XCPT_PF, 6, { P_ES, P_RN, 0x0f, 0xc2, RM_XMM0_XMM1, 0 } }, + { BECRC_OUT_SD, X86_XCPT_PF, 6, { P_RN, P_ES, 0x0f, 0xc2, RM_XMM0_XMM1, 0 } }, + { BECRC_OUT_SD, X86_XCPT_PF, 7, { P_ES, P_SS, P_RN, 0x0f, 0xc2, RM_XMM0_XMM1, 0 } }, + { BECRC_OUT_SD, X86_XCPT_PF, 7, { P_ES, P_RN, P_SS, 0x0f, 0xc2, RM_XMM0_XMM1, 0 } }, + { BECRC_OUT_SD, X86_XCPT_PF, 7, { P_RN, P_ES, P_SS, 0x0f, 0xc2, RM_XMM0_XMM1, 0 } }, + { BECRC_OUT_SD, X86_XCPT_PF, 6, { P_AZ, P_RN, 0x0f, 0xc2, RM_XMM0_XMM1, 0 } }, + { BECRC_OUT_SD, X86_XCPT_PF, 6, { P_RN, P_AZ, 0x0f, 0xc2, RM_XMM0_XMM1, 0 } }, + { BECRC_OUT_SD, X86_XCPT_PF, 7, { P_AZ, P_CS, P_RN, 0x0f, 0xc2, RM_XMM0_XMM1, 0 } }, + { BECRC_OUT_SD, X86_XCPT_PF, 7, { P_AZ, P_RN, P_CS, 0x0f, 0xc2, RM_XMM0_XMM1, 0 } }, + { BECRC_OUT_SD, X86_XCPT_PF, 7, { P_RN, P_AZ, P_CS, 0x0f, 0xc2, RM_XMM0_XMM1, 0 } }, + { BECRC_OUT_SD, X86_XCPT_PF, 8, { P_OZ, P_RN, P_AZ, P_CS, 0x0f, 0xc2, RM_XMM0_XMM1, 0 } }, + { BECRC_OUT_SD, X86_XCPT_PF, 8, { P_RN, P_OZ, P_AZ, P_CS, 0x0f, 0xc2, RM_XMM0_XMM1, 0 } }, + { BECRC_OUT_SD, X86_XCPT_PF, 8, { P_RN, P_AZ, P_OZ, P_CS, 0x0f, 0xc2, RM_XMM0_XMM1, 0 } }, + { BECRC_OUT_SD, X86_XCPT_PF, 8, { P_RN, P_AZ, P_CS, P_OZ, 0x0f, 0xc2, RM_XMM0_XMM1, 0 } }, + + /* Pit f2h against f3h, on skylake+jaguar the last prefix wins. */ + { BECRC_OUT_SS, X86_XCPT_PF, 6, { P_RN, P_RZ, 0x0f, 0xc2, RM_XMM0_XMM1, 0 } }, + { BECRC_OUT_SS, X86_XCPT_PF, 7, { P_RN, P_RN, P_RZ, 0x0f, 0xc2, RM_XMM0_XMM1, 0 } }, + { BECRC_OUT_SS, X86_XCPT_PF, 7, { P_RZ, P_RN, P_RZ, 0x0f, 0xc2, RM_XMM0_XMM1, 0 } }, + { BECRC_OUT_SS, X86_XCPT_PF, 7, { P_RN, P_RZ, P_RZ, 0x0f, 0xc2, RM_XMM0_XMM1, 0 } }, + { BECRC_OUT_SS, X86_XCPT_PF, 8, { P_RN, P_RN, P_RN, P_RZ, 0x0f, 0xc2, RM_XMM0_XMM1, 0 } }, + { BECRC_OUT_SS, X86_XCPT_PF, 8, { P_RN, P_RN, P_RZ, P_RZ, 0x0f, 0xc2, RM_XMM0_XMM1, 0 } }, + { BECRC_OUT_SS, X86_XCPT_PF, 8, { P_RN, P_RZ, P_RN, P_RZ, 0x0f, 0xc2, RM_XMM0_XMM1, 0 } }, + { BECRC_OUT_SS, X86_XCPT_PF, 8, { P_RZ, P_RN, P_RN, P_RZ, 0x0f, 0xc2, RM_XMM0_XMM1, 0 } }, + { BECRC_OUT_SS, X86_XCPT_PF, 8, { P_RZ, P_RZ, P_RN, P_RZ, 0x0f, 0xc2, RM_XMM0_XMM1, 0 } }, + { BECRC_OUT_SS, X86_XCPT_PF, 8, { P_RN, P_RZ, P_RZ, P_RZ, 0x0f, 0xc2, RM_XMM0_XMM1, 0 } }, + + { BECRC_OUT_SD, X86_XCPT_PF, 6, { P_RZ, P_RN, 0x0f, 0xc2, RM_XMM0_XMM1, 0 } }, + { BECRC_OUT_SD, X86_XCPT_PF, 7, { P_RZ, P_RZ, P_RN, 0x0f, 0xc2, RM_XMM0_XMM1, 0 } }, + { BECRC_OUT_SD, X86_XCPT_PF, 7, { P_RN, P_RZ, P_RN, 0x0f, 0xc2, RM_XMM0_XMM1, 0 } }, + { BECRC_OUT_SD, X86_XCPT_PF, 7, { P_RZ, P_RN, P_RN, 0x0f, 0xc2, RM_XMM0_XMM1, 0 } }, + { BECRC_OUT_SD, X86_XCPT_PF, 8, { P_RZ, P_RZ, P_RZ, P_RN, 0x0f, 0xc2, RM_XMM0_XMM1, 0 } }, + { BECRC_OUT_SD, X86_XCPT_PF, 8, { P_RZ, P_RZ, P_RN, P_RN, 0x0f, 0xc2, RM_XMM0_XMM1, 0 } }, + { BECRC_OUT_SD, X86_XCPT_PF, 8, { P_RZ, P_RN, P_RZ, P_RN, 0x0f, 0xc2, RM_XMM0_XMM1, 0 } }, + { BECRC_OUT_SD, X86_XCPT_PF, 8, { P_RN, P_RZ, P_RZ, P_RN, 0x0f, 0xc2, RM_XMM0_XMM1, 0 } }, + { BECRC_OUT_SD, X86_XCPT_PF, 8, { P_RN, P_RN, P_RZ, P_RN, 0x0f, 0xc2, RM_XMM0_XMM1, 0 } }, + { BECRC_OUT_SD, X86_XCPT_PF, 8, { P_RZ, P_RN, P_RN, P_RN, 0x0f, 0xc2, RM_XMM0_XMM1, 0 } }, + }; + RTUINT128U InXmm0 = BECRC_IN_XMM0; + RTUINT128U InXmm1 = BECRC_IN_XMM1; + RTUINT128U OutXmm0 = RTUINT128_INIT_C(0xeeeeeeeeeeeeeeee, 0xcccccccccccccccc); + + Bs3MemZero(&Ctx, sizeof(Ctx)); + Bs3MemZero(&ExpectCtxPf, sizeof(ExpectCtxPf)); + Bs3MemZero(&ExpectCtxUd, sizeof(ExpectCtxUd)); + Bs3MemZero(&TrapFrame, sizeof(TrapFrame)); + + /* Enable SSE. */ + ASMSetCR0((ASMGetCR0() & ~(X86_CR0_EM | X86_CR0_TS)) | X86_CR0_MP); + ASMSetCR4(ASMGetCR4() | X86_CR4_OSFXSR); + + /* Create a test context. */ + Bs3RegCtxSaveEx(&Ctx, BS3_MODE_CODE_32, 512); + Ctx.rax.u = BECRC_EAX; + Ctx.rbx.u = (uintptr_t)pbPages; + + /* Create expected result contexts. */ + Bs3MemCpy(&ExpectCtxPf, &Ctx, sizeof(ExpectCtxPf)); + ExpectCtxPf.rflags.u32 |= X86_EFL_RF; + ExpectCtxPf.rip.u = (uintptr_t)&pbPages[X86_PAGE_SIZE]; + ExpectCtxPf.cr2.u = (uintptr_t)&pbPages[X86_PAGE_SIZE]; + + Bs3MemCpy(&ExpectCtxUd, &Ctx, sizeof(ExpectCtxUd)); + ExpectCtxUd.rflags.u32 |= X86_EFL_RF; + + /* Loop thru the tests. */ + g_usBs3TestStep = 0; + for (iTest = 0; iTest < RT_ELEMENTS(s_aTests); iTest++) + { + unsigned const cbOpcodes = s_aTests[iTest].cbOpcodes; + uint8_t BS3_FAR *pbRip = &pbPages[X86_PAGE_SIZE - cbOpcodes]; + + Bs3MemCpy(pbRip, s_aTests[iTest].abOpcodes, cbOpcodes); + Bs3RegCtxSetRipCsFromFlat(&Ctx, (uintptr_t)pbRip); + ExpectCtxUd.rip = Ctx.rip; +#if 0 + Bs3TestPrintf("iTest=%d pbRip=%p cbOpcodes=%d: %.*Rhxs\n", + iTest, pbRip, cbOpcodes, cbOpcodes, s_aTests[iTest].abOpcodes); + //Bs3RegCtxPrint(&Ctx); +#endif + BS3_CMN_NM(bs3CpuDecoding1_LoadXmm0)(&InXmm0); + BS3_CMN_NM(bs3CpuDecoding1_LoadXmm1)(&InXmm1); + Bs3TrapSetJmpAndRestore(&Ctx, &TrapFrame); + BS3_CMN_NM(bs3CpuDecoding1_SaveXmm0)(&OutXmm0); + + if ( !Bs3TestCheckRegCtxEx(&TrapFrame.Ctx, s_aTests[iTest].bXcpt == X86_XCPT_UD ? &ExpectCtxUd : &ExpectCtxPf, + 0 /*cbPcAdjust*/, 0 /*cbSpAdjust*/, 0 /*fExtraEfl*/, "mode", iTest) + || TrapFrame.bXcpt != s_aTests[iTest].bXcpt + || OutXmm0.s.Lo != s_aTests[iTest].Xmm0Expect.s.Lo + || OutXmm0.s.Hi != s_aTests[iTest].Xmm0Expect.s.Hi) + { + Bs3TestFailedF("iTest=%d cbOpcodes=%d: %.*Rhxs\n", iTest, cbOpcodes, cbOpcodes, s_aTests[iTest].abOpcodes); + if (TrapFrame.bXcpt != s_aTests[iTest].bXcpt) + Bs3TestFailedF("Expected bXcpt=%#x, got %#x\n", s_aTests[iTest].bXcpt, TrapFrame.bXcpt); + if ( OutXmm0.s.Lo != s_aTests[iTest].Xmm0Expect.s.Lo + || OutXmm0.s.Hi != s_aTests[iTest].Xmm0Expect.s.Hi) + Bs3TestFailedF("Expected XMM0=%08RX32:%08RX32:%08RX32:%08RX32, not %08RX32:%08RX32:%08RX32:%08RX32\n", + s_aTests[iTest].Xmm0Expect.DWords.dw3, s_aTests[iTest].Xmm0Expect.DWords.dw2, + s_aTests[iTest].Xmm0Expect.DWords.dw1, s_aTests[iTest].Xmm0Expect.DWords.dw0, + OutXmm0.DWords.dw3, OutXmm0.DWords.dw2, OutXmm0.DWords.dw1, OutXmm0.DWords.dw0); + } + } + + Bs3MemGuardedTestPageFree(pbPages); + } + else + Bs3TestFailed("Failed to allocate two pages!\n"); +} + + +BS3_DECL(void) Main_pp32() +{ + Bs3TestInit("bs3-cpu-decoding-1"); + Bs3TestPrintf("g_uBs3CpuDetected=%#x\n", g_uBs3CpuDetected); + +#if 0 + Bs3TestSub("CMPPS, CMPPD, CMPSS, CMPSD"); + DecodeCmppsCmppdCmpssCmpsd(); + + Bs3TestSub("MOVBE vs CRC32"); + DecodeMovbeVsCrc32(); +#endif + + //Bs3TestSub("CMPXCHG8B/16B"); + //DecodeCmpXchg8bVs16b(); + +#if 1 + Bs3TestSub("2 byte undefined opcodes 0f"); + DecodeUdEdgeTest(g_aUdTest2Byte_0f, RT_ELEMENTS(g_aUdTest2Byte_0f)); +#endif +#if 0 + Bs3TestSub("3 byte undefined opcodes 0f 38"); + DecodeUdEdgeTest(g_aUdTest3Byte_0f_38, RT_ELEMENTS(g_aUdTest3Byte_0f_38)); +#endif + +#if 0 + Bs3TestSub("misc"); + DecodeEdgeTest(); +#endif + + Bs3TestTerm(); +} + diff --git a/src/VBox/ValidationKit/bootsectors/bs3-cpu-generated-1-asm.asm b/src/VBox/ValidationKit/bootsectors/bs3-cpu-generated-1-asm.asm new file mode 100644 index 00000000..d695dcf7 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3-cpu-generated-1-asm.asm @@ -0,0 +1,34 @@ +; $Id: bs3-cpu-generated-1-asm.asm $ +;; @file +; BS3Kit - bs3-generated-1, assembly helpers and template instantiation. +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + + +;********************************************************************************************************************************* +;* Header Files * +;********************************************************************************************************************************* +%include "bs3kit.mac" + +; later maybe. + diff --git a/src/VBox/ValidationKit/bootsectors/bs3-cpu-generated-1-data.py b/src/VBox/ValidationKit/bootsectors/bs3-cpu-generated-1-data.py new file mode 100755 index 00000000..4d27c986 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3-cpu-generated-1-data.py @@ -0,0 +1,644 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# $Id: bs3-cpu-generated-1-data.py $ +# pylint: disable=invalid-name + +""" +Generates testcases from @optest specifications in IEM. +""" + +from __future__ import print_function; + +__copyright__ = \ +""" +Copyright (C) 2017-2019 Oracle Corporation + +This file is part of VirtualBox Open Source Edition (OSE), as +available from http://www.virtualbox.org. This file is free software; +you can redistribute it and/or modify it under the terms of the GNU +General Public License (GPL) as published by the Free Software +Foundation, in version 2 as it comes in the "COPYING" file of the +VirtualBox OSE distribution. VirtualBox OSE is distributed in the +hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + +The contents of this file may alternatively be used under the terms +of the Common Development and Distribution License Version 1.0 +(CDDL) only, as it comes in the "COPYING.CDDL" file of the +VirtualBox OSE distribution, in which case the provisions of the +CDDL are applicable instead of those of the GPL. + +You may elect to license modified versions of this file under the +terms and conditions of either the GPL or the CDDL or both. +""" +__version__ = "$Revision: 127855 $" + +# Standard python imports. +import os; +import sys; + +# Only the main script needs to modify the path. +g_ksValidationKitDir = os.path.dirname(os.path.dirname(os.path.abspath(__file__))); +g_ksVmmAllDir = os.path.join(os.path.dirname(g_ksValidationKitDir), 'VMM', 'VMMAll') +sys.path.append(g_ksVmmAllDir); + +import IEMAllInstructionsPython as iai; # pylint: disable=import-error + + +# Python 3 hacks: +if sys.version_info[0] >= 3: + long = int; # pylint: disable=redefined-builtin,invalid-name + + +class Bs3Cg1TestEncoder(object): + """ + Does the encoding of a single test. + """ + + def __init__(self, fLast): + self.fLast = fLast; + # Each list member (in all lists) are C expression of a byte. + self.asHdr = []; + self.asSelectors = []; + self.asInputs = []; + self.asOutputs = []; + + @staticmethod + def _compileSelectors(aoSelectors): # (list(iai.TestSelector)) -> list(str) + """ + Compiles a list of iai.TestSelector predicate checks. + Returns C byte expression strings. + """ + asRet = []; + for oSelector in aoSelectors: + sConstant = oSelector.kdVariables[oSelector.sVariable][oSelector.sValue]; + sConstant = sConstant.upper().replace('.', '_'); + if oSelector.sOp == '==': + sByte = '(BS3CG1PRED_%s << BS3CG1SEL_OP_PRED_SHIFT) | BS3CG1SEL_OP_IS_TRUE' % (sConstant,); + elif oSelector.sOp == '!=': + sByte = '(BS3CG1PRED_%s << BS3CG1SEL_OP_PRED_SHIFT) | BS3CG1SEL_OP_IS_FALSE' % (sConstant,); + else: + raise Exception('Unknown selector operator: %s' % (oSelector.sOp,)); + asRet.append(sByte); + return asRet; + + kdSmallFields = { + 'op1': 'BS3CG1_CTXOP_OP1', + 'op2': 'BS3CG1_CTXOP_OP2', + 'efl': 'BS3CG1_CTXOP_EFL', + }; + kdOperators = { + '=': 'BS3CG1_CTXOP_ASSIGN', + '|=': 'BS3CG1_CTXOP_OR', + '&=': 'BS3CG1_CTXOP_AND', + '&~=': 'BS3CG1_CTXOP_AND_INV', + }; + kdSmallSizes = { + 1: 'BS3CG1_CTXOP_1_BYTE', + 2: 'BS3CG1_CTXOP_2_BYTES', + 4: 'BS3CG1_CTXOP_4_BYTES', + 8: 'BS3CG1_CTXOP_8_BYTES', + 16: 'BS3CG1_CTXOP_16_BYTES', + 32: 'BS3CG1_CTXOP_32_BYTES', + 12: 'BS3CG1_CTXOP_12_BYTES', + }; + + @staticmethod + def _amendOutputs(aoOutputs, oInstr): # type: (list(iai.TestInOut), iai.Instruction) -> list(iai.TestInOut) + """ + Amends aoOutputs for instructions with special flag behaviour (undefined, + always set, always clear). + + Undefined flags are copied from the result context as the very first + operation so they can be set to CPU vendor specific values later if + desired. + + Always set or cleared flags are applied at the very end of the + modification operations so that we spot incorrect specifications. + """ + if oInstr.asFlUndefined or oInstr.asFlClear or oInstr.asFlSet: + aoOutputs = list(aoOutputs); + + if oInstr.asFlUndefined: + fFlags = oInstr.getUndefinedFlagsMask(); + assert fFlags != 0; + aoOutputs.insert(0, iai.TestInOut('efl_undef', '=', str(fFlags), 'uint')); + + if oInstr.asFlClear: + fFlags = oInstr.getClearedFlagsMask(); + assert fFlags != 0; + aoOutputs.append(iai.TestInOut('efl', '&~=', str(fFlags), 'uint')); + + if oInstr.asFlSet: + fFlags = oInstr.getSetFlagsMask(); + assert fFlags != 0; + aoOutputs.append(iai.TestInOut('efl', '|=', str(fFlags), 'uint')); + + return aoOutputs; + + @staticmethod + def _compileContextModifers(aoOperations): # (list(iai.TestInOut)) + """ + Compile a list of iai.TestInOut context modifiers. + """ + asRet = []; + for oOperation in aoOperations: + oType = iai.TestInOut.kdTypes[oOperation.sType]; + aaoValues = oType.get(oOperation.sValue); + assert len(aaoValues) == 1 or len(aaoValues) == 2; + + sOp = oOperation.sOp; + if sOp == '&|=': + sOp = '|=' if len(aaoValues) == 1 else '&~='; + + for fSignExtend, abValue in aaoValues: + cbValue = len(abValue); + + # The opcode byte. + sOpcode = Bs3Cg1TestEncoder.kdOperators[sOp]; + sOpcode += ' | '; + if oOperation.sField in Bs3Cg1TestEncoder.kdSmallFields: + sOpcode += Bs3Cg1TestEncoder.kdSmallFields[oOperation.sField]; + else: + sOpcode += 'BS3CG1_CTXOP_DST_ESC'; + sOpcode += ' | '; + if cbValue in Bs3Cg1TestEncoder.kdSmallSizes: + sOpcode += Bs3Cg1TestEncoder.kdSmallSizes[cbValue]; + else: + sOpcode += 'BS3CG1_CTXOP_SIZE_ESC'; + if fSignExtend: + sOpcode += ' | BS3CG1_CTXOP_SIGN_EXT'; + asRet.append(sOpcode); + + # Escaped field identifier. + if oOperation.sField not in Bs3Cg1TestEncoder.kdSmallFields: + asRet.append('BS3CG1DST_%s' % (oOperation.sField.upper().replace('.', '_'),)); + + # Escaped size byte? + if cbValue not in Bs3Cg1TestEncoder.kdSmallSizes: + if cbValue >= 256 or cbValue not in [ 1, 2, 4, 6, 8, 12, 16, 32, 64, 128, ]: + raise Exception('Invalid value size: %s' % (cbValue,)); + asRet.append('0x%02x' % (cbValue,)); + + # The value bytes. + for b in abValue: + asRet.append('0x%02x' % (b,)); + + sOp = '|='; + + return asRet; + + def _constructHeader(self): + """ + Returns C byte expression strings for BS3CG1TESTHDR. + """ + cbSelectors = len(self.asSelectors); + if cbSelectors >= 256: + raise Exception('Too many selectors: %s bytes, max 255 bytes' % (cbSelectors,)) + + cbInputs = len(self.asInputs); + if cbInputs >= 4096: + raise Exception('Too many input context modifiers: %s bytes, max 4095 bytes' % (cbInputs,)) + + cbOutputs = len(self.asOutputs); + if cbOutputs >= 2048: + raise Exception('Too many output context modifiers: %s bytes, max 2047 bytes' % (cbOutputs,)) + + return [ + '%#04x' % (cbSelectors,), # 8-bit + '%#05x & 0xff' % (cbInputs,), # first 8 bits of cbInputs + '(%#05x >> 8) | ((%#05x & 0xf) << 4)' % (cbInputs, cbOutputs,), # last 4 bits of cbInputs, lower 4 bits of cbOutputs. + '(%#05x >> 4) | (%#05x << 7)' % (cbOutputs, self.fLast), # last 7 bits of cbOutputs and 1 bit fLast. + ]; + + def encodeTest(self, oTest): # type: (iai.InstructionTest) + """ + Does the encoding. + """ + self.asSelectors = self._compileSelectors(oTest.aoSelectors); + self.asInputs = self._compileContextModifers(oTest.aoInputs); + self.asOutputs = self._compileContextModifers(self._amendOutputs(oTest.aoOutputs, oTest.oInstr)); + self.asHdr = self._constructHeader(); + + +class Bs3Cg1EncodedTests(object): + """ + Encodes the tests for an instruction. + """ + + def __init__(self, oInstr): + self.offTests = -1; + self.cbTests = 0; + self.asLines = []; # type: list(str) + self.aoInstructions = []; # type: list(iai.Instruction) + + # Encode the tests. + for iTest, oTest in enumerate(oInstr.aoTests): + oEncodedTest = Bs3Cg1TestEncoder(iTest + 1 == len(oInstr.aoTests)); + oEncodedTest.encodeTest(oTest); + + self.cbTests += len(oEncodedTest.asHdr) + len(oEncodedTest.asSelectors) \ + + len(oEncodedTest.asInputs) + len(oEncodedTest.asOutputs); + + self.asLines.append(' /* test #%s: %s */' % (iTest, oTest,)); + self.asLines += self.bytesToLines(' ', oEncodedTest.asHdr); + if oEncodedTest.asSelectors: + self.asLines += self.bytesToLines(' /*sel:*/ ', oEncodedTest.asSelectors); + if oEncodedTest.asInputs: + self.asLines += self.bytesToLines(' /* in:*/ ', oEncodedTest.asInputs); + if oEncodedTest.asOutputs: + self.asLines += self.bytesToLines(' /*out:*/ ', oEncodedTest.asOutputs); + + @staticmethod + def bytesToLines(sPrefix, asBytes): + """ + Formats a series of bytes into one or more lines. + A byte ending with a newline indicates that we should start a new line, + and prefix it by len(sPrefix) spaces. + + Returns list of lines. + """ + asRet = []; + sLine = sPrefix; + for sByte in asBytes: + if sByte[-1] == '\n': + sLine += sByte[:-1] + ','; + asRet.append(sLine); + sLine = ' ' * len(sPrefix); + else: + if len(sLine) + 2 + len(sByte) > 132 and len(sLine) > len(sPrefix): + asRet.append(sLine[:-1]); + sLine = ' ' * len(sPrefix); + sLine += sByte + ', '; + + + if len(sLine) > len(sPrefix): + asRet.append(sLine); + return asRet; + + + def isEqual(self, oOther): + """ Compares two encoded tests. """ + if self.cbTests != oOther.cbTests: + return False; + if len(self.asLines) != len(oOther.asLines): + return False; + for iLine, sLines in enumerate(self.asLines): + if sLines != oOther.asLines[iLine]: + return False; + return True; + + + +class Bs3Cg1Instruction(object): + """ + An instruction with tests. + """ + + def __init__(self, oMap, oInstr, oTests): + self.oMap = oMap; # type: iai.InstructionMap + self.oInstr = oInstr; # type: iai.Instruction + self.oTests = oTests; # type: Bs3Cg1EncodedTests + + self.asOpcodes = oMap.asLeadOpcodes + [ '0x%02x' % (oInstr.getOpcodeByte(),) ]; + self.sEncoding = iai.g_kdEncodings[oInstr.sEncoding][0]; + + for oOp in oInstr.aoOperands: + self.sEncoding += '_' + oOp.sType; + if oInstr.sSubOpcode and iai.g_kdSubOpcodes[oInstr.sSubOpcode][1]: + self.sEncoding += '_' + iai.g_kdSubOpcodes[oInstr.sSubOpcode][1]; + + if oInstr.fUnused: + if oInstr.sInvalidStyle == 'immediate' and oInstr.sSubOpcode: + self.sEncoding += '_MOD_EQ_3' if oInstr.sSubOpcode == '11 mr/reg' else '_MOD_NE_3'; + elif oInstr.sInvalidStyle == 'intel-modrm': + if oInstr.sSubOpcode is None: + self.sEncoding = 'BS3CG1ENC_MODRM_Gv_Ev'; + elif oInstr.sSubOpcode == '11 mr/reg': + self.sEncoding = 'BS3CG1ENC_MODRM_MOD_EQ_3'; + elif oInstr.sSubOpcode == '!11 mr/reg': + self.sEncoding = 'BS3CG1ENC_MODRM_MOD_NE_3'; + else: + raise Exception('Unhandled sSubOpcode=%s for sInvalidStyle=%s' % (oInstr.sSubOpcode, oInstr.sInvalidStyle)); + elif oInstr.sInvalidStyle == 'vex.modrm': + self.sEncoding = 'BS3CG1ENC_VEX_MODRM'; + + self.asFlags = []; + if 'invalid_64' in oInstr.dHints: + self.asFlags.append('BS3CG1INSTR_F_INVALID_64BIT'); + if oInstr.fUnused: + self.asFlags.append('BS3CG1INSTR_F_UNUSED'); + elif oInstr.fInvalid: + self.asFlags.append('BS3CG1INSTR_F_INVALID'); + if oInstr.sInvalidStyle and oInstr.sInvalidStyle.startswith('intel-'): + self.asFlags.append('BS3CG1INSTR_F_INTEL_DECODES_INVALID'); + if 'vex_l_zero' in oInstr.dHints: + self.asFlags.append('BS3CG1INSTR_F_VEX_L_ZERO'); + if 'vex_l_ignored' in oInstr.dHints: + self.asFlags.append('BS3CG1INSTR_F_VEX_L_IGNORED'); + + self.fAdvanceMnemonic = True; ##< Set by the caller. + if oInstr.sPrefix: + if oInstr.sPrefix == 'none': + self.sPfxKind = 'BS3CG1PFXKIND_NO_F2_F3_66'; + else: + self.sPfxKind = 'BS3CG1PFXKIND_REQ_' + oInstr.sPrefix[-2:].upper(); + elif oInstr.sEncoding == 'ModR/M': + if 'ignores_op_size' not in oInstr.dHints: + self.sPfxKind = 'BS3CG1PFXKIND_MODRM'; + else: + self.sPfxKind = 'BS3CG1PFXKIND_MODRM_NO_OP_SIZES'; + else: + self.sPfxKind = '0'; + + self.sCpu = 'BS3CG1CPU_'; + assert len(oInstr.asCpuIds) in [0, 1], str(oInstr); + if oInstr.asCpuIds: + self.sCpu += oInstr.asCpuIds[0].upper().replace('.', '_'); + elif oInstr.sMinCpu: + self.sCpu += 'GE_' + oInstr.sMinCpu; + else: + self.sCpu += 'ANY'; + + if oInstr.sXcptType: + self.sXcptType = 'BS3CG1XCPTTYPE_' + oInstr.sXcptType.upper(); + else: + self.sXcptType = 'BS3CG1XCPTTYPE_NONE'; + + def getOperands(self): + """ Returns comma separated string of operand values for g_abBs3Cg1Operands. """ + return ', '.join(['(uint8_t)BS3CG1OP_%s' % (oOp.sType,) for oOp in self.oInstr.aoOperands]); + + def getOpcodeMap(self): + """ Returns the opcode map number for the BS3CG1INSTR structure. """ + sEncoding = self.oInstr.aoMaps[0].sEncoding; + if sEncoding == 'legacy': return 0; + if sEncoding == 'vex1': return 1; + if sEncoding == 'vex2': return 2; + if sEncoding == 'vex3': return 3; + if sEncoding == 'xop8': return 8; + if sEncoding == 'xop9': return 9; + if sEncoding == 'xop10': return 10; + assert False, sEncoding; + return 3; + + def getInstructionEntry(self): + """ Returns an array of BS3CG1INSTR member initializers. """ + assert len(self.oInstr.sMnemonic) < 16; + sOperands = ', '.join([oOp.sType for oOp in self.oInstr.aoOperands]); + if sOperands: + sOperands = ' /* ' + sOperands + ' */'; + return [ + ' /* cbOpcodes = */ %s, /* %s */' % (len(self.asOpcodes), ' '.join(self.asOpcodes),), + ' /* cOperands = */ %s,%s' % (len(self.oInstr.aoOperands), sOperands,), + ' /* cchMnemonic = */ %s, /* %s */' % (len(self.oInstr.sMnemonic), self.oInstr.sMnemonic,), + ' /* fAdvanceMnemonic = */ %s,' % ('true' if self.fAdvanceMnemonic else 'false',), + ' /* offTests = */ %s,' % (self.oTests.offTests,), + ' /* enmEncoding = */ (unsigned)%s,' % (self.sEncoding,), + ' /* uOpcodeMap = */ (unsigned)%s,' % (self.getOpcodeMap(),), + ' /* enmPrefixKind = */ (unsigned)%s,' % (self.sPfxKind,), + ' /* enmCpuTest = */ (unsigned)%s,' % (self.sCpu,), + ' /* enmXcptType = */ (unsigned)%s,' % (self.sXcptType,), + ' /* uUnused = */ 0,', + ' /* fFlags = */ %s' % (' | '.join(self.asFlags) if self.asFlags else '0'), + ]; + + +class Bs3CpuGenerated1Generator(object): + """ + The generator code for bs3-cpu-generated-1. + """ + + def __init__(self): + self.aoInstructions = []; # type: Bs3Cg1Instruction + self.aoTests = []; # type: Bs3Cg1EncodedTests + self.cbTests = 0; + + def addTests(self, oTests, oInstr): # type: (Bs3Cg1EncodedTests, iai.Instruction) -> Bs3Cg1EncodedTests + """ + Adds oTests to self.aoTests, setting the oTests.offTests member. + Checks for and eliminates duplicates. + Returns the tests to use. + """ + # Check for duplicates. + for oExisting in self.aoTests: + if oTests.isEqual(oExisting): + oExisting.aoInstructions.append(oInstr); + return oExisting; + + # New test, so add it. + oTests.offTests = self.cbTests; + self.aoTests.append(oTests); + self.cbTests += oTests.cbTests; + + assert not oTests.aoInstructions; + oTests.aoInstructions.append(oInstr); + + return oTests; + + def processInstruction(self): + """ + Processes the IEM specified instructions. + Returns success indicator. + """ + + # + # Group instructions by mnemonic to reduce the number of sub-tests. + # + for oInstr in sorted(iai.g_aoAllInstructions, + key = lambda oInstr: oInstr.sMnemonic + ''.join([oOp.sType for oOp in oInstr.aoOperands]) + + (oInstr.sOpcode if oInstr.sOpcode else 'zz')): + if oInstr.aoTests: + oTests = Bs3Cg1EncodedTests(oInstr); + oTests = self.addTests(oTests, oInstr); + + for oMap in oInstr.aoMaps: + self.aoInstructions.append(Bs3Cg1Instruction(oMap, oInstr, oTests)); + + # Set fAdvanceMnemonic. + for iInstr, oInstr in enumerate(self.aoInstructions): + oInstr.fAdvanceMnemonic = iInstr + 1 >= len(self.aoInstructions) \ + or oInstr.oInstr.sMnemonic != self.aoInstructions[iInstr + 1].oInstr.sMnemonic; + + return True; + + def generateCode(self, oOut): + """ + Generates the C code. + Returns success indicator. + """ + + # First, a file header. + asLines = [ + '/*', + ' * Autogenerated by $Id: bs3-cpu-generated-1-data.py $ ', + ' * Do not edit!', + ' */', + '', + '/*', + ' * Copyright (C) 2017 Oracle Corporation', + ' *', + ' * This file is part of VirtualBox Open Source Edition (OSE), as', + ' * available from http://www.virtualbox.org. This file is free software;', + ' * you can redistribute it and/or modify it under the terms of the GNU', + ' * General Public License (GPL) as published by the Free Software', + ' * Foundation, in version 2 as it comes in the "COPYING" file of the', + ' * VirtualBox OSE distribution. VirtualBox OSE is distributed in the', + ' * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.', + ' * ', + ' * The contents of this file may alternatively be used under the terms', + ' * of the Common Development and Distribution License Version 1.0', + ' * (CDDL) only, as it comes in the "COPYING.CDDL" file of the', + ' * VirtualBox OSE distribution, in which case the provisions of the', + ' * CDDL are applicable instead of those of the GPL.', + ' * ', + ' * You may elect to license modified versions of this file under the', + ' * terms and conditions of either the GPL or the CDDL or both.', + ' */', + '', + '', + '#include "bs3-cpu-generated-1.h"', + '', + '', + '#pragma data_seg ("BS3DATA16")', + ]; + + # Generate the g_achBs3Cg1Mnemonics array. + asLines += [ + 'const char BS3_FAR_DATA g_achBs3Cg1Mnemonics[] = ', + '{', + ]; + fAdvanceMnemonic = True; + for oInstr in self.aoInstructions: + if fAdvanceMnemonic: + asLines.append(' \"%s\"' % (oInstr.oInstr.sMnemonic,)); + fAdvanceMnemonic = oInstr.fAdvanceMnemonic; + asLines += [ + '};', + '', + '', + ]; + + # Generate the g_abBs3Cg1Opcodes array. + asLines += [ + 'const uint8_t BS3_FAR_DATA g_abBs3Cg1Opcodes[] = ', + '{', + ]; + for oInstr in self.aoInstructions: + asLines.append(' ' + ', '.join(oInstr.asOpcodes) + ','); + asLines += [ + '};', + '', + '', + ]; + + # Generate the g_abBs3Cg1Opcodes array. + asLines += [ + 'const uint8_t BS3_FAR_DATA g_abBs3Cg1Operands[] = ', + '{', + ]; + cOperands = 0; + for oInstr in self.aoInstructions: + if oInstr.oInstr.aoOperands: + cOperands += len(oInstr.oInstr.aoOperands); + asLines.append(' ' + oInstr.getOperands() + ', /* %s */' % (oInstr.oInstr.sStats,)); + else: + asLines.append(' /* none */'); + if not cOperands: + asLines.append(' 0 /* dummy */'); + asLines += [ + '};', + '', + '', + ]; + + # Generate the g_abBs3Cg1Operands array. + asLines += [ + 'const BS3CG1INSTR BS3_FAR_DATA g_aBs3Cg1Instructions[] = ', + '{', + ]; + for oInstr in self.aoInstructions: + asLines.append(' {'); + asLines += oInstr.getInstructionEntry(); + asLines.append(' },'); + asLines += [ + '};', + 'const uint16_t BS3_FAR_DATA g_cBs3Cg1Instructions = RT_ELEMENTS(g_aBs3Cg1Instructions);', + '', + '', + ]; + + # Generate the g_abBs3Cg1Tests array. + asLines += [ + 'const uint8_t BS3_FAR_DATA g_abBs3Cg1Tests[] = ', + '{', + ]; + for oTests in self.aoTests: + asLines.append(' /*'); + asLines.append(' * offTests=%s' % (oTests.offTests,)); + asLines.append(' * Instructions: %s' % (', '.join([oInstr.sStats for oInstr in oTests.aoInstructions]),)); + asLines.append(' */'); + asLines += oTests.asLines; + asLines += [ + '};', + '', + ]; + + + #/** The test data that BS3CG1INSTR. + # * In order to simplify generating these, we use a byte array. */ + #extern const uint8_t BS3_FAR_DATA g_abBs3Cg1Tests[]; + + + oOut.write('\n'.join(asLines)); + return True; + + + def usage(self): + """ Prints usage. """ + print('usage: bs3-cpu-generated-1-data.py [output file|-]'); + return 0; + + def main(self, asArgs): + """ + C-like main function. + Returns exit code. + """ + + # + # Quick argument parsing. + # + if len(asArgs) == 1: + sOutFile = '-'; + elif len(asArgs) != 2: + print('syntax error! Expected exactly one argument.'); + return 2; + elif asArgs[1] in [ '-h', '-?', '--help' ]: + return self.usage(); + else: + sOutFile = asArgs[1]; + + # + # Process the instructions specified in the IEM sources. + # + if self.processInstruction(): + + # + # Open the output file and generate the code. + # + if sOutFile == '-': + oOut = sys.stdout; + else: + try: + oOut = open(sOutFile, 'w'); + except Exception as oXcpt: + print('error! Failed open "%s" for writing: %s' % (sOutFile, oXcpt,)); + return 1; + if self.generateCode(oOut): + return 0; + + return 1; + + +if __name__ == '__main__': + sys.exit(Bs3CpuGenerated1Generator().main(sys.argv)); + diff --git a/src/VBox/ValidationKit/bootsectors/bs3-cpu-generated-1-template.c b/src/VBox/ValidationKit/bootsectors/bs3-cpu-generated-1-template.c new file mode 100644 index 00000000..3e0df3f1 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3-cpu-generated-1-template.c @@ -0,0 +1,6141 @@ +/* $Id: bs3-cpu-generated-1-template.c $ */ +/** @file + * BS3Kit - bs3-cpu-generated-1, C code template. + */ + +/* + * Copyright (C) 2007-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + +#ifndef BS3_INSTANTIATING_CMN +# error "BS3_INSTANTIATING_CMN not defined" +#endif + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include <iprt/asm.h> +#include <iprt/asm-amd64-x86.h> + +#include "bs3-cpu-generated-1.h" + + +/********************************************************************************************************************************* +* Defined Constants And Macros * +*********************************************************************************************************************************/ +#define BS3CG1_WITH_VEX + +#define P_CS X86_OP_PRF_CS +#define P_SS X86_OP_PRF_SS +#define P_DS X86_OP_PRF_DS +#define P_ES X86_OP_PRF_ES +#define P_FS X86_OP_PRF_FS +#define P_GS X86_OP_PRF_GS +#define P_OZ X86_OP_PRF_SIZE_OP +#define P_AZ X86_OP_PRF_SIZE_ADDR +#define P_LK X86_OP_PRF_LOCK +#define P_RN X86_OP_PRF_REPNZ +#define P_RZ X86_OP_PRF_REPZ + +#define REX_WRBX (X86_OP_REX_W | X86_OP_REX_R | X86_OP_REX_B | X86_OP_REX_X) +#define REX_W___ (X86_OP_REX_W) +#define REX_WR__ (X86_OP_REX_W | X86_OP_REX_R) +#define REX_W_B_ (X86_OP_REX_W | X86_OP_REX_B) +#define REX_W__X (X86_OP_REX_W | X86_OP_REX_X) +#define REX_WRB_ (X86_OP_REX_W | X86_OP_REX_R | X86_OP_REX_B) +#define REX_WR_X (X86_OP_REX_W | X86_OP_REX_R | X86_OP_REX_X) +#define REX_W_BX (X86_OP_REX_W | X86_OP_REX_B | X86_OP_REX_X) +#define REX__R__ (X86_OP_REX_R) +#define REX__RB_ (X86_OP_REX_R | X86_OP_REX_B) +#define REX__R_X (X86_OP_REX_R | X86_OP_REX_X) +#define REX__RBX (X86_OP_REX_R | X86_OP_REX_B | X86_OP_REX_X) +#define REX___B_ (X86_OP_REX_B) +#define REX___BX (X86_OP_REX_B | X86_OP_REX_X) +#define REX____X (X86_OP_REX_X) +#define REX_____ (0x40) + + +/** @def BS3CG1_DPRINTF + * Debug print macro. + */ +#if 0 +# define BS3CG1_DPRINTF(a_ArgList) Bs3TestPrintf a_ArgList +# define BS3CG1_DEBUG_CTX_MOD +#else +# define BS3CG1_DPRINTF(a_ArgList) do { } while (0) +#endif + +/** + * Checks if this is a 64-bit test target or not. + * Helps avoid ifdefs or code bloat. + */ +#if ARCH_BITS == 64 +# define BS3CG1_IS_64BIT_TARGET(a_pThis) BS3_MODE_IS_64BIT_CODE((a_pThis)->bMode) +#else +# define BS3CG1_IS_64BIT_TARGET(a_pThis) (false) +#endif + + +/********************************************************************************************************************************* +* Structures and Typedefs * +*********************************************************************************************************************************/ +/** Operand value location. */ +typedef enum BS3CG1OPLOC +{ + BS3CG1OPLOC_INVALID = 0, + BS3CG1OPLOC_CTX, + BS3CG1OPLOC_CTX_ZX_VLMAX, + BS3CG1OPLOC_IMM, + BS3CG1OPLOC_MEM, + BS3CG1OPLOC_MEM_RW, + BS3CG1OPLOC_MEM_WO, + BS3CG1OPLOC_END +} BS3CG1OPLOC; +AssertCompile(BS3CG1OPLOC_END <= 16); + + +/** Pointer to the generated test state. */ +typedef struct BS3CG1STATE *PBS3CG1STATE; + +/** + * Encoder callback. + * @returns Next encoding. If equal or less to @a iEncoding, no + * further encodings are available for testing. + * @param pThis The state. + * @param iEncoding The encoding. + */ +typedef unsigned BS3_NEAR_CODE FNBS3CG1ENCODER(PBS3CG1STATE pThis, unsigned iEncoding); +/** Pointer to a encoder callback. */ +typedef FNBS3CG1ENCODER *PFNBS3CG1ENCODER; + + +/** + * The state. + */ +typedef struct BS3CG1STATE +{ + /** @name Instruction details (expanded from BS3CG1INSTR). + * @{ */ + /** Pointer to the mnemonic string (not terminated) (g_achBs3Cg1Mnemonics). */ + const char BS3_FAR *pchMnemonic; + /** Pointer to the test header. */ + PCBS3CG1TESTHDR pTestHdr; + /** Pointer to the per operand flags (g_abBs3Cg1Operands). */ + const uint8_t BS3_FAR *pabOperands; + /** Opcode bytes (g_abBs3Cg1Opcodes). */ + const uint8_t BS3_FAR *pabOpcodes; + /** The current instruction number in the input array (for error reporting). */ + uint32_t iInstr; + + /** The instruction flags. */ + uint32_t fFlags; + /** The encoding. */ + BS3CG1ENC enmEncoding; + /** The non-invalid encoding. This may differ from enmEncoding when + * Bs3Cg1CalcNoneIntelInvalidEncoding has been called. */ + BS3CG1ENC enmEncodingNonInvalid; + /** The CPU test / CPU ID. */ + BS3CG1CPU enmCpuTest; + /** Prefix sensitivity and requirements. */ + BS3CG1PFXKIND enmPrefixKind; + /** Exception type (SSE, AVX). */ + BS3CG1XCPTTYPE enmXcptType; + /** Per operand flags. */ + BS3CG1OP aenmOperands[4]; + /** Opcode bytes. */ + uint8_t abOpcodes[4]; + /** The instruction encoder. */ + PFNBS3CG1ENCODER pfnEncoder; + + /** The length of the mnemonic. */ + uint8_t cchMnemonic; + /** Whether to advance the mnemonic pointer or not. */ + uint8_t fAdvanceMnemonic; + /** The opcode map number. */ + uint8_t uOpcodeMap; + /** The number of opcode bytes. */ + uint8_t cbOpcodes; + /** Number of operands. */ + uint8_t cOperands; + /** @} */ + + /** Default operand size. */ + uint8_t cbOpDefault; + /** Operand size when overridden by 066h. */ + uint8_t cbOpOvrd66; + /** Operand size when overridden by REX.W. */ + uint8_t cbOpOvrdRexW; + + /** Operand size in bytes (0 if not applicable). */ + uint8_t cbOperand; + /** Current VEX.L value (UINT8_MAX if not applicable). */ + uint8_t uVexL; + /** Current target ring (0..3). */ + uint8_t uCpl; + + /** The current test number. */ + uint8_t iTest; + + /** Target mode (g_bBs3CurrentMode). */ + uint8_t bMode; + /** The CPU vendor (BS3CPUVENDOR). */ + uint8_t bCpuVendor; + /** First ring being tested. */ + uint8_t iFirstRing; + /** End of rings being tested. */ + uint8_t iEndRing; + + /** @name Current encoded instruction. + * @{ */ + /** The size of the current instruction that we're testing. */ + uint8_t cbCurInstr; + /** The size the prefixes. */ + uint8_t cbCurPrefix; + /** The offset into abCurInstr of the immediate. */ + uint8_t offCurImm; + /** Buffer for assembling the current instruction. */ + uint8_t abCurInstr[23]; + + /** Set if the encoding can't be tested in the same ring as this test code. + * This is used to deal with encodings modifying SP/ESP/RSP. */ + bool fSameRingNotOkay; + /** Whether to work the extended context too. */ + bool fWorkExtCtx; + /** The aOperands index of the modrm.reg operand (if applicable). */ + uint8_t iRegOp; + /** The aOperands index of the modrm.rm operand (if applicable). */ + uint8_t iRmOp; + + /** Operands details. */ + struct + { + uint8_t cbOp; + /** BS3CG1OPLOC_XXX. */ + uint8_t enmLocation; + /** BS3CG1OPLOC_XXX for memory encodings (MODRM.rm field). */ + uint8_t enmLocationMem : 4; + /** BS3CG1OPLOC_XXX for register encodings (MODRM.rm field). */ + uint8_t enmLocationReg : 4; + /** The BS3CG1DST value for this field. + * Set to BS3CG1DST_INVALID if memory or immediate. */ + uint8_t idxField; + /** The base BS3CG1DST value for this field. + * Used only by some generalized encoders when dealing with registers. */ + uint8_t idxFieldBase; + /** Depends on enmLocation. + * - BS3CG1OPLOC_IMM: offset relative to start of the instruction. + * - BS3CG1OPLOC_MEM: offset should be subtracted from &pbDataPg[_4K]. + * - BS3CG1OPLOC_MEM_RW: offset should be subtracted from &pbDataPg[_4K]. + * - BS3CG1OPLOC_MEM_RO: offset should be subtracted from &pbDataPg[_4K]. + * - BS3CG1OPLOC_CTX: not used (use idxField instead). + */ + uint8_t off; + } aOperands[4]; + /** @} */ + + /** Page to put code in. When paging is enabled, the page before and after + * are marked not-present. */ + uint8_t BS3_FAR *pbCodePg; + /** The flat address corresponding to pbCodePg. */ + uintptr_t uCodePgFlat; + /** The 16-bit address corresponding to pbCodePg if relevant for bMode. */ + RTFAR16 CodePgFar; + /** The IP/EIP/RIP value for pbCodePg[0] relative to CS (bMode). */ + uintptr_t CodePgRip; + + /** Page for placing data operands in. When paging is enabled, the page before + * and after are marked not-present. */ + uint8_t BS3_FAR *pbDataPg; + /** The flat address corresponding to pbDataPg. */ + uintptr_t uDataPgFlat; + /** The 16-bit address corresponding to pbDataPg. */ + RTFAR16 DataPgFar; + + /** The name corresponding to bMode. */ + const char BS3_FAR *pszMode; + /** The short name corresponding to bMode. */ + const char BS3_FAR *pszModeShort; + + /** @name Expected result (modifiable by output program). + * @{ */ + /** The expected exception based on operand values or result. + * UINT8_MAX if no special exception expected. */ + uint8_t bValueXcpt; + /** @} */ + /** Alignment exception expected by the encoder. + * UINT8_MAX if no special exception expected. */ + uint8_t bAlignmentXcpt; + /** Set by the encoding method to indicating invalid encoding. */ + bool fInvalidEncoding; + /** The result of Bs3Cg1CpuSetupFirst(). */ + bool fCpuSetupFirstResult; + + /** The context we're working on. */ + BS3REGCTX Ctx; + /** The trap context and frame. */ + BS3TRAPFRAME TrapFrame; + /** Initial contexts, one for each ring. */ + BS3REGCTX aInitialCtxs[4]; + + /** The extended context we're working on (input, expected output). */ + PBS3EXTCTX pExtCtx; + /** The extended result context (analoguous to TrapFrame). */ + PBS3EXTCTX pResultExtCtx; + /** The initial extended context. */ + PBS3EXTCTX pInitialExtCtx; + + /** Memory operand scratch space. */ + union + { + uint8_t ab[128]; + uint16_t au16[128 / sizeof(uint16_t)]; + uint32_t au32[128 / sizeof(uint32_t)]; + uint64_t au64[128 / sizeof(uint64_t)]; + } MemOp; + + /** Array parallel to aInitialCtxs for saving segment registers. */ + struct + { + RTSEL ds; + } aSavedSegRegs[4]; + +} BS3CG1STATE; + + +#define BS3CG1_PF_OZ UINT16_C(0x0001) +#define BS3CG1_PF_AZ UINT16_C(0x0002) +#define BS3CG1_PF_CS UINT16_C(0x0004) +#define BS3CG1_PF_DS UINT16_C(0x0008) +#define BS3CG1_PF_ES UINT16_C(0x0010) +#define BS3CG1_PF_FS UINT16_C(0x0020) +#define BS3CG1_PF_GS UINT16_C(0x0040) +#define BS3CG1_PF_SS UINT16_C(0x0080) +#define BS3CG1_PF_SEGS (BS3CG1_PF_CS | BS3CG1_PF_DS | BS3CG1_PF_ES | BS3CG1_PF_FS | BS3CG1_PF_GS | BS3CG1_PF_SS) +#define BS3CG1_PF_MEM (BS3CG1_PF_SEGS | BS3CG1_PF_AZ) +#define BS3CG1_PF_LK UINT16_C(0x0100) +#define BS3CG1_PF_RN UINT16_C(0x0200) +#define BS3CG1_PF_RZ UINT16_C(0x0400) +#define BS3CG1_PF_W UINT16_C(0x0800) /**< REX.W */ +#define BS3CG1_PF_R UINT16_C(0x1000) /**< REX.R */ +#define BS3CG1_PF_B UINT16_C(0x2000) /**< REX.B */ +#define BS3CG1_PF_X UINT16_C(0x4000) /**< REX.X */ + + +/** Used in g_cbBs3Cg1DstFields to indicate that it's one of the 4 operands. */ +#define BS3CG1DSTSIZE_OPERAND UINT8_C(255) +/** Used in g_cbBs3Cg1DstFields to indicate that the operand size determins + * the field size (2, 4, or 8). */ +#define BS3CG1DSTSIZE_OPERAND_SIZE_GRP UINT8_C(254) + + + +/********************************************************************************************************************************* +* Global Variables * +*********************************************************************************************************************************/ +/** Destination field sizes indexed by bBS3CG1DST. + * Zero means operand size sized. */ +static const uint8_t g_acbBs3Cg1DstFields[] = +{ + /* [BS3CG1DST_INVALID] = */ BS3CG1DSTSIZE_OPERAND, + + /* [BS3CG1DST_OP1] = */ BS3CG1DSTSIZE_OPERAND, + /* [BS3CG1DST_OP2] = */ BS3CG1DSTSIZE_OPERAND, + /* [BS3CG1DST_OP3] = */ BS3CG1DSTSIZE_OPERAND, + /* [BS3CG1DST_OP4] = */ BS3CG1DSTSIZE_OPERAND, + /* [BS3CG1DST_EFL] = */ 4, + /* [BS3CG1DST_EFL_UNDEF]=*/ 4, + + /* [BS3CG1DST_AL] = */ 1, + /* [BS3CG1DST_CL] = */ 1, + /* [BS3CG1DST_DL] = */ 1, + /* [BS3CG1DST_BL] = */ 1, + /* [BS3CG1DST_AH] = */ 1, + /* [BS3CG1DST_CH] = */ 1, + /* [BS3CG1DST_DH] = */ 1, + /* [BS3CG1DST_BH] = */ 1, + /* [BS3CG1DST_SPL] = */ 1, + /* [BS3CG1DST_BPL] = */ 1, + /* [BS3CG1DST_SIL] = */ 1, + /* [BS3CG1DST_DIL] = */ 1, + /* [BS3CG1DST_R8L] = */ 1, + /* [BS3CG1DST_R9L] = */ 1, + /* [BS3CG1DST_R10L] = */ 1, + /* [BS3CG1DST_R11L] = */ 1, + /* [BS3CG1DST_R12L] = */ 1, + /* [BS3CG1DST_R13L] = */ 1, + /* [BS3CG1DST_R14L] = */ 1, + /* [BS3CG1DST_R15L] = */ 1, + + /* [BS3CG1DST_AX] = */ 2, + /* [BS3CG1DST_CX] = */ 2, + /* [BS3CG1DST_DX] = */ 2, + /* [BS3CG1DST_BX] = */ 2, + /* [BS3CG1DST_SP] = */ 2, + /* [BS3CG1DST_BP] = */ 2, + /* [BS3CG1DST_SI] = */ 2, + /* [BS3CG1DST_DI] = */ 2, + /* [BS3CG1DST_R8W] = */ 2, + /* [BS3CG1DST_R9W] = */ 2, + /* [BS3CG1DST_R10W] = */ 2, + /* [BS3CG1DST_R11W] = */ 2, + /* [BS3CG1DST_R12W] = */ 2, + /* [BS3CG1DST_R13W] = */ 2, + /* [BS3CG1DST_R14W] = */ 2, + /* [BS3CG1DST_R15W] = */ 2, + + /* [BS3CG1DST_EAX] = */ 4, + /* [BS3CG1DST_ECX] = */ 4, + /* [BS3CG1DST_EDX] = */ 4, + /* [BS3CG1DST_EBX] = */ 4, + /* [BS3CG1DST_ESP] = */ 4, + /* [BS3CG1DST_EBP] = */ 4, + /* [BS3CG1DST_ESI] = */ 4, + /* [BS3CG1DST_EDI] = */ 4, + /* [BS3CG1DST_R8D] = */ 4, + /* [BS3CG1DST_R9D] = */ 4, + /* [BS3CG1DST_R10D] = */ 4, + /* [BS3CG1DST_R11D] = */ 4, + /* [BS3CG1DST_R12D] = */ 4, + /* [BS3CG1DST_R13D] = */ 4, + /* [BS3CG1DST_R14D] = */ 4, + /* [BS3CG1DST_R15D] = */ 4, + + /* [BS3CG1DST_RAX] = */ 8, + /* [BS3CG1DST_RCX] = */ 8, + /* [BS3CG1DST_RDX] = */ 8, + /* [BS3CG1DST_RBX] = */ 8, + /* [BS3CG1DST_RSP] = */ 8, + /* [BS3CG1DST_RBP] = */ 8, + /* [BS3CG1DST_RSI] = */ 8, + /* [BS3CG1DST_RDI] = */ 8, + /* [BS3CG1DST_R8] = */ 8, + /* [BS3CG1DST_R9] = */ 8, + /* [BS3CG1DST_R10] = */ 8, + /* [BS3CG1DST_R11] = */ 8, + /* [BS3CG1DST_R12] = */ 8, + /* [BS3CG1DST_R13] = */ 8, + /* [BS3CG1DST_R14] = */ 8, + /* [BS3CG1DST_R15] = */ 8, + + /* [BS3CG1DST_OZ_RAX] = */ BS3CG1DSTSIZE_OPERAND_SIZE_GRP, + /* [BS3CG1DST_OZ_RCX] = */ BS3CG1DSTSIZE_OPERAND_SIZE_GRP, + /* [BS3CG1DST_OZ_RDX] = */ BS3CG1DSTSIZE_OPERAND_SIZE_GRP, + /* [BS3CG1DST_OZ_RBX] = */ BS3CG1DSTSIZE_OPERAND_SIZE_GRP, + /* [BS3CG1DST_OZ_RSP] = */ BS3CG1DSTSIZE_OPERAND_SIZE_GRP, + /* [BS3CG1DST_OZ_RBP] = */ BS3CG1DSTSIZE_OPERAND_SIZE_GRP, + /* [BS3CG1DST_OZ_RSI] = */ BS3CG1DSTSIZE_OPERAND_SIZE_GRP, + /* [BS3CG1DST_OZ_RDI] = */ BS3CG1DSTSIZE_OPERAND_SIZE_GRP, + /* [BS3CG1DST_OZ_R8] = */ BS3CG1DSTSIZE_OPERAND_SIZE_GRP, + /* [BS3CG1DST_OZ_R9] = */ BS3CG1DSTSIZE_OPERAND_SIZE_GRP, + /* [BS3CG1DST_OZ_R10] = */ BS3CG1DSTSIZE_OPERAND_SIZE_GRP, + /* [BS3CG1DST_OZ_R11] = */ BS3CG1DSTSIZE_OPERAND_SIZE_GRP, + /* [BS3CG1DST_OZ_R12] = */ BS3CG1DSTSIZE_OPERAND_SIZE_GRP, + /* [BS3CG1DST_OZ_R13] = */ BS3CG1DSTSIZE_OPERAND_SIZE_GRP, + /* [BS3CG1DST_OZ_R14] = */ BS3CG1DSTSIZE_OPERAND_SIZE_GRP, + /* [BS3CG1DST_OZ_R15] = */ BS3CG1DSTSIZE_OPERAND_SIZE_GRP, + + /* [BS3CG1DST_CR0] = */ 4, + /* [BS3CG1DST_CR4] = */ 4, + /* [BS3CG1DST_XCR0] = */ 8, + + /* [BS3CG1DST_FCW] = */ 2, + /* [BS3CG1DST_FSW] = */ 2, + /* [BS3CG1DST_FTW] = */ 2, + /* [BS3CG1DST_FOP] = */ 2, + /* [BS3CG1DST_FPUIP] = */ 2, + /* [BS3CG1DST_FPUCS] = */ 2, + /* [BS3CG1DST_FPUDP] = */ 2, + /* [BS3CG1DST_FPUDS] = */ 2, + /* [BS3CG1DST_MXCSR] = */ 4, + /* [BS3CG1DST_ST0] = */ 12, + /* [BS3CG1DST_ST1] = */ 12, + /* [BS3CG1DST_ST2] = */ 12, + /* [BS3CG1DST_ST3] = */ 12, + /* [BS3CG1DST_ST4] = */ 12, + /* [BS3CG1DST_ST5] = */ 12, + /* [BS3CG1DST_ST6] = */ 12, + /* [BS3CG1DST_ST7] = */ 12, + /* [BS3CG1DST_MM0] = */ 8, + /* [BS3CG1DST_MM1] = */ 8, + /* [BS3CG1DST_MM2] = */ 8, + /* [BS3CG1DST_MM3] = */ 8, + /* [BS3CG1DST_MM4] = */ 8, + /* [BS3CG1DST_MM5] = */ 8, + /* [BS3CG1DST_MM6] = */ 8, + /* [BS3CG1DST_MM7] = */ 8, + /* [BS3CG1DST_MM0_LO_ZX] = */ 4, + /* [BS3CG1DST_MM1_LO_ZX] = */ 4, + /* [BS3CG1DST_MM2_LO_ZX] = */ 4, + /* [BS3CG1DST_MM3_LO_ZX] = */ 4, + /* [BS3CG1DST_MM4_LO_ZX] = */ 4, + /* [BS3CG1DST_MM5_LO_ZX] = */ 4, + /* [BS3CG1DST_MM6_LO_ZX] = */ 4, + /* [BS3CG1DST_MM7_LO_ZX] = */ 4, + /* [BS3CG1DST_XMM0] = */ 16, + /* [BS3CG1DST_XMM1] = */ 16, + /* [BS3CG1DST_XMM2] = */ 16, + /* [BS3CG1DST_XMM3] = */ 16, + /* [BS3CG1DST_XMM4] = */ 16, + /* [BS3CG1DST_XMM5] = */ 16, + /* [BS3CG1DST_XMM6] = */ 16, + /* [BS3CG1DST_XMM7] = */ 16, + /* [BS3CG1DST_XMM8] = */ 16, + /* [BS3CG1DST_XMM9] = */ 16, + /* [BS3CG1DST_XMM10] = */ 16, + /* [BS3CG1DST_XMM11] = */ 16, + /* [BS3CG1DST_XMM12] = */ 16, + /* [BS3CG1DST_XMM13] = */ 16, + /* [BS3CG1DST_XMM14] = */ 16, + /* [BS3CG1DST_XMM15] = */ 16, + /* [BS3CG1DST_XMM0_LO] = */ 8, + /* [BS3CG1DST_XMM1_LO] = */ 8, + /* [BS3CG1DST_XMM2_LO] = */ 8, + /* [BS3CG1DST_XMM3_LO] = */ 8, + /* [BS3CG1DST_XMM4_LO] = */ 8, + /* [BS3CG1DST_XMM5_LO] = */ 8, + /* [BS3CG1DST_XMM6_LO] = */ 8, + /* [BS3CG1DST_XMM7_LO] = */ 8, + /* [BS3CG1DST_XMM8_LO] = */ 8, + /* [BS3CG1DST_XMM9_LO] = */ 8, + /* [BS3CG1DST_XMM10_LO] = */ 8, + /* [BS3CG1DST_XMM11_LO] = */ 8, + /* [BS3CG1DST_XMM12_LO] = */ 8, + /* [BS3CG1DST_XMM13_LO] = */ 8, + /* [BS3CG1DST_XMM14_LO] = */ 8, + /* [BS3CG1DST_XMM15_LO] = */ 8, + /* [BS3CG1DST_XMM0_HI] = */ 8, + /* [BS3CG1DST_XMM1_HI] = */ 8, + /* [BS3CG1DST_XMM2_HI] = */ 8, + /* [BS3CG1DST_XMM3_HI] = */ 8, + /* [BS3CG1DST_XMM4_HI] = */ 8, + /* [BS3CG1DST_XMM5_HI] = */ 8, + /* [BS3CG1DST_XMM6_HI] = */ 8, + /* [BS3CG1DST_XMM7_HI] = */ 8, + /* [BS3CG1DST_XMM8_HI] = */ 8, + /* [BS3CG1DST_XMM9_HI] = */ 8, + /* [BS3CG1DST_XMM10_HI] = */ 8, + /* [BS3CG1DST_XMM11_HI] = */ 8, + /* [BS3CG1DST_XMM12_HI] = */ 8, + /* [BS3CG1DST_XMM13_HI] = */ 8, + /* [BS3CG1DST_XMM14_HI] = */ 8, + /* [BS3CG1DST_XMM15_HI] = */ 8, + /* [BS3CG1DST_XMM0_LO_ZX] = */ 8, + /* [BS3CG1DST_XMM1_LO_ZX] = */ 8, + /* [BS3CG1DST_XMM2_LO_ZX] = */ 8, + /* [BS3CG1DST_XMM3_LO_ZX] = */ 8, + /* [BS3CG1DST_XMM4_LO_ZX] = */ 8, + /* [BS3CG1DST_XMM5_LO_ZX] = */ 8, + /* [BS3CG1DST_XMM6_LO_ZX] = */ 8, + /* [BS3CG1DST_XMM7_LO_ZX] = */ 8, + /* [BS3CG1DST_XMM8_LO_ZX] = */ 8, + /* [BS3CG1DST_XMM9_LO_ZX] = */ 8, + /* [BS3CG1DST_XMM10_LO_ZX] = */ 8, + /* [BS3CG1DST_XMM11_LO_ZX] = */ 8, + /* [BS3CG1DST_XMM12_LO_ZX] = */ 8, + /* [BS3CG1DST_XMM13_LO_ZX] = */ 8, + /* [BS3CG1DST_XMM14_LO_ZX] = */ 8, + /* [BS3CG1DST_XMM15_LO_ZX] = */ 8, + /* [BS3CG1DST_XMM0_DW0] = */ 4, + /* [BS3CG1DST_XMM1_DW0] = */ 4, + /* [BS3CG1DST_XMM2_DW0] = */ 4, + /* [BS3CG1DST_XMM3_DW0] = */ 4, + /* [BS3CG1DST_XMM4_DW0] = */ 4, + /* [BS3CG1DST_XMM5_DW0] = */ 4, + /* [BS3CG1DST_XMM6_DW0] = */ 4, + /* [BS3CG1DST_XMM7_DW0] = */ 4, + /* [BS3CG1DST_XMM8_DW0] = */ 4, + /* [BS3CG1DST_XMM9_DW0] = */ 4, + /* [BS3CG1DST_XMM10_DW0] = */ 4, + /* [BS3CG1DST_XMM11_DW0] = */ 4, + /* [BS3CG1DST_XMM12_DW0] = */ 4, + /* [BS3CG1DST_XMM13_DW0] = */ 4, + /* [BS3CG1DST_XMM14_DW0] = */ 4, + /* [BS3CG1DST_XMM15_DW0] = */ 4, + /* [BS3CG1DST_XMM0_DW0_ZX] = */ 4, + /* [BS3CG1DST_XMM1_DW0_ZX] = */ 4, + /* [BS3CG1DST_XMM2_DW0_ZX] = */ 4, + /* [BS3CG1DST_XMM3_DW0_ZX] = */ 4, + /* [BS3CG1DST_XMM4_DW0_ZX] = */ 4, + /* [BS3CG1DST_XMM5_DW0_ZX] = */ 4, + /* [BS3CG1DST_XMM6_DW0_ZX] = */ 4, + /* [BS3CG1DST_XMM7_DW0_ZX] = */ 4, + /* [BS3CG1DST_XMM8_DW0_ZX] = */ 4, + /* [BS3CG1DST_XMM9_DW0_ZX] = */ 4, + /* [BS3CG1DST_XMM10_DW0_ZX] =*/ 4, + /* [BS3CG1DST_XMM11_DW0_ZX] =*/ 4, + /* [BS3CG1DST_XMM12_DW0_ZX] =*/ 4, + /* [BS3CG1DST_XMM13_DW0_ZX] =*/ 4, + /* [BS3CG1DST_XMM14_DW0_ZX] =*/ 4, + /* [BS3CG1DST_XMM15_DW0_ZX] =*/ 4, + /* [BS3CG1DST_XMM0_HI96] = */ 12, + /* [BS3CG1DST_XMM1_HI96] = */ 12, + /* [BS3CG1DST_XMM2_HI96] = */ 12, + /* [BS3CG1DST_XMM3_HI96] = */ 12, + /* [BS3CG1DST_XMM4_HI96] = */ 12, + /* [BS3CG1DST_XMM5_HI96] = */ 12, + /* [BS3CG1DST_XMM6_HI96] = */ 12, + /* [BS3CG1DST_XMM7_HI96] = */ 12, + /* [BS3CG1DST_XMM8_HI96] = */ 12, + /* [BS3CG1DST_XMM9_HI96] = */ 12, + /* [BS3CG1DST_XMM10_HI96] =*/ 12, + /* [BS3CG1DST_XMM11_HI96] =*/ 12, + /* [BS3CG1DST_XMM12_HI96] =*/ 12, + /* [BS3CG1DST_XMM13_HI96] =*/ 12, + /* [BS3CG1DST_XMM14_HI96] =*/ 12, + /* [BS3CG1DST_XMM15_HI96] =*/ 12, + /* [BS3CG1DST_YMM0] = */ 32, + /* [BS3CG1DST_YMM1] = */ 32, + /* [BS3CG1DST_YMM2] = */ 32, + /* [BS3CG1DST_YMM3] = */ 32, + /* [BS3CG1DST_YMM4] = */ 32, + /* [BS3CG1DST_YMM5] = */ 32, + /* [BS3CG1DST_YMM6] = */ 32, + /* [BS3CG1DST_YMM7] = */ 32, + /* [BS3CG1DST_YMM8] = */ 32, + /* [BS3CG1DST_YMM9] = */ 32, + /* [BS3CG1DST_YMM10] = */ 32, + /* [BS3CG1DST_YMM11] = */ 32, + /* [BS3CG1DST_YMM12] = */ 32, + /* [BS3CG1DST_YMM13] = */ 32, + /* [BS3CG1DST_YMM14] = */ 32, + /* [BS3CG1DST_YMM15] = */ 32, + + /* [BS3CG1DST_VALUE_XCPT] = */ 1, +}; +AssertCompile(RT_ELEMENTS(g_acbBs3Cg1DstFields) == BS3CG1DST_END); + +/** Destination field offset indexed by bBS3CG1DST. + * Zero means operand size sized. */ +static const unsigned g_aoffBs3Cg1DstFields[] = +{ + /* [BS3CG1DST_INVALID] = */ ~0U, + /* [BS3CG1DST_OP1] = */ ~0U, + /* [BS3CG1DST_OP2] = */ ~0U, + /* [BS3CG1DST_OP3] = */ ~0U, + /* [BS3CG1DST_OP4] = */ ~0U, + /* [BS3CG1DST_EFL] = */ RT_OFFSETOF(BS3REGCTX, rflags), + /* [BS3CG1DST_EFL_UNDEF]=*/ ~0, /* special field */ + + /* [BS3CG1DST_AL] = */ RT_OFFSETOF(BS3REGCTX, rax.u8), + /* [BS3CG1DST_CL] = */ RT_OFFSETOF(BS3REGCTX, rcx.u8), + /* [BS3CG1DST_DL] = */ RT_OFFSETOF(BS3REGCTX, rdx.u8), + /* [BS3CG1DST_BL] = */ RT_OFFSETOF(BS3REGCTX, rbx.u8), + /* [BS3CG1DST_AH] = */ RT_OFFSETOF(BS3REGCTX, rax.b.bHi), + /* [BS3CG1DST_CH] = */ RT_OFFSETOF(BS3REGCTX, rcx.b.bHi), + /* [BS3CG1DST_DH] = */ RT_OFFSETOF(BS3REGCTX, rdx.b.bHi), + /* [BS3CG1DST_BH] = */ RT_OFFSETOF(BS3REGCTX, rbx.b.bHi), + /* [BS3CG1DST_SPL] = */ RT_OFFSETOF(BS3REGCTX, rsp.u8), + /* [BS3CG1DST_BPL] = */ RT_OFFSETOF(BS3REGCTX, rbp.u8), + /* [BS3CG1DST_SIL] = */ RT_OFFSETOF(BS3REGCTX, rsi.u8), + /* [BS3CG1DST_DIL] = */ RT_OFFSETOF(BS3REGCTX, rdi.u8), + /* [BS3CG1DST_R8L] = */ RT_OFFSETOF(BS3REGCTX, r8.u8), + /* [BS3CG1DST_R9L] = */ RT_OFFSETOF(BS3REGCTX, r9.u8), + /* [BS3CG1DST_R10L] = */ RT_OFFSETOF(BS3REGCTX, r10.u8), + /* [BS3CG1DST_R11L] = */ RT_OFFSETOF(BS3REGCTX, r11.u8), + /* [BS3CG1DST_R12L] = */ RT_OFFSETOF(BS3REGCTX, r12.u8), + /* [BS3CG1DST_R13L] = */ RT_OFFSETOF(BS3REGCTX, r13.u8), + /* [BS3CG1DST_R14L] = */ RT_OFFSETOF(BS3REGCTX, r14.u8), + /* [BS3CG1DST_R15L] = */ RT_OFFSETOF(BS3REGCTX, r15.u8), + + /* [BS3CG1DST_AX] = */ RT_OFFSETOF(BS3REGCTX, rax.u16), + /* [BS3CG1DST_CX] = */ RT_OFFSETOF(BS3REGCTX, rcx.u16), + /* [BS3CG1DST_DX] = */ RT_OFFSETOF(BS3REGCTX, rdx.u16), + /* [BS3CG1DST_BX] = */ RT_OFFSETOF(BS3REGCTX, rbx.u16), + /* [BS3CG1DST_SP] = */ RT_OFFSETOF(BS3REGCTX, rsp.u16), + /* [BS3CG1DST_BP] = */ RT_OFFSETOF(BS3REGCTX, rbp.u16), + /* [BS3CG1DST_SI] = */ RT_OFFSETOF(BS3REGCTX, rsi.u16), + /* [BS3CG1DST_DI] = */ RT_OFFSETOF(BS3REGCTX, rdi.u16), + /* [BS3CG1DST_R8W] = */ RT_OFFSETOF(BS3REGCTX, r8.u16), + /* [BS3CG1DST_R9W] = */ RT_OFFSETOF(BS3REGCTX, r9.u16), + /* [BS3CG1DST_R10W] = */ RT_OFFSETOF(BS3REGCTX, r10.u16), + /* [BS3CG1DST_R11W] = */ RT_OFFSETOF(BS3REGCTX, r11.u16), + /* [BS3CG1DST_R12W] = */ RT_OFFSETOF(BS3REGCTX, r12.u16), + /* [BS3CG1DST_R13W] = */ RT_OFFSETOF(BS3REGCTX, r13.u16), + /* [BS3CG1DST_R14W] = */ RT_OFFSETOF(BS3REGCTX, r14.u16), + /* [BS3CG1DST_R15W] = */ RT_OFFSETOF(BS3REGCTX, r15.u16), + + /* [BS3CG1DST_EAX] = */ RT_OFFSETOF(BS3REGCTX, rax.u32), + /* [BS3CG1DST_ECX] = */ RT_OFFSETOF(BS3REGCTX, rcx.u32), + /* [BS3CG1DST_EDX] = */ RT_OFFSETOF(BS3REGCTX, rdx.u32), + /* [BS3CG1DST_EBX] = */ RT_OFFSETOF(BS3REGCTX, rbx.u32), + /* [BS3CG1DST_ESP] = */ RT_OFFSETOF(BS3REGCTX, rsp.u32), + /* [BS3CG1DST_EBP] = */ RT_OFFSETOF(BS3REGCTX, rbp.u32), + /* [BS3CG1DST_ESI] = */ RT_OFFSETOF(BS3REGCTX, rsi.u32), + /* [BS3CG1DST_EDI] = */ RT_OFFSETOF(BS3REGCTX, rdi.u32), + /* [BS3CG1DST_R8D] = */ RT_OFFSETOF(BS3REGCTX, r8.u32), + /* [BS3CG1DST_R9D] = */ RT_OFFSETOF(BS3REGCTX, r9.u32), + /* [BS3CG1DST_R10D] = */ RT_OFFSETOF(BS3REGCTX, r10.u32), + /* [BS3CG1DST_R11D] = */ RT_OFFSETOF(BS3REGCTX, r11.u32), + /* [BS3CG1DST_R12D] = */ RT_OFFSETOF(BS3REGCTX, r12.u32), + /* [BS3CG1DST_R13D] = */ RT_OFFSETOF(BS3REGCTX, r13.u32), + /* [BS3CG1DST_R14D] = */ RT_OFFSETOF(BS3REGCTX, r14.u32), + /* [BS3CG1DST_R15D] = */ RT_OFFSETOF(BS3REGCTX, r15.u32), + + /* [BS3CG1DST_RAX] = */ RT_OFFSETOF(BS3REGCTX, rax.u64), + /* [BS3CG1DST_RCX] = */ RT_OFFSETOF(BS3REGCTX, rcx.u64), + /* [BS3CG1DST_RDX] = */ RT_OFFSETOF(BS3REGCTX, rdx.u64), + /* [BS3CG1DST_RBX] = */ RT_OFFSETOF(BS3REGCTX, rbx.u64), + /* [BS3CG1DST_RSP] = */ RT_OFFSETOF(BS3REGCTX, rsp.u64), + /* [BS3CG1DST_RBP] = */ RT_OFFSETOF(BS3REGCTX, rbp.u64), + /* [BS3CG1DST_RSI] = */ RT_OFFSETOF(BS3REGCTX, rsi.u64), + /* [BS3CG1DST_RDI] = */ RT_OFFSETOF(BS3REGCTX, rdi.u64), + /* [BS3CG1DST_R8] = */ RT_OFFSETOF(BS3REGCTX, r8.u64), + /* [BS3CG1DST_R9] = */ RT_OFFSETOF(BS3REGCTX, r9.u64), + /* [BS3CG1DST_R10] = */ RT_OFFSETOF(BS3REGCTX, r10.u64), + /* [BS3CG1DST_R11] = */ RT_OFFSETOF(BS3REGCTX, r11.u64), + /* [BS3CG1DST_R12] = */ RT_OFFSETOF(BS3REGCTX, r12.u64), + /* [BS3CG1DST_R13] = */ RT_OFFSETOF(BS3REGCTX, r13.u64), + /* [BS3CG1DST_R14] = */ RT_OFFSETOF(BS3REGCTX, r14.u64), + /* [BS3CG1DST_R15] = */ RT_OFFSETOF(BS3REGCTX, r15.u64), + + /* [BS3CG1DST_OZ_RAX] = */ RT_OFFSETOF(BS3REGCTX, rax), + /* [BS3CG1DST_OZ_RCX] = */ RT_OFFSETOF(BS3REGCTX, rcx), + /* [BS3CG1DST_OZ_RDX] = */ RT_OFFSETOF(BS3REGCTX, rdx), + /* [BS3CG1DST_OZ_RBX] = */ RT_OFFSETOF(BS3REGCTX, rbx), + /* [BS3CG1DST_OZ_RSP] = */ RT_OFFSETOF(BS3REGCTX, rsp), + /* [BS3CG1DST_OZ_RBP] = */ RT_OFFSETOF(BS3REGCTX, rbp), + /* [BS3CG1DST_OZ_RSI] = */ RT_OFFSETOF(BS3REGCTX, rsi), + /* [BS3CG1DST_OZ_RDI] = */ RT_OFFSETOF(BS3REGCTX, rdi), + /* [BS3CG1DST_OZ_R8] = */ RT_OFFSETOF(BS3REGCTX, r8), + /* [BS3CG1DST_OZ_R9] = */ RT_OFFSETOF(BS3REGCTX, r9), + /* [BS3CG1DST_OZ_R10] = */ RT_OFFSETOF(BS3REGCTX, r10), + /* [BS3CG1DST_OZ_R11] = */ RT_OFFSETOF(BS3REGCTX, r11), + /* [BS3CG1DST_OZ_R12] = */ RT_OFFSETOF(BS3REGCTX, r12), + /* [BS3CG1DST_OZ_R13] = */ RT_OFFSETOF(BS3REGCTX, r13), + /* [BS3CG1DST_OZ_R14] = */ RT_OFFSETOF(BS3REGCTX, r14), + /* [BS3CG1DST_OZ_R15] = */ RT_OFFSETOF(BS3REGCTX, r15), + + /* [BS3CG1DST_CR0] = */ RT_OFFSETOF(BS3REGCTX, cr0), + /* [BS3CG1DST_CR4] = */ RT_OFFSETOF(BS3REGCTX, cr4), + /* [BS3CG1DST_XCR0] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, fXcr0Saved), + + /* [BS3CG1DST_FCW] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.FCW), + /* [BS3CG1DST_FSW] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.FSW), + /* [BS3CG1DST_FTW] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.FTW), + /* [BS3CG1DST_FOP] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.FOP), + /* [BS3CG1DST_FPUIP] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.FPUIP), + /* [BS3CG1DST_FPUCS] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.CS), + /* [BS3CG1DST_FPUDP] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.FPUDP), + /* [BS3CG1DST_FPUDS] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.DS), + /* [BS3CG1DST_MXCSR] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.MXCSR), + /* [BS3CG1DST_ST0] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aRegs[0]), + /* [BS3CG1DST_ST1] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aRegs[1]), + /* [BS3CG1DST_ST2] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aRegs[2]), + /* [BS3CG1DST_ST3] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aRegs[3]), + /* [BS3CG1DST_ST4] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aRegs[4]), + /* [BS3CG1DST_ST5] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aRegs[5]), + /* [BS3CG1DST_ST6] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aRegs[6]), + /* [BS3CG1DST_ST7] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aRegs[7]), + /* [BS3CG1DST_MM0] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aRegs[0]), + /* [BS3CG1DST_MM1] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aRegs[1]), + /* [BS3CG1DST_MM2] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aRegs[2]), + /* [BS3CG1DST_MM3] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aRegs[3]), + /* [BS3CG1DST_MM4] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aRegs[4]), + /* [BS3CG1DST_MM5] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aRegs[5]), + /* [BS3CG1DST_MM6] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aRegs[6]), + /* [BS3CG1DST_MM7] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aRegs[7]), + /* [BS3CG1DST_MM0_LO_ZX] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aRegs[0]), + /* [BS3CG1DST_MM1_LO_ZX] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aRegs[1]), + /* [BS3CG1DST_MM2_LO_ZX] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aRegs[2]), + /* [BS3CG1DST_MM3_LO_ZX] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aRegs[3]), + /* [BS3CG1DST_MM4_LO_ZX] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aRegs[4]), + /* [BS3CG1DST_MM5_LO_ZX] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aRegs[5]), + /* [BS3CG1DST_MM6_LO_ZX] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aRegs[6]), + /* [BS3CG1DST_MM7_LO_ZX] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aRegs[7]), + + /* [BS3CG1DST_XMM0] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[0]), + /* [BS3CG1DST_XMM1] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[1]), + /* [BS3CG1DST_XMM2] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[2]), + /* [BS3CG1DST_XMM3] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[3]), + /* [BS3CG1DST_XMM4] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[4]), + /* [BS3CG1DST_XMM5] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[5]), + /* [BS3CG1DST_XMM6] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[6]), + /* [BS3CG1DST_XMM7] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[7]), + /* [BS3CG1DST_XMM8] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[8]), + /* [BS3CG1DST_XMM9] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[9]), + /* [BS3CG1DST_XMM10] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[10]), + /* [BS3CG1DST_XMM11] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[11]), + /* [BS3CG1DST_XMM12] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[12]), + /* [BS3CG1DST_XMM13] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[13]), + /* [BS3CG1DST_XMM14] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[14]), + /* [BS3CG1DST_XMM15] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[15]), + /* [BS3CG1DST_XMM0_LO] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[0]), + /* [BS3CG1DST_XMM1_LO] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[1]), + /* [BS3CG1DST_XMM2_LO] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[2]), + /* [BS3CG1DST_XMM3_LO] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[3]), + /* [BS3CG1DST_XMM4_LO] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[4]), + /* [BS3CG1DST_XMM5_LO] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[5]), + /* [BS3CG1DST_XMM6_LO] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[6]), + /* [BS3CG1DST_XMM7_LO] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[7]), + /* [BS3CG1DST_XMM8_LO] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[8]), + /* [BS3CG1DST_XMM9_LO] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[9]), + /* [BS3CG1DST_XMM10_LO] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[10]), + /* [BS3CG1DST_XMM11_LO] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[11]), + /* [BS3CG1DST_XMM12_LO] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[12]), + /* [BS3CG1DST_XMM13_LO] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[13]), + /* [BS3CG1DST_XMM14_LO] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[14]), + /* [BS3CG1DST_XMM15_LO] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[15]), + /* [BS3CG1DST_XMM0_HI] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[0]) + sizeof(uint64_t), + /* [BS3CG1DST_XMM1_HI] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[1]) + sizeof(uint64_t), + /* [BS3CG1DST_XMM2_HI] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[2]) + sizeof(uint64_t), + /* [BS3CG1DST_XMM3_HI] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[3]) + sizeof(uint64_t), + /* [BS3CG1DST_XMM4_HI] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[4]) + sizeof(uint64_t), + /* [BS3CG1DST_XMM5_HI] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[5]) + sizeof(uint64_t), + /* [BS3CG1DST_XMM6_HI] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[6]) + sizeof(uint64_t), + /* [BS3CG1DST_XMM7_HI] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[7]) + sizeof(uint64_t), + /* [BS3CG1DST_XMM8_HI] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[8]) + sizeof(uint64_t), + /* [BS3CG1DST_XMM9_HI] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[9]) + sizeof(uint64_t), + /* [BS3CG1DST_XMM10_HI] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[10]) + sizeof(uint64_t), + /* [BS3CG1DST_XMM11_HI] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[11]) + sizeof(uint64_t), + /* [BS3CG1DST_XMM12_HI] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[12]) + sizeof(uint64_t), + /* [BS3CG1DST_XMM13_HI] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[13]) + sizeof(uint64_t), + /* [BS3CG1DST_XMM14_HI] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[14]) + sizeof(uint64_t), + /* [BS3CG1DST_XMM15_HI] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[15]) + sizeof(uint64_t), + /* [BS3CG1DST_XMM0_LO_ZX] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[0]), + /* [BS3CG1DST_XMM1_LO_ZX] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[1]), + /* [BS3CG1DST_XMM2_LO_ZX] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[2]), + /* [BS3CG1DST_XMM3_LO_ZX] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[3]), + /* [BS3CG1DST_XMM4_LO_ZX] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[4]), + /* [BS3CG1DST_XMM5_LO_ZX] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[5]), + /* [BS3CG1DST_XMM6_LO_ZX] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[6]), + /* [BS3CG1DST_XMM7_LO_ZX] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[7]), + /* [BS3CG1DST_XMM8_LO_ZX] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[8]), + /* [BS3CG1DST_XMM9_LO_ZX] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[9]), + /* [BS3CG1DST_XMM10_LO_ZX] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[10]), + /* [BS3CG1DST_XMM11_LO_ZX] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[11]), + /* [BS3CG1DST_XMM12_LO_ZX] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[12]), + /* [BS3CG1DST_XMM13_LO_ZX] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[13]), + /* [BS3CG1DST_XMM14_LO_ZX] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[14]), + /* [BS3CG1DST_XMM15_LO_ZX] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[15]), + /* [BS3CG1DST_XMM0_DW0] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[0]), + /* [BS3CG1DST_XMM1_DW0] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[1]), + /* [BS3CG1DST_XMM2_DW0] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[2]), + /* [BS3CG1DST_XMM3_DW0] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[3]), + /* [BS3CG1DST_XMM4_DW0] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[4]), + /* [BS3CG1DST_XMM5_DW0] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[5]), + /* [BS3CG1DST_XMM6_DW0] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[6]), + /* [BS3CG1DST_XMM7_DW0] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[7]), + /* [BS3CG1DST_XMM8_DW0] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[8]), + /* [BS3CG1DST_XMM9_DW0] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[9]), + /* [BS3CG1DST_XMM10_DW0] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[10]), + /* [BS3CG1DST_XMM11_DW0] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[11]), + /* [BS3CG1DST_XMM12_DW0] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[12]), + /* [BS3CG1DST_XMM13_DW0] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[13]), + /* [BS3CG1DST_XMM14_DW0] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[14]), + /* [BS3CG1DST_XMM15_DW0] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[15]), + /* [BS3CG1DST_XMM0_DW0_ZX] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[0]), + /* [BS3CG1DST_XMM1_DW0_ZX] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[1]), + /* [BS3CG1DST_XMM2_DW0_ZX] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[2]), + /* [BS3CG1DST_XMM3_DW0_ZX] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[3]), + /* [BS3CG1DST_XMM4_DW0_ZX] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[4]), + /* [BS3CG1DST_XMM5_DW0_ZX] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[5]), + /* [BS3CG1DST_XMM6_DW0_ZX] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[6]), + /* [BS3CG1DST_XMM7_DW0_ZX] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[7]), + /* [BS3CG1DST_XMM8_DW0_ZX] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[8]), + /* [BS3CG1DST_XMM9_DW0_ZX] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[9]), + /* [BS3CG1DST_XMM10_DW0_ZX] =*/ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[10]), + /* [BS3CG1DST_XMM11_DW0_ZX] =*/ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[11]), + /* [BS3CG1DST_XMM12_DW0_ZX] =*/ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[12]), + /* [BS3CG1DST_XMM13_DW0_ZX] =*/ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[13]), + /* [BS3CG1DST_XMM14_DW0_ZX] =*/ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[14]), + /* [BS3CG1DST_XMM15_DW0_ZX] =*/ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[15]), + /* [BS3CG1DST_XMM0_HI96] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[0].au32[1]), + /* [BS3CG1DST_XMM1_HI96] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[1].au32[1]), + /* [BS3CG1DST_XMM2_HI96] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[2].au32[1]), + /* [BS3CG1DST_XMM3_HI96] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[3].au32[1]), + /* [BS3CG1DST_XMM4_HI96] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[4].au32[1]), + /* [BS3CG1DST_XMM5_HI96] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[5].au32[1]), + /* [BS3CG1DST_XMM6_HI96] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[6].au32[1]), + /* [BS3CG1DST_XMM7_HI96] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[7].au32[1]), + /* [BS3CG1DST_XMM8_HI96] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[8].au32[1]), + /* [BS3CG1DST_XMM9_HI96] = */ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[9].au32[1]), + /* [BS3CG1DST_XMM10_HI96] =*/ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[10].au32[1]), + /* [BS3CG1DST_XMM11_HI96] =*/ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[11].au32[1]), + /* [BS3CG1DST_XMM12_HI96] =*/ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[12].au32[1]), + /* [BS3CG1DST_XMM13_HI96] =*/ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[13].au32[1]), + /* [BS3CG1DST_XMM14_HI96] =*/ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[14].au32[1]), + /* [BS3CG1DST_XMM15_HI96] =*/ sizeof(BS3REGCTX) + RT_OFFSETOF(BS3EXTCTX, Ctx.x87.aXMM[15].au32[1]), + + /* [BS3CG1DST_YMM0] = */ ~0U, + /* [BS3CG1DST_YMM1] = */ ~0U, + /* [BS3CG1DST_YMM2] = */ ~0U, + /* [BS3CG1DST_YMM3] = */ ~0U, + /* [BS3CG1DST_YMM4] = */ ~0U, + /* [BS3CG1DST_YMM5] = */ ~0U, + /* [BS3CG1DST_YMM6] = */ ~0U, + /* [BS3CG1DST_YMM7] = */ ~0U, + /* [BS3CG1DST_YMM8] = */ ~0U, + /* [BS3CG1DST_YMM9] = */ ~0U, + /* [BS3CG1DST_YMM10] = */ ~0U, + /* [BS3CG1DST_YMM11] = */ ~0U, + /* [BS3CG1DST_YMM12] = */ ~0U, + /* [BS3CG1DST_YMM13] = */ ~0U, + /* [BS3CG1DST_YMM14] = */ ~0U, + /* [BS3CG1DST_YMM15] = */ ~0U, + + /* [BS3CG1DST_VALUE_XCPT] = */ ~0U, +}; +AssertCompile(RT_ELEMENTS(g_aoffBs3Cg1DstFields) == BS3CG1DST_END); + +/** Destination field names. */ +static const struct { char sz[12]; } g_aszBs3Cg1DstFields[] = +{ + { "INVALID" }, + { "OP1" }, + { "OP2" }, + { "OP3" }, + { "OP4" }, + { "EFL" }, + { "EFL_UND" }, + + { "AL" }, + { "CL" }, + { "DL" }, + { "BL" }, + { "AH" }, + { "CH" }, + { "DH" }, + { "BH" }, + { "SPL" }, + { "BPL" }, + { "SIL" }, + { "DIL" }, + { "R8L" }, + { "R9L" }, + { "R10L" }, + { "R11L" }, + { "R12L" }, + { "R13L" }, + { "R14L" }, + { "R15L" }, + + { "AX" }, + { "CX" }, + { "DX" }, + { "BX" }, + { "SP" }, + { "BP" }, + { "SI" }, + { "DI" }, + { "R8W" }, + { "R9W" }, + { "R10W" }, + { "R11W" }, + { "R12W" }, + { "R13W" }, + { "R14W" }, + { "R15W" }, + + { "EAX" }, + { "ECX" }, + { "EDX" }, + { "EBX" }, + { "ESP" }, + { "EBP" }, + { "ESI" }, + { "EDI" }, + { "R8D" }, + { "R9D" }, + { "R10D" }, + { "R11D" }, + { "R12D" }, + { "R13D" }, + { "R14D" }, + { "R15D" }, + + { "RAX" }, + { "RCX" }, + { "RDX" }, + { "RBX" }, + { "RSP" }, + { "RBP" }, + { "RSI" }, + { "RDI" }, + { "R8" }, + { "R9" }, + { "R10" }, + { "R11" }, + { "R12" }, + { "R13" }, + { "R14" }, + { "R15" }, + + { "OZ_RAX" }, + { "OZ_RCX" }, + { "OZ_RDX" }, + { "OZ_RBX" }, + { "OZ_RSP" }, + { "OZ_RBP" }, + { "OZ_RSI" }, + { "OZ_RDI" }, + { "OZ_R8" }, + { "OZ_R9" }, + { "OZ_R10" }, + { "OZ_R11" }, + { "OZ_R12" }, + { "OZ_R13" }, + { "OZ_R14" }, + { "OZ_R15" }, + + { "CR0" }, + { "CR4" }, + { "XCR0" }, + + { "FCW" }, + { "FSW" }, + { "FTW" }, + { "FOP" }, + { "FPUIP" }, + { "FPUCS" }, + { "FPUDP" }, + { "FPUDS" }, + { "MXCSR" }, + { "ST0" }, + { "ST1" }, + { "ST2" }, + { "ST3" }, + { "ST4" }, + { "ST5" }, + { "ST6" }, + { "ST7" }, + { "MM0" }, + { "MM1" }, + { "MM2" }, + { "MM3" }, + { "MM4" }, + { "MM5" }, + { "MM6" }, + { "MM7" }, + { "MM0_LO_ZX" }, + { "MM1_LO_ZX" }, + { "MM2_LO_ZX" }, + { "MM3_LO_ZX" }, + { "MM4_LO_ZX" }, + { "MM5_LO_ZX" }, + { "MM6_LO_ZX" }, + { "MM7_LO_ZX" }, + { "XMM0" }, + { "XMM1" }, + { "XMM2" }, + { "XMM3" }, + { "XMM4" }, + { "XMM5" }, + { "XMM6" }, + { "XMM7" }, + { "XMM8" }, + { "XMM9" }, + { "XMM10" }, + { "XMM11" }, + { "XMM12" }, + { "XMM13" }, + { "XMM14" }, + { "XMM15" }, + { "XMM0_LO" }, + { "XMM1_LO" }, + { "XMM2_LO" }, + { "XMM3_LO" }, + { "XMM4_LO" }, + { "XMM5_LO" }, + { "XMM6_LO" }, + { "XMM7_LO" }, + { "XMM8_LO" }, + { "XMM9_LO" }, + { "XMM10_LO" }, + { "XMM11_LO" }, + { "XMM12_LO" }, + { "XMM13_LO" }, + { "XMM14_LO" }, + { "XMM15_LO" }, + { "XMM0_HI" }, + { "XMM1_HI" }, + { "XMM2_HI" }, + { "XMM3_HI" }, + { "XMM4_HI" }, + { "XMM5_HI" }, + { "XMM6_HI" }, + { "XMM7_HI" }, + { "XMM8_HI" }, + { "XMM9_HI" }, + { "XMM10_HI" }, + { "XMM11_HI" }, + { "XMM12_HI" }, + { "XMM13_HI" }, + { "XMM14_HI" }, + { "XMM15_HI" }, + { "XMM0_LO_ZX" }, + { "XMM1_LO_ZX" }, + { "XMM2_LO_ZX" }, + { "XMM3_LO_ZX" }, + { "XMM4_LO_ZX" }, + { "XMM5_LO_ZX" }, + { "XMM6_LO_ZX" }, + { "XMM7_LO_ZX" }, + { "XMM8_LO_ZX" }, + { "XMM9_LO_ZX" }, + { "XMM10_LO_ZX" }, + { "XMM11_LO_ZX" }, + { "XMM12_LO_ZX" }, + { "XMM13_LO_ZX" }, + { "XMM14_LO_ZX" }, + { "XMM15_LO_ZX" }, + { "XMM0_DW0" }, + { "XMM1_DW0" }, + { "XMM2_DW0" }, + { "XMM3_DW0" }, + { "XMM4_DW0" }, + { "XMM5_DW0" }, + { "XMM6_DW0" }, + { "XMM7_DW0" }, + { "XMM8_DW0" }, + { "XMM9_DW0" }, + { "XMM10_DW0" }, + { "XMM11_DW0" }, + { "XMM12_DW0" }, + { "XMM13_DW0" }, + { "XMM14_DW0" }, + { "XMM15_DW0" }, + { "XMM0_DW0_ZX" }, + { "XMM1_DW0_ZX" }, + { "XMM2_DW0_ZX" }, + { "XMM3_DW0_ZX" }, + { "XMM4_DW0_ZX" }, + { "XMM5_DW0_ZX" }, + { "XMM6_DW0_ZX" }, + { "XMM7_DW0_ZX" }, + { "XMM8_DW0_ZX" }, + { "XMM9_DW0_ZX" }, + { "XMM10_DW0_ZX" }, + { "XMM11_DW0_ZX" }, + { "XMM12_DW0_ZX" }, + { "XMM13_DW0_ZX" }, + { "XMM14_DW0_ZX" }, + { "XMM15_DW0_ZX" }, + { "XMM0_HI96" }, + { "XMM1_HI96" }, + { "XMM2_HI96" }, + { "XMM3_HI96" }, + { "XMM4_HI96" }, + { "XMM5_HI96" }, + { "XMM6_HI96" }, + { "XMM7_HI96" }, + { "XMM8_HI96" }, + { "XMM9_HI96" }, + { "XMM10_HI96" }, + { "XMM11_HI96" }, + { "XMM12_HI96" }, + { "XMM13_HI96" }, + { "XMM14_HI96" }, + { "XMM15_HI96" }, + { "YMM0" }, + { "YMM1" }, + { "YMM2" }, + { "YMM3" }, + { "YMM4" }, + { "YMM5" }, + { "YMM6" }, + { "YMM7" }, + { "YMM8" }, + { "YMM9" }, + { "YMM10" }, + { "YMM11" }, + { "YMM12" }, + { "YMM13" }, + { "YMM14" }, + { "YMM15" }, + + { "VALXCPT" }, +}; +AssertCompile(RT_ELEMENTS(g_aszBs3Cg1DstFields) >= BS3CG1DST_END); +AssertCompile(RT_ELEMENTS(g_aszBs3Cg1DstFields) == BS3CG1DST_END); + + +#if 0 +static const struct +{ + uint8_t cbPrefixes; + uint8_t abPrefixes[14]; + uint16_t fEffective; +} g_aPrefixVariations[] = +{ + { 0, { 0x00 }, BS3CG1_PF_NONE }, + + { 1, { P_OZ }, BS3CG1_PF_OZ }, + { 1, { P_CS }, BS3CG1_PF_CS }, + { 1, { P_DS }, BS3CG1_PF_DS }, + { 1, { P_ES }, BS3CG1_PF_ES }, + { 1, { P_FS }, BS3CG1_PF_FS }, + { 1, { P_GS }, BS3CG1_PF_GS }, + { 1, { P_SS }, BS3CG1_PF_SS }, + { 1, { P_LK }, BS3CG1_PF_LK }, + + { 2, { P_CS, P_OZ, }, BS3CG1_PF_CS | BS3CFG1_PF_OZ }, + { 2, { P_DS, P_OZ, }, BS3CG1_PF_DS | BS3CFG1_PF_OZ }, + { 2, { P_ES, P_OZ, }, BS3CG1_PF_ES | BS3CFG1_PF_OZ }, + { 2, { P_FS, P_OZ, }, BS3CG1_PF_FS | BS3CFG1_PF_OZ }, + { 2, { P_GS, P_OZ, }, BS3CG1_PF_GS | BS3CFG1_PF_OZ }, + { 2, { P_GS, P_OZ, }, BS3CG1_PF_SS | BS3CFG1_PF_OZ }, + { 2, { P_SS, P_OZ, }, BS3CG1_PF_SS | BS3CFG1_PF_OZ }, + + { 2, { P_OZ, P_CS, }, BS3CG1_PF_CS | BS3CFG1_PF_OZ }, + { 2, { P_OZ, P_DS, }, BS3CG1_PF_DS | BS3CFG1_PF_OZ }, + { 2, { P_OZ, P_ES, }, BS3CG1_PF_ES | BS3CFG1_PF_OZ }, + { 2, { P_OZ, P_FS, }, BS3CG1_PF_FS | BS3CFG1_PF_OZ }, + { 2, { P_OZ, P_GS, }, BS3CG1_PF_GS | BS3CFG1_PF_OZ }, + { 2, { P_OZ, P_GS, }, BS3CG1_PF_SS | BS3CFG1_PF_OZ }, + { 2, { P_OZ, P_SS, }, BS3CG1_PF_SS | BS3CFG1_PF_OZ }, +}; + +static const uint16_t g_afPfxKindToIgnoredFlags[BS3CG1PFXKIND_END] = +{ + /* [BS3CG1PFXKIND_INVALID] = */ UINT16_MAX, + /* [BS3CG1PFXKIND_MODRM] = */ 0, + /* [BS3CG1PFXKIND_MODRM_NO_OP_SIZES] = */ BS3CG1_PF_OZ | BS3CG1_PF_W, +}; + +#endif + + +/** + * Checks if >= 16 byte SSE alignment are exempted for the exception type. + * + * @returns true / false. + * @param enmXcptType The type to check. + */ +static bool BS3_NEAR_CODE Bs3Cg1XcptTypeIsUnaligned(BS3CG1XCPTTYPE enmXcptType) +{ + switch (enmXcptType) + { + case BS3CG1XCPTTYPE_1: + case BS3CG1XCPTTYPE_2: + case BS3CG1XCPTTYPE_4: + return false; + case BS3CG1XCPTTYPE_NONE: + case BS3CG1XCPTTYPE_3: + case BS3CG1XCPTTYPE_4UA: + case BS3CG1XCPTTYPE_5: + return true; + default: + return false; + } +} + + +/** + * Checks if >= 16 byte AVX alignment are exempted for the exception type. + * + * @returns true / false. + * @param enmXcptType The type to check. + */ +static bool BS3_NEAR_CODE Bs3Cg1XcptTypeIsVexUnaligned(BS3CG1XCPTTYPE enmXcptType) +{ + switch (enmXcptType) + { + case BS3CG1XCPTTYPE_1: + return false; + + case BS3CG1XCPTTYPE_NONE: + case BS3CG1XCPTTYPE_2: + case BS3CG1XCPTTYPE_3: + case BS3CG1XCPTTYPE_4: + case BS3CG1XCPTTYPE_4UA: + case BS3CG1XCPTTYPE_5: + case BS3CG1XCPTTYPE_6: + case BS3CG1XCPTTYPE_11: + case BS3CG1XCPTTYPE_12: + return true; + + default: + return false; + } +} + + +DECLINLINE(unsigned) BS3_NEAR_CODE Bs3Cg1InsertReqPrefix(PBS3CG1STATE pThis, unsigned offDst) +{ + switch (pThis->enmPrefixKind) + { + case BS3CG1PFXKIND_REQ_66: + pThis->abCurInstr[offDst] = 0x66; + break; + case BS3CG1PFXKIND_REQ_F2: + pThis->abCurInstr[offDst] = 0xf2; + break; + case BS3CG1PFXKIND_REQ_F3: + pThis->abCurInstr[offDst] = 0xf3; + break; + default: + return offDst; + } + return offDst + 1; +} + + +DECLINLINE(unsigned) BS3_NEAR_CODE Bs3Cg1InsertOpcodes(PBS3CG1STATE pThis, unsigned offDst) +{ + switch (pThis->cbOpcodes) + { + case 4: pThis->abCurInstr[offDst + 3] = pThis->abOpcodes[3]; + case 3: pThis->abCurInstr[offDst + 2] = pThis->abOpcodes[2]; + case 2: pThis->abCurInstr[offDst + 1] = pThis->abOpcodes[1]; + case 1: pThis->abCurInstr[offDst] = pThis->abOpcodes[0]; + return offDst + pThis->cbOpcodes; + + default: + BS3_ASSERT(0); + return 0; + } +} + + +/** + * Inserts a ModR/M byte with mod=3 and set the two idxFields members. + * + * @returns off + 1. + * @param pThis The state. + * @param off Current instruction offset. + * @param uReg Register index for ModR/M.reg. + * @param uRegMem Register index for ModR/M.rm. + */ +static unsigned Bs3Cg1InsertModRmWithRegFields(PBS3CG1STATE pThis, unsigned off, uint8_t uReg, uint8_t uRegMem) +{ + pThis->abCurInstr[off++] = X86_MODRM_MAKE(3, uReg & 7, uRegMem & 7); + pThis->aOperands[pThis->iRegOp].idxField = pThis->aOperands[pThis->iRegOp].idxFieldBase + uReg; + pThis->aOperands[pThis->iRmOp ].idxField = pThis->aOperands[pThis->iRmOp ].idxFieldBase + uRegMem; + return off; +} + + + +/** + * Cleans up state and context changes made by the encoder. + * + * @param pThis The state. + */ +static void BS3_NEAR_CODE Bs3Cg1EncodeCleanup(PBS3CG1STATE pThis) +{ + /* Restore the DS registers in the contexts. */ + unsigned iRing = 4; + while (iRing-- > 0) + pThis->aInitialCtxs[iRing].ds = pThis->aSavedSegRegs[iRing].ds; + + switch (pThis->enmEncoding) + { + /* Most encodings currently doesn't need any special cleaning up. */ + default: + return; + } +} + + +static unsigned BS3_NEAR_CODE Bs3Cfg1EncodeMemMod0Disp(PBS3CG1STATE pThis, bool fAddrOverride, unsigned off, uint8_t iReg, + uint8_t cbOp, uint8_t cbMisalign, BS3CG1OPLOC enmLocation) +{ + pThis->aOperands[pThis->iRmOp].idxField = BS3CG1DST_INVALID; + pThis->aOperands[pThis->iRmOp].enmLocation = enmLocation; + pThis->aOperands[pThis->iRmOp].cbOp = cbOp; + pThis->aOperands[pThis->iRmOp].off = cbOp + cbMisalign; + + if ( BS3_MODE_IS_16BIT_CODE(pThis->bMode) + || (fAddrOverride && BS3_MODE_IS_32BIT_CODE(pThis->bMode)) ) + { + /* + * 16-bit code doing 16-bit or 32-bit addressing, + * or 32-bit code doing 16-bit addressing. + */ + unsigned iRing = 4; + if (BS3_MODE_IS_RM_OR_V86(pThis->bMode)) + while (iRing-- > 0) + pThis->aInitialCtxs[iRing].ds = pThis->DataPgFar.sel; + else + while (iRing-- > 0) + pThis->aInitialCtxs[iRing].ds = pThis->DataPgFar.sel | iRing; + if (!fAddrOverride || BS3_MODE_IS_32BIT_CODE(pThis->bMode)) + { + pThis->abCurInstr[off++] = X86_MODRM_MAKE(0, iReg, 6 /*disp16*/); + *(uint16_t *)&pThis->abCurInstr[off] = pThis->DataPgFar.off + X86_PAGE_SIZE - cbOp - cbMisalign; + off += 2; + } + else + { + pThis->abCurInstr[off++] = X86_MODRM_MAKE(0, iReg, 5 /*disp32*/); + *(uint32_t *)&pThis->abCurInstr[off] = pThis->DataPgFar.off + X86_PAGE_SIZE - cbOp - cbMisalign; + off += 4; + } + } + else + { + /* + * 32-bit code doing 32-bit addressing, + * or 64-bit code doing either 64-bit or 32-bit addressing. + */ + pThis->abCurInstr[off++] = X86_MODRM_MAKE(0, iReg, 5 /*disp32*/); + *(uint32_t *)&pThis->abCurInstr[off] = BS3_FP_OFF(pThis->pbDataPg) + X86_PAGE_SIZE - cbOp - cbMisalign; + +#if ARCH_BITS == 64 + /* In 64-bit mode we always have a rip relative encoding regardless of fAddrOverride. */ + if (BS3CG1_IS_64BIT_TARGET(pThis)) + *(uint32_t *)&pThis->abCurInstr[off] -= BS3_FP_OFF(&pThis->pbCodePg[X86_PAGE_SIZE]); +#endif + off += 4; + } + + /* + * Fill the memory with 0xcc. + */ + switch (cbOp + cbMisalign) + { + case 8: pThis->pbDataPg[X86_PAGE_SIZE - 8] = 0xcc; RT_FALL_THRU(); + case 7: pThis->pbDataPg[X86_PAGE_SIZE - 7] = 0xcc; RT_FALL_THRU(); + case 6: pThis->pbDataPg[X86_PAGE_SIZE - 6] = 0xcc; RT_FALL_THRU(); + case 5: pThis->pbDataPg[X86_PAGE_SIZE - 5] = 0xcc; RT_FALL_THRU(); + case 4: pThis->pbDataPg[X86_PAGE_SIZE - 4] = 0xcc; RT_FALL_THRU(); + case 3: pThis->pbDataPg[X86_PAGE_SIZE - 3] = 0xcc; RT_FALL_THRU(); + case 2: pThis->pbDataPg[X86_PAGE_SIZE - 2] = 0xcc; RT_FALL_THRU(); + case 1: pThis->pbDataPg[X86_PAGE_SIZE - 1] = 0xcc; RT_FALL_THRU(); + case 0: break; + default: + { + BS3CG1_DPRINTF(("Bs3MemSet(%p,%#x,%#x)\n", &pThis->pbDataPg[X86_PAGE_SIZE - cbOp - cbMisalign], 0xcc, cbOp - cbMisalign)); + Bs3MemSet(&pThis->pbDataPg[X86_PAGE_SIZE - cbOp - cbMisalign], 0xcc, cbOp - cbMisalign); + break; + } + } + + return off; +} + + +#if 0 /* unused */ +/** Also encodes idxField of the register operand using idxFieldBase. */ +static unsigned BS3_NEAR_CODE +Bs3Cfg1EncodeMemMod0DispWithRegField(PBS3CG1STATE pThis, bool fAddrOverride, unsigned off, uint8_t iReg, + uint8_t cbOp, uint8_t cbMisalign, BS3CG1OPLOC enmLocation) +{ + pThis->aOperands[pThis->iRegOp].idxField = pThis->aOperands[pThis->iRegOp].idxFieldBase + iReg; + return Bs3Cfg1EncodeMemMod0Disp(pThis, fAddrOverride, off, iReg & 7, cbOp, cbMisalign, enmLocation); +} +#endif + +/** Also encodes idxField of the register operand using idxFieldBase. */ +static unsigned BS3_NEAR_CODE +Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(PBS3CG1STATE pThis, unsigned off, uint8_t iReg) +{ + pThis->aOperands[pThis->iRegOp].idxField = pThis->aOperands[pThis->iRegOp].idxFieldBase + iReg; + return Bs3Cfg1EncodeMemMod0Disp(pThis, false /*fAddrOverride*/, off, iReg & 7, + pThis->aOperands[pThis->iRmOp].cbOp, + 0 /*cbMisalign*/, + pThis->aOperands[pThis->iRmOp].enmLocation); +} + +/** Also encodes idxField of the register operand using idxFieldBase. */ +static unsigned BS3_NEAR_CODE +Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaultsAddrOverride(PBS3CG1STATE pThis, unsigned off, uint8_t iReg) +{ + pThis->aOperands[pThis->iRegOp].idxField = pThis->aOperands[pThis->iRegOp].idxFieldBase + iReg; + return Bs3Cfg1EncodeMemMod0Disp(pThis, true /*fAddrOverride*/, off, iReg & 7, + pThis->aOperands[pThis->iRmOp].cbOp, + 0 /*cbMisalign*/, + pThis->aOperands[pThis->iRmOp].enmLocation); +} + + +/** Also encodes idxField of the register operand using idxFieldBase. */ +static unsigned BS3_NEAR_CODE +Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaultsMisaligned(PBS3CG1STATE pThis, unsigned off, uint8_t iReg, uint8_t cbMisalign) +{ + pThis->aOperands[pThis->iRegOp].idxField = pThis->aOperands[pThis->iRegOp].idxFieldBase + iReg; + return Bs3Cfg1EncodeMemMod0Disp(pThis, false /*fAddrOverride*/, off, iReg & 7, + pThis->aOperands[pThis->iRmOp].cbOp, + cbMisalign, + pThis->aOperands[pThis->iRmOp].enmLocation); +} + + +/** Also encodes idxField of the register operand using idxFieldBase. */ +static unsigned BS3_NEAR_CODE +Bs3Cfg1EncodeMemMod0DispWithRegFieldAndSizeAndDefaults(PBS3CG1STATE pThis, unsigned off, uint8_t iReg, uint8_t cbOp) +{ + pThis->aOperands[pThis->iRegOp].idxField = pThis->aOperands[pThis->iRegOp].idxFieldBase + iReg; + return Bs3Cfg1EncodeMemMod0Disp(pThis, false /*fAddrOverride*/, off, iReg & 7, cbOp, 0 /*cbMisalign*/, + pThis->aOperands[pThis->iRmOp].enmLocation); +} + +/** Also encodes idxField of the register operand using idxFieldBase. */ +static unsigned BS3_NEAR_CODE +Bs3Cfg1EncodeMemMod0DispWithRegFieldAndSizeAndDefaultsAddrOverride(PBS3CG1STATE pThis, unsigned off, uint8_t iReg, uint8_t cbOp) +{ + pThis->aOperands[pThis->iRegOp].idxField = pThis->aOperands[pThis->iRegOp].idxFieldBase + iReg; + return Bs3Cfg1EncodeMemMod0Disp(pThis, true /*fAddrOverride*/, off, iReg & 7, cbOp, 0 /*cbMisalign*/, + pThis->aOperands[pThis->iRmOp].enmLocation); +} + + +/** The modrm.reg value is taken from the instruction byte at @a off. */ +static unsigned BS3_NEAR_CODE +Bs3Cfg1EncodeMemMod0DispWithDefaultsAndNoReg(PBS3CG1STATE pThis, unsigned off) +{ + return Bs3Cfg1EncodeMemMod0Disp(pThis, false /*fAddrOverride*/, off, + (pThis->abCurInstr[off] & X86_MODRM_REG_MASK) >> X86_MODRM_REG_SHIFT, + pThis->aOperands[pThis->iRmOp].cbOp, + 0 /*cbMisalign*/, + pThis->aOperands[pThis->iRmOp].enmLocation); +} + + + +static unsigned BS3_NEAR_CODE Bs3Cg1EncodeNext_MODRM_Eb_Gb_OR_ViceVersa(PBS3CG1STATE pThis, unsigned iEncoding) +{ + unsigned off; + switch (iEncoding) + { + /* Start by reg,reg encoding. */ + case 0: + pThis->aOperands[pThis->iRmOp].enmLocation = pThis->aOperands[pThis->iRmOp].enmLocationReg; + off = Bs3Cg1InsertOpcodes(pThis, Bs3Cg1InsertReqPrefix(pThis, 0)); + off = Bs3Cg1InsertModRmWithRegFields(pThis, off, X86_GREG_xAX, X86_GREG_xCX); + break; + case 1: + pThis->aOperands[pThis->iRmOp].enmLocation = pThis->aOperands[pThis->iRmOp].enmLocationMem; + off = Bs3Cg1InsertOpcodes(pThis, Bs3Cg1InsertReqPrefix(pThis, 0)); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 5 /*CH*/); + break; + case 2: + if ((g_uBs3CpuDetected & BS3CPU_TYPE_MASK) < BS3CPU_80386) + return 0; + pThis->aOperands[pThis->iRmOp].enmLocation = pThis->aOperands[pThis->iRmOp].enmLocationMem; + pThis->abCurInstr[0] = P_OZ; + off = Bs3Cg1InsertOpcodes(pThis, Bs3Cg1InsertReqPrefix(pThis, 0)); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 6 /*DH*/); + break; + /* Tests with address overrides go last! */ + case 3: + pThis->abCurInstr[0] = P_AZ; + off = Bs3Cg1InsertOpcodes(pThis, Bs3Cg1InsertReqPrefix(pThis, 1)); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaultsAddrOverride(pThis, off, 7 /*BH*/); + break; + + default: + return 0; + } + pThis->cbCurInstr = off; + return iEncoding + 1; +} + + +static unsigned BS3_NEAR_CODE Bs3Cg1EncodeNext_MODRM_Gv_Ev__OR__MODRM_Ev_Gv(PBS3CG1STATE pThis, unsigned iEncoding) +{ + unsigned off; + unsigned cbOp; + switch (iEncoding) + { + case 0: + pThis->aOperands[pThis->iRmOp].enmLocation = pThis->aOperands[pThis->iRmOp].enmLocationReg; + off = Bs3Cg1InsertOpcodes(pThis, Bs3Cg1InsertReqPrefix(pThis, 0)); + off = Bs3Cg1InsertModRmWithRegFields(pThis, off, X86_GREG_xBX, X86_GREG_xDX); + cbOp = pThis->cbOpDefault; + break; + case 1: + pThis->aOperands[pThis->iRmOp].enmLocation = pThis->aOperands[pThis->iRmOp].enmLocationMem; + off = Bs3Cg1InsertOpcodes(pThis, Bs3Cg1InsertReqPrefix(pThis, 0)); + cbOp = pThis->cbOpDefault; + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndSizeAndDefaults(pThis, off, X86_GREG_xBP, cbOp); + break; + case 2: + if ((g_uBs3CpuDetected & BS3CPU_TYPE_MASK) < BS3CPU_80386) + return 0; + pThis->aOperands[pThis->iRmOp].enmLocation = pThis->aOperands[pThis->iRmOp].enmLocationReg; + pThis->abCurInstr[0] = P_OZ; + off = Bs3Cg1InsertOpcodes(pThis, Bs3Cg1InsertReqPrefix(pThis, 1)); + off = Bs3Cg1InsertModRmWithRegFields(pThis, off, X86_GREG_xAX, X86_GREG_xCX); + cbOp = pThis->cbOpOvrd66; + break; + case 3: + pThis->aOperands[pThis->iRmOp].enmLocation = pThis->aOperands[pThis->iRmOp].enmLocationMem; + pThis->abCurInstr[0] = P_OZ; + off = Bs3Cg1InsertOpcodes(pThis, Bs3Cg1InsertReqPrefix(pThis, 1)); + cbOp = pThis->cbOpOvrd66; + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndSizeAndDefaults(pThis, off, X86_GREG_xSI, cbOp); + iEncoding += !BS3CG1_IS_64BIT_TARGET(pThis) ? 2 : 0; + break; + case 4: + pThis->aOperands[pThis->iRmOp].enmLocation = pThis->aOperands[pThis->iRmOp].enmLocationReg; + off = Bs3Cg1InsertReqPrefix(pThis, 0); + pThis->abCurInstr[off++] = REX_W___; + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cg1InsertModRmWithRegFields(pThis, off, X86_GREG_xBX, X86_GREG_xDX); + cbOp = pThis->cbOpOvrdRexW; + break; + case 5: + off = Bs3Cg1InsertReqPrefix(pThis, 0); + pThis->abCurInstr[off++] = REX__RB_; + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cg1InsertModRmWithRegFields(pThis, off, X86_GREG_x14, X86_GREG_x12); + cbOp = pThis->cbOpDefault; + break; + /* Tests with address overrides go last!*/ + case 6: + pThis->aOperands[pThis->iRmOp].enmLocation = pThis->aOperands[pThis->iRmOp].enmLocationMem; + pThis->abCurInstr[0] = P_AZ; + off = Bs3Cg1InsertOpcodes(pThis, Bs3Cg1InsertReqPrefix(pThis, 1)); + cbOp = pThis->cbOpDefault; + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndSizeAndDefaultsAddrOverride(pThis, off, X86_GREG_xDI, cbOp); + break; + case 7: + pThis->abCurInstr[0] = P_OZ; + pThis->abCurInstr[1] = P_AZ; + off = Bs3Cg1InsertOpcodes(pThis, Bs3Cg1InsertReqPrefix(pThis, 2)); + cbOp = pThis->cbOpOvrd66; + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndSizeAndDefaultsAddrOverride(pThis, off, X86_GREG_xDI, cbOp); + break; + default: + return 0; + } + pThis->aOperands[0].cbOp = cbOp; + pThis->aOperands[1].cbOp = cbOp; + pThis->cbOperand = cbOp; + pThis->cbCurInstr = off; + return iEncoding + 1; +} + + +static unsigned BS3_NEAR_CODE Bs3Cg1EncodeNext_MODRM_Pq_WO_Qq(PBS3CG1STATE pThis, unsigned iEncoding) +{ + unsigned off; + switch (iEncoding) + { + case 0: + pThis->aOperands[pThis->iRmOp ].enmLocation = pThis->aOperands[pThis->iRmOp].enmLocationReg; + off = Bs3Cg1InsertOpcodes(pThis, Bs3Cg1InsertReqPrefix(pThis, 0)); + off = Bs3Cg1InsertModRmWithRegFields(pThis, off, 1, 0); + break; + case 1: + pThis->aOperands[pThis->iRmOp ].enmLocation = pThis->aOperands[pThis->iRmOp].enmLocationReg; + off = Bs3Cg1InsertOpcodes(pThis, Bs3Cg1InsertReqPrefix(pThis, 0)); + off = Bs3Cg1InsertModRmWithRegFields(pThis, off, 4, 7); + iEncoding += !BS3CG1_IS_64BIT_TARGET(pThis) ? 1 : 0; + break; +#if ARCH_BITS == 64 + case 2: + off = Bs3Cg1InsertReqPrefix(pThis, 0); + pThis->abCurInstr[off++] = REX__RBX; + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cg1InsertModRmWithRegFields(pThis, off, 6 /*no +8*/, 2 /*no +8*/); + break; +#endif + case 3: + pThis->aOperands[pThis->iRmOp ].enmLocation = pThis->aOperands[pThis->iRmOp].enmLocationMem; + off = Bs3Cg1InsertOpcodes(pThis, Bs3Cg1InsertReqPrefix(pThis, 0)); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 4 /*iReg*/); + break; + case 4: + off = Bs3Cg1InsertOpcodes(pThis, Bs3Cg1InsertReqPrefix(pThis, 0)); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaultsMisaligned(pThis, off, 7 /*iReg*/, 1 /*cbMisalign*/); + iEncoding += !BS3CG1_IS_64BIT_TARGET(pThis) ? 1 : 0; + break; +#if ARCH_BITS == 64 + case 5: + off = Bs3Cg1InsertReqPrefix(pThis, 0); + pThis->abCurInstr[off++] = REX__RBX; + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 7 /*iReg - no +8*/); + break; +#endif + + default: + return 0; + } + + pThis->cbCurInstr = off; + return iEncoding + 1; +} + + +static unsigned BS3_NEAR_CODE Bs3Cg1EncodeNext_MODRM_Pq_WO_Uq(PBS3CG1STATE pThis, unsigned iEncoding) +{ + unsigned off; + switch (iEncoding) + { + case 0: + off = Bs3Cg1InsertOpcodes(pThis, Bs3Cg1InsertReqPrefix(pThis, 0)); + off = Bs3Cg1InsertModRmWithRegFields(pThis, off, 1, 0); + break; + case 1: + off = Bs3Cg1InsertOpcodes(pThis, Bs3Cg1InsertReqPrefix(pThis, 0)); + off = Bs3Cg1InsertModRmWithRegFields(pThis, off, 6, 2); + iEncoding += !BS3CG1_IS_64BIT_TARGET(pThis) ? 1 : 0; + break; + case 2: + off = Bs3Cg1InsertReqPrefix(pThis, 0); + pThis->abCurInstr[off++] = REX__RBX; + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cg1InsertModRmWithRegFields(pThis, off, 6 /*no+8*/, 2 + 8); + break; + default: + return 0; + } + pThis->cbCurInstr = off; + return iEncoding + 1; +} + + +static unsigned BS3_NEAR_CODE Bs3Cg1EncodeNext_MODRM_PdZx_WO_Ed_WZ(PBS3CG1STATE pThis, unsigned iEncoding) +{ + unsigned off; + switch (iEncoding) + { + case 0: + pThis->aOperands[pThis->iRmOp ].enmLocation = pThis->aOperands[pThis->iRmOp].enmLocationReg; + off = Bs3Cg1InsertOpcodes(pThis, Bs3Cg1InsertReqPrefix(pThis, 0)); + off = Bs3Cg1InsertModRmWithRegFields(pThis, off, 1, 0); + break; + case 1: + off = Bs3Cg1InsertOpcodes(pThis, Bs3Cg1InsertReqPrefix(pThis, 0)); + off = Bs3Cg1InsertModRmWithRegFields(pThis, off, 6, 2); + iEncoding += !BS3CG1_IS_64BIT_TARGET(pThis) ? 1 : 0; + break; +#if ARCH_BITS == 64 + case 2: + off = Bs3Cg1InsertReqPrefix(pThis, 0); + pThis->abCurInstr[off++] = REX__RBX; + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cg1InsertModRmWithRegFields(pThis, off, 6 /*no +8*/, 2+8); + break; +#endif + case 3: + pThis->aOperands[pThis->iRmOp ].enmLocation = pThis->aOperands[pThis->iRmOp].enmLocationMem; + off = Bs3Cg1InsertOpcodes(pThis, Bs3Cg1InsertReqPrefix(pThis, 0)); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 4 /*iReg*/); + break; + case 4: + off = Bs3Cg1InsertOpcodes(pThis, Bs3Cg1InsertReqPrefix(pThis, 0)); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaultsMisaligned(pThis, off, 7 /*iReg*/, 1 /*cbMisalign*/); + iEncoding += !BS3CG1_IS_64BIT_TARGET(pThis) ? 1 : 0; + break; +#if ARCH_BITS == 64 + case 5: + off = Bs3Cg1InsertReqPrefix(pThis, 0); + pThis->abCurInstr[off++] = REX__RBX; + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 7 /*iReg*/); + break; +#endif + + default: + return 0; + } + pThis->cbCurInstr = off; + return iEncoding + 1; +} + + +static unsigned BS3_NEAR_CODE Bs3Cg1EncodeNext_MODRM_Pq_WO_Eq_WNZ(PBS3CG1STATE pThis, unsigned iEncoding) +{ +#if ARCH_BITS == 64 + if (BS3CG1_IS_64BIT_TARGET(pThis)) + { + unsigned off; + switch (iEncoding) + { + case 0: + pThis->aOperands[pThis->iRmOp ].enmLocation = pThis->aOperands[pThis->iRmOp].enmLocationReg; + off = Bs3Cg1InsertReqPrefix(pThis, 0); + pThis->abCurInstr[off++] = REX_W___; + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cg1InsertModRmWithRegFields(pThis, off, 1, 0); + break; + case 1: + off = Bs3Cg1InsertReqPrefix(pThis, 0); + pThis->abCurInstr[off++] = REX_W___; + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cg1InsertModRmWithRegFields(pThis, off, 6, 2); + break; + case 2: + off = Bs3Cg1InsertReqPrefix(pThis, 0); + pThis->abCurInstr[off++] = REX_WRBX; + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cg1InsertModRmWithRegFields(pThis, off, 6 /*no +8*/, 2+8); + break; + case 3: + pThis->aOperands[pThis->iRmOp ].enmLocation = pThis->aOperands[pThis->iRmOp].enmLocationMem; + off = Bs3Cg1InsertReqPrefix(pThis, 0); + pThis->abCurInstr[off++] = REX_W___; + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 4 /*iReg*/); + break; + case 4: + off = Bs3Cg1InsertReqPrefix(pThis, 0); + pThis->abCurInstr[off++] = REX_W___; + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaultsMisaligned(pThis, off, 7 /*iReg*/, 1 /*cbMisalign*/); + break; + case 5: + off = Bs3Cg1InsertReqPrefix(pThis, 0); + pThis->abCurInstr[off++] = REX_WRBX; + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 7 /*iReg*/); + break; + + default: + return 0; + } + pThis->cbCurInstr = off; + return iEncoding + 1; + } +#endif + return 0; +} + + +/* Differs from Bs3Cg1EncodeNext_MODRM_PdZx_WO_Ed_WZ in that REX.R isn't ignored. */ +static unsigned BS3_NEAR_CODE Bs3Cg1EncodeNext_MODRM_Vd_WO_Ed_WZ(PBS3CG1STATE pThis, unsigned iEncoding) +{ + unsigned off; + switch (iEncoding) + { + case 0: + pThis->aOperands[pThis->iRmOp ].enmLocation = pThis->aOperands[pThis->iRmOp].enmLocationReg; + off = Bs3Cg1InsertOpcodes(pThis, Bs3Cg1InsertReqPrefix(pThis, 0)); + off = Bs3Cg1InsertModRmWithRegFields(pThis, off, 1, 0); + break; + case 1: + off = Bs3Cg1InsertOpcodes(pThis, Bs3Cg1InsertReqPrefix(pThis, 0)); + off = Bs3Cg1InsertModRmWithRegFields(pThis, off, 6, 2); + iEncoding += !BS3CG1_IS_64BIT_TARGET(pThis) ? 1 : 0; + break; +#if ARCH_BITS == 64 + case 2: + off = Bs3Cg1InsertReqPrefix(pThis, 0); + pThis->abCurInstr[off++] = REX__RBX; + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cg1InsertModRmWithRegFields(pThis, off, 6+8, 2+8); + break; +#endif + case 3: + pThis->aOperands[pThis->iRmOp ].enmLocation = pThis->aOperands[pThis->iRmOp].enmLocationMem; + off = Bs3Cg1InsertOpcodes(pThis, Bs3Cg1InsertReqPrefix(pThis, 0)); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 4 /*iReg*/); + break; + case 4: + off = Bs3Cg1InsertOpcodes(pThis, Bs3Cg1InsertReqPrefix(pThis, 0)); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaultsMisaligned(pThis, off, 7 /*iReg*/, 1 /*cbMisalign*/); + iEncoding += !BS3CG1_IS_64BIT_TARGET(pThis) ? 1 : 0; + break; +#if ARCH_BITS == 64 + case 5: + off = Bs3Cg1InsertReqPrefix(pThis, 0); + pThis->abCurInstr[off++] = REX__RBX; + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 7+8 /*iReg*/); + break; +#endif + + default: + return 0; + } + pThis->cbCurInstr = off; + return iEncoding + 1; +} + + +/* Differs from Bs3Cg1EncodeNext_MODRM_Pq_WO_Eq_WNZ in that REX.R isn't ignored. */ +static unsigned BS3_NEAR_CODE Bs3Cg1EncodeNext_MODRM_Vq_WO_Eq_WNZ(PBS3CG1STATE pThis, unsigned iEncoding) +{ +#if ARCH_BITS == 64 + if (BS3CG1_IS_64BIT_TARGET(pThis)) + { + unsigned off; + switch (iEncoding) + { + case 0: + pThis->aOperands[pThis->iRmOp ].enmLocation = pThis->aOperands[pThis->iRmOp].enmLocationReg; + off = Bs3Cg1InsertReqPrefix(pThis, 0); + pThis->abCurInstr[off++] = REX_W___; + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cg1InsertModRmWithRegFields(pThis, off, 1, 0); + break; + case 1: + off = Bs3Cg1InsertReqPrefix(pThis, 0); + pThis->abCurInstr[off++] = REX_W___; + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cg1InsertModRmWithRegFields(pThis, off, 6, 2); + break; + case 2: + off = Bs3Cg1InsertReqPrefix(pThis, 0); + pThis->abCurInstr[off++] = REX_WRBX; + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cg1InsertModRmWithRegFields(pThis, off, 6+8, 2+8); + break; + case 4: + pThis->aOperands[pThis->iRmOp ].enmLocation = pThis->aOperands[pThis->iRmOp].enmLocationMem; + off = Bs3Cg1InsertReqPrefix(pThis, 0); + pThis->abCurInstr[off++] = REX_W___; + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 4 /*iReg*/); + break; + case 5: + off = Bs3Cg1InsertReqPrefix(pThis, 0); + pThis->abCurInstr[off++] = REX_W___; + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaultsMisaligned(pThis, off, 7 /*iReg*/, 1 /*cbMisalign*/); + break; + case 6: + off = Bs3Cg1InsertReqPrefix(pThis, 0); + pThis->abCurInstr[off++] = REX_WRBX; + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 7+8 /*iReg*/); + break; + + default: + return 0; + } + pThis->cbCurInstr = off; + return iEncoding + 1; + } +#endif + return 0; +} + + +static unsigned BS3_NEAR_CODE Bs3Cg1EncodeNext_MODRM_Vsomething_Usomething_OR_ViceVersa(PBS3CG1STATE pThis, unsigned iEncoding) +{ + unsigned off; + switch (iEncoding) + { + case 0: + off = Bs3Cg1InsertOpcodes(pThis, Bs3Cg1InsertReqPrefix(pThis, 0)); + off = Bs3Cg1InsertModRmWithRegFields(pThis, off, 1, 0); + break; + case 1: + off = Bs3Cg1InsertOpcodes(pThis, Bs3Cg1InsertReqPrefix(pThis, 0)); + off = Bs3Cg1InsertModRmWithRegFields(pThis, off, 2, 2); + iEncoding += !BS3CG1_IS_64BIT_TARGET(pThis) ? 1 : 0; + break; + case 2: + off = Bs3Cg1InsertReqPrefix(pThis, 0); + pThis->abCurInstr[off++] = REX__RBX; + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cg1InsertModRmWithRegFields(pThis, off, 3+8, 7+8); + break; + default: + return 0; + } + pThis->cbCurInstr = off; + return iEncoding + 1; +} + + +static unsigned BS3_NEAR_CODE Bs3Cg1EncodeNext_MODRM_Vsomething_Wsomething_OR_ViceVersa(PBS3CG1STATE pThis, unsigned iEncoding) +{ + unsigned off; + switch (iEncoding) + { + case 0: + pThis->aOperands[pThis->iRmOp].enmLocation = pThis->aOperands[pThis->iRmOp].enmLocationReg; + off = Bs3Cg1InsertModRmWithRegFields(pThis, Bs3Cg1InsertOpcodes(pThis, Bs3Cg1InsertReqPrefix(pThis, 0)), 1, 0); + break; + case 1: + pThis->aOperands[pThis->iRmOp].enmLocation = pThis->aOperands[pThis->iRmOp].enmLocationMem; + off = Bs3Cg1InsertOpcodes(pThis, Bs3Cg1InsertReqPrefix(pThis, 0)); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 2 /*iReg*/); + break; + case 2: + off = Bs3Cg1InsertOpcodes(pThis, Bs3Cg1InsertReqPrefix(pThis, 0)); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaultsMisaligned(pThis, off, 3 /*iReg*/, 1 /*cbMisalign*/); + if (!Bs3Cg1XcptTypeIsUnaligned(pThis->enmXcptType)) + pThis->bAlignmentXcpt = X86_XCPT_GP; + break; + default: + return 0; + } + pThis->cbCurInstr = off; + return iEncoding + 1; +} + + +static unsigned BS3_NEAR_CODE Bs3Cg1EncodeNext_MODRM_Vsomething_Nsomething(PBS3CG1STATE pThis, unsigned iEncoding) +{ + unsigned off; + switch (iEncoding) + { + case 0: + off = Bs3Cg1InsertOpcodes(pThis, Bs3Cg1InsertReqPrefix(pThis, 0)); + off = Bs3Cg1InsertModRmWithRegFields(pThis, off, 1, 0); + break; + case 1: + off = Bs3Cg1InsertOpcodes(pThis, Bs3Cg1InsertReqPrefix(pThis, 0)); + off = Bs3Cg1InsertModRmWithRegFields(pThis, off, 6, 7); + iEncoding += !BS3CG1_IS_64BIT_TARGET(pThis) ? 1 : 0; + break; + case 2: + off = Bs3Cg1InsertReqPrefix(pThis, 0); + pThis->abCurInstr[off++] = REX_WRBX; + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cg1InsertModRmWithRegFields(pThis, off, 6 + 8, 7 /*no +8*/); + break; + + default: + return 0; + } + pThis->cbCurInstr = off; + return iEncoding + 1; +} + + +static unsigned BS3_NEAR_CODE Bs3Cg1EncodeNext_MODRM_Gv_RO_Ma(PBS3CG1STATE pThis, unsigned iEncoding) /* bound instr */ +{ + unsigned off; + unsigned cbOp = BS3_MODE_IS_16BIT_CODE(pThis->bMode) ? 2 : 4; + switch (iEncoding) + { + case 0: + off = Bs3Cg1InsertOpcodes(pThis, Bs3Cg1InsertReqPrefix(pThis, 0)); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndSizeAndDefaults(pThis, off, X86_GREG_xBP, cbOp * 2); + break; + case 1: + if ((g_uBs3CpuDetected & BS3CPU_TYPE_MASK) < BS3CPU_80386) + return 0; + cbOp = cbOp == 2 ? 4 : 2; + pThis->abCurInstr[0] = P_OZ; + off = Bs3Cg1InsertOpcodes(pThis, Bs3Cg1InsertReqPrefix(pThis, 1)); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndSizeAndDefaults(pThis, off, X86_GREG_xBP, cbOp * 2); + break; + case 2: + pThis->abCurInstr[0] = P_AZ; + off = Bs3Cg1InsertOpcodes(pThis, Bs3Cg1InsertReqPrefix(pThis, 1)); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndSizeAndDefaultsAddrOverride(pThis, off, X86_GREG_xBP, cbOp * 2); + break; + case 3: + cbOp = cbOp == 2 ? 4 : 2; + pThis->abCurInstr[0] = P_AZ; + pThis->abCurInstr[1] = P_OZ; + off = Bs3Cg1InsertOpcodes(pThis, Bs3Cg1InsertReqPrefix(pThis, 2)); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndSizeAndDefaultsAddrOverride(pThis, off, X86_GREG_xBP, cbOp * 2); + break; + default: + return 0; + } + pThis->aOperands[pThis->iRegOp].cbOp = cbOp; + pThis->cbOperand = cbOp; + pThis->cbCurInstr = off; + return iEncoding + 1; +} + + +static unsigned BS3_NEAR_CODE Bs3Cg1EncodeNext_MODRM_Msomething(PBS3CG1STATE pThis, unsigned iEncoding) +{ + unsigned off; + switch (iEncoding) + { + case 0: + off = Bs3Cg1InsertOpcodes(pThis, Bs3Cg1InsertReqPrefix(pThis, 0)) - 1; + off = Bs3Cfg1EncodeMemMod0DispWithDefaultsAndNoReg(pThis, off); + break; + default: + return 0; + } + pThis->cbCurInstr = off; + return iEncoding + 1; +} + + +static unsigned BS3_NEAR_CODE Bs3Cg1EncodeNext_MODRM_Msomething_Psomething(PBS3CG1STATE pThis, unsigned iEncoding) +{ + unsigned off; + switch (iEncoding) + { + case 0: + off = Bs3Cg1InsertOpcodes(pThis, Bs3Cg1InsertReqPrefix(pThis, 0)); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 4 /*iReg*/); + break; + case 1: + off = Bs3Cg1InsertOpcodes(pThis, Bs3Cg1InsertReqPrefix(pThis, 0)); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaultsMisaligned(pThis, off, 7 /*iReg*/, 1 /*cbMisalign*/); + iEncoding += !BS3CG1_IS_64BIT_TARGET(pThis) ? 1 : 0; + break; +#if ARCH_BITS == 64 + case 2: + off = Bs3Cg1InsertReqPrefix(pThis, 0); + pThis->abCurInstr[off++] = REX__RBX; + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 7 /*iReg - no +8*/); + break; +#endif + + default: + return 0; + } + + pThis->cbCurInstr = off; + return iEncoding + 1; +} + + +static unsigned BS3_NEAR_CODE Bs3Cg1EncodeNext_MODRM_Msomething_Vsomething_OR_ViceVersa(PBS3CG1STATE pThis, unsigned iEncoding) +{ + unsigned off; + switch (iEncoding) + { + case 0: + off = Bs3Cg1InsertOpcodes(pThis, Bs3Cg1InsertReqPrefix(pThis, 0)); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 2 /*iReg*/); + break; + case 1: + off = Bs3Cg1InsertOpcodes(pThis, Bs3Cg1InsertReqPrefix(pThis, 0)); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaultsMisaligned(pThis, off, 2 /*iReg*/, 1 /*cbMisalign*/ ); + if (!Bs3Cg1XcptTypeIsUnaligned(pThis->enmXcptType)) + pThis->bAlignmentXcpt = X86_XCPT_GP; + iEncoding += !BS3CG1_IS_64BIT_TARGET(pThis) ? 1 : 0; + break; + case 2: + off = Bs3Cg1InsertReqPrefix(pThis, 0); + pThis->abCurInstr[off++] = REX__R__; + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 2+8 /*iReg*/); + break; + default: + return 0; + } + pThis->cbCurInstr = off; + return iEncoding + 1; +} + + +static unsigned BS3_NEAR_CODE Bs3Cg1EncodeNext_FIXED(PBS3CG1STATE pThis, unsigned iEncoding) +{ + unsigned off; + switch (iEncoding) + { + case 0: + off = Bs3Cg1InsertOpcodes(pThis, Bs3Cg1InsertReqPrefix(pThis, 0)); + pThis->cbCurInstr = off; + break; + default: + return 0; + } + return iEncoding + 1; +} + + +static unsigned BS3_NEAR_CODE Bs3Cg1EncodeNext_FIXED_AL_Ib(PBS3CG1STATE pThis, unsigned iEncoding) +{ + unsigned off; + switch (iEncoding) + { + case 0: + off = Bs3Cg1InsertOpcodes(pThis, Bs3Cg1InsertReqPrefix(pThis, 0)); + pThis->aOperands[1].off = (uint8_t)off; + pThis->abCurInstr[off++] = 0xff; + pThis->cbCurInstr = off; + break; + default: + return 0; + } + return iEncoding + 1; +} + + +static unsigned BS3_NEAR_CODE Bs3Cg1EncodeNext_FIXED_rAX_Iz(PBS3CG1STATE pThis, unsigned iEncoding) +{ + unsigned off; + unsigned cbOp; + switch (iEncoding) + { + case 0: + off = Bs3Cg1InsertOpcodes(pThis, Bs3Cg1InsertReqPrefix(pThis, 0)); + pThis->aOperands[1].off = (uint8_t)off; + cbOp = pThis->cbOpDefault; + if (cbOp == 2) + *(uint16_t *)&pThis->abCurInstr[off] = UINT16_MAX; + else + *(uint32_t *)&pThis->abCurInstr[off] = UINT32_MAX; + off += cbOp; + pThis->aOperands[0].cbOp = cbOp; + pThis->aOperands[1].cbOp = cbOp; + pThis->cbOperand = cbOp; + break; + case 1: + if ((g_uBs3CpuDetected & BS3CPU_TYPE_MASK) < BS3CPU_80386) + return 0; + pThis->abCurInstr[0] = P_OZ; + off = Bs3Cg1InsertOpcodes(pThis, Bs3Cg1InsertReqPrefix(pThis, 1)); + pThis->aOperands[1].off = (uint8_t)off; + cbOp = pThis->cbOpOvrd66; + if (cbOp == 2) + *(uint16_t *)&pThis->abCurInstr[off] = UINT16_MAX; + else + *(uint32_t *)&pThis->abCurInstr[off] = UINT32_MAX; + off += cbOp; + pThis->aOperands[0].cbOp = cbOp; + pThis->aOperands[1].cbOp = cbOp; + pThis->cbOperand = cbOp; + iEncoding += !BS3CG1_IS_64BIT_TARGET(pThis) ? 1 : 0; + break; + case 2: + off = Bs3Cg1InsertReqPrefix(pThis, 0); + pThis->abCurInstr[off++] = REX_W___; + off = Bs3Cg1InsertOpcodes(pThis, off); + pThis->aOperands[1].off = (uint8_t)off; + *(uint32_t *)&pThis->abCurInstr[off] = UINT32_MAX; + off += 4; + pThis->aOperands[0].cbOp = 8; + pThis->aOperands[1].cbOp = 4; + pThis->cbOperand = 8; + break; + default: + return 0; + + /* IMAGE PADDING - workaround for "rd err" - remove later! */ + case 4: + ASMHalt(); + ASMHalt(); + ASMHalt(); + return 0; + + } + pThis->cbCurInstr = off; + return iEncoding + 1; +} + + +static unsigned BS3_NEAR_CODE Bs3Cg1EncodeNext_MODRM_MOD_EQ_3(PBS3CG1STATE pThis, unsigned iEncoding) +{ + unsigned off; + if (iEncoding < 8) + { + off = Bs3Cg1InsertReqPrefix(pThis, 0); + off = Bs3Cg1InsertOpcodes(pThis, off); + pThis->abCurInstr[off++] = X86_MODRM_MAKE(3, iEncoding, 1); + } + else if (iEncoding < 16) + { + off = Bs3Cg1InsertReqPrefix(pThis, 0); + off = Bs3Cg1InsertOpcodes(pThis, off); + pThis->abCurInstr[off++] = X86_MODRM_MAKE(3, 0, iEncoding & 7); + } + else + return 0; + pThis->cbCurInstr = off; + + return iEncoding + 1; +} + + +static unsigned BS3_NEAR_CODE Bs3Cg1EncodeNext_MODRM_MOD_NE_3(PBS3CG1STATE pThis, unsigned iEncoding) +{ + unsigned off; + if (iEncoding < 3) + { + off = Bs3Cg1InsertReqPrefix(pThis, 0); + off = Bs3Cg1InsertOpcodes(pThis, off); + pThis->abCurInstr[off++] = X86_MODRM_MAKE(iEncoding, 0, 1); + if (iEncoding >= 1) + pThis->abCurInstr[off++] = 0x7f; + if (iEncoding == 2) + { + pThis->abCurInstr[off++] = 0x5f; + if (!BS3_MODE_IS_16BIT_CODE(pThis->bMode)) + { + pThis->abCurInstr[off++] = 0x3f; + pThis->abCurInstr[off++] = 0x1f; + } + } + } + else + return 0; + pThis->cbCurInstr = off; + return iEncoding + 1; +} + + +/* + * + * VEX + * VEX + * VEX + * + */ +#ifdef BS3CG1_WITH_VEX + +/** + * Inserts a 3-byte VEX prefix. + * + * @returns New offDst value. + * @param pThis The state. + * @param offDst The current instruction offset. + * @param uVexL The VEX.L value. + * @param uVexV The VEX.V value (caller inverted it already). + * @param uVexR The VEX.R value (caller inverted it already). + * @param uVexX The VEX.X value (caller inverted it already). + * @param uVexB The VEX.B value (caller inverted it already). + * @param uVexW The VEX.W value (straight). + */ +DECLINLINE(unsigned) BS3_NEAR_CODE Bs3Cg1InsertVex3bPrefix(PBS3CG1STATE pThis, unsigned offDst, uint8_t uVexV, uint8_t uVexL, + uint8_t uVexR, uint8_t uVexX, uint8_t uVexB, uint8_t uVexW) +{ + uint8_t b1; + uint8_t b2; + b1 = uVexR << 7; + b1 |= uVexX << 6; + b1 |= uVexB << 5; + b1 |= pThis->uOpcodeMap; + b2 = uVexV << 3; + b2 |= uVexW << 7; + b2 |= uVexL << 2; + switch (pThis->enmPrefixKind) + { + case BS3CG1PFXKIND_NO_F2_F3_66: b2 |= 0; break; + case BS3CG1PFXKIND_REQ_66: b2 |= 1; break; + case BS3CG1PFXKIND_REQ_F3: b2 |= 2; break; + case BS3CG1PFXKIND_REQ_F2: b2 |= 3; break; + default: + Bs3TestFailedF("enmPrefixKind=%d not supported for VEX!\n", pThis->enmPrefixKind); + break; + } + + pThis->abCurInstr[offDst] = 0xc4; /* vex3 */ + pThis->abCurInstr[offDst + 1] = b1; + pThis->abCurInstr[offDst + 2] = b2; + pThis->uVexL = uVexL; + return offDst + 3; +} + + +/** + * Inserts a 2-byte VEX prefix. + * + * @note Will switch to 3-byte VEX prefix if uOpcodeMap isn't one. + * + * @returns New offDst value. + * @param pThis The state. + * @param offDst The current instruction offset. + * @param uVexL The VEX.L value. + * @param uVexV The VEX.V value (caller inverted it already). + * @param uVexR The VEX.R value (caller inverted it already). + */ +DECLINLINE(unsigned) BS3_NEAR_CODE Bs3Cg1InsertVex2bPrefix(PBS3CG1STATE pThis, unsigned offDst, + uint8_t uVexV, uint8_t uVexL, uint8_t uVexR) +{ + if (pThis->uOpcodeMap == 1) + { + uint8_t b = uVexR << 7; + b |= uVexV << 3; + b |= uVexL << 2; + switch (pThis->enmPrefixKind) + { + case BS3CG1PFXKIND_NO_F2_F3_66: b |= 0; break; + case BS3CG1PFXKIND_REQ_66: b |= 1; break; + case BS3CG1PFXKIND_REQ_F3: b |= 2; break; + case BS3CG1PFXKIND_REQ_F2: b |= 3; break; + default: + Bs3TestFailedF("enmPrefixKind=%d not supported for VEX!\n"); + break; + } + + pThis->abCurInstr[offDst] = 0xc5; /* vex2 */ + pThis->abCurInstr[offDst + 1] = b; + pThis->uVexL = uVexL; + return offDst + 2; + } + return Bs3Cg1InsertVex3bPrefix(pThis, offDst, uVexV, uVexL, uVexR, 1 /*uVexX*/, 1 /*uVexB*/, 0/*uVexW*/); +} + + +/** + * Inserts a ModR/M byte with mod=3 and set the two idxFields members. + * + * @returns off + 1. + * @param pThis The state. + * @param off Current instruction offset. + * @param uReg Register index for ModR/M.reg. + * @param uRegMem Register index for ModR/M.rm. + * @param uVexVvvv The VEX.vvvv register. + */ +static unsigned Bs3Cg1InsertModRmWithRegFieldsAndVvvv(PBS3CG1STATE pThis, unsigned off, + uint8_t uReg, uint8_t uRegMem, uint8_t uVexVvvv) +{ + pThis->abCurInstr[off++] = X86_MODRM_MAKE(3, uReg & 7, uRegMem & 7); + pThis->aOperands[pThis->iRegOp].idxField = pThis->aOperands[pThis->iRegOp].idxFieldBase + uReg; + pThis->aOperands[1 ].idxField = pThis->aOperands[1 ].idxFieldBase + uVexVvvv; + pThis->aOperands[pThis->iRmOp ].idxField = pThis->aOperands[pThis->iRmOp ].idxFieldBase + uRegMem; + return off; +} + + +static unsigned BS3_NEAR_CODE Bs3Cg1EncodeNext_VEX_MODRM_Vd_WO_Ed_WZ(PBS3CG1STATE pThis, unsigned iEncoding) +{ + unsigned off; + switch (iEncoding) + { + case 0: + pThis->aOperands[pThis->iRmOp ].enmLocation = pThis->aOperands[pThis->iRmOp].enmLocationReg; + off = Bs3Cg1InsertVex2bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, 0 /*L*/, 1 /*~R*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cg1InsertModRmWithRegFields(pThis, off, 1, 0); + break; + case 1: + off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, 0 /*L*/, 1 /*~R*/, 1 /*~X*/, 1 /*~B*/, 0 /*W*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cg1InsertModRmWithRegFields(pThis, off, 6, 2); + break; + case 2: + off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, 1 /*L-invalid*/, 1 /*~R*/, 1 /*~X*/, 1 /*~B*/, 0 /*W*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cg1InsertModRmWithRegFields(pThis, off, 6, 2); + pThis->fInvalidEncoding = true; + break; + case 3: + off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 0xe /*~V-invalid*/, 0 /*L*/, 1 /*~R*/, 1 /*~X*/, 1 /*~B*/, 0 /*W*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cg1InsertModRmWithRegFields(pThis, off, 6, 2); + pThis->fInvalidEncoding = true; + iEncoding += !BS3CG1_IS_64BIT_TARGET(pThis) ? 1 : 0; + break; +#if ARCH_BITS == 64 + case 4: + off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, 0 /*L*/, 0 /*~R*/, 1 /*~X*/, 0 /*~B*/, 0 /*W*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cg1InsertModRmWithRegFields(pThis, off, 6+8, 2+8); + break; +#endif + case 5: + pThis->aOperands[pThis->iRmOp ].enmLocation = pThis->aOperands[pThis->iRmOp].enmLocationMem; + off = Bs3Cg1InsertVex2bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, 0 /*L*/, 1 /*~R*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 4 /*iReg*/); + break; + case 6: + off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, 0 /*L*/, 1 /*~R*/, 1 /*~X*/, 1 /*~B*/, 0 /*W*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 4 /*iReg*/); + break; + case 7: + off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, 0 /*L*/, 1 /*~R*/, 1 /*~X*/, 1 /*~B*/, 0 /*W*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaultsMisaligned(pThis, off, 4 /*iReg*/, 1 /*cbMisalign*/); + iEncoding += !BS3CG1_IS_64BIT_TARGET(pThis) ? 2 : 0; + break; +#if ARCH_BITS == 64 + case 8: + off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, 0 /*L*/, 0 /*~R*/, 1 /*~X*/, 1 /*~B*/, 0 /*W*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 4+8 /*iReg*/); + break; + case 9: + off = Bs3Cg1InsertVex2bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, 0 /*L*/, 0 /*~R*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 5+8 /*iReg*/); + iEncoding += 2; + break; +#endif + case 10: /* VEX.W is ignored in 32-bit mode. flag? */ + BS3_ASSERT(!BS3CG1_IS_64BIT_TARGET(pThis)); + off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, 0 /*L*/, 1 /*~R*/, 1 /*~X*/, 1 /*~B*/, 1 /*W*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 4 /*iReg*/); + break; + + default: + return 0; + } + pThis->cbCurInstr = off; + return iEncoding + 1; +} + + +/* Differs from Bs3Cg1EncodeNext_MODRM_Pq_WO_Eq_WNZ in that REX.R isn't ignored. */ +static unsigned BS3_NEAR_CODE Bs3Cg1EncodeNext_VEX_MODRM_Vq_WO_Eq_WNZ(PBS3CG1STATE pThis, unsigned iEncoding) +{ +#if ARCH_BITS == 64 + if (BS3CG1_IS_64BIT_TARGET(pThis)) + { + unsigned off; + switch (iEncoding) + { + case 0: + pThis->aOperands[pThis->iRmOp].enmLocation = pThis->aOperands[pThis->iRmOp].enmLocationReg; + off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, 0 /*L*/, 1 /*~R*/, 1 /*~X*/, 1 /*~B*/, 1 /*W*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cg1InsertModRmWithRegFields(pThis, off, 6, 2); + break; + case 1: + off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, 1 /*L-invalid*/, 1 /*~R*/, 1 /*~X*/, 1 /*~B*/, 1 /*W*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cg1InsertModRmWithRegFields(pThis, off, 6, 2); + pThis->fInvalidEncoding = true; + break; + case 2: + off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 0xe /*~V-invalid*/, 0 /*L*/, 1 /*~R*/, 1 /*~X*/, 1 /*~B*/, 1 /*W*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cg1InsertModRmWithRegFields(pThis, off, 6, 2); + pThis->fInvalidEncoding = true; + break; + case 3: + off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, 0 /*L*/, 0 /*~R*/, 1 /*~X*/, 0 /*~B*/, 1 /*W*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cg1InsertModRmWithRegFields(pThis, off, 6+8, 2+8); + break; + case 4: + pThis->aOperands[pThis->iRmOp ].enmLocation = pThis->aOperands[pThis->iRmOp].enmLocationMem; + off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, 0 /*L*/, 1 /*~R*/, 1 /*~X*/, 1 /*~B*/, 1 /*W*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 4 /*iReg*/); + break; + case 5: + off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, 0 /*L*/, 1 /*~R*/, 1 /*~X*/, 1 /*~B*/, 1 /*W*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaultsMisaligned(pThis, off, 4 /*iReg*/, 1 /*cbMisalign*/); + iEncoding += !BS3CG1_IS_64BIT_TARGET(pThis) ? 2 : 0; + break; + case 6: + off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, 0 /*L*/, 0 /*~R*/, 1 /*~X*/, 1 /*~B*/, 1 /*W*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 4+8 /*iReg*/); + break; + + default: + return 0; + } + pThis->cbCurInstr = off; + return iEncoding + 1; + } +#endif + return 0; +} + + +/** + * Wip - VEX.W ignored. + * Lig - VEX.L ignored. + */ +static unsigned BS3_NEAR_CODE +Bs3Cg1EncodeNext_VEX_MODRM_VsomethingWO_Hsomething_Usomething_Lip_Wip_OR_ViceVersa(PBS3CG1STATE pThis, unsigned iEncoding) +{ + unsigned off; + switch (iEncoding) + { + case 0: + off = Bs3Cg1InsertVex2bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, 0 /*L*/, 1 /*~R*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cg1InsertModRmWithRegFieldsAndVvvv(pThis, off, 2, 1, 0); + break; + case 1: + off = Bs3Cg1InsertVex2bPrefix(pThis, 0 /*offDst*/, 0x8 /*~V*/, 1 /*L-ignored*/, 1 /*~R*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cg1InsertModRmWithRegFieldsAndVvvv(pThis, off, 3, 1, 7); + iEncoding += !BS3CG1_IS_64BIT_TARGET(pThis) ? 1 : 0; + break; + case 2: +#if ARCH_BITS == 64 + off = Bs3Cg1InsertVex2bPrefix(pThis, 0 /*offDst*/, 0 /*~V*/, 0 /*L*/, 0 /*~R*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cg1InsertModRmWithRegFieldsAndVvvv(pThis, off, 3+8, 2, 15); + break; +#endif + case 3: + off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, 0 /*L*/, 1 /*~R*/, 1 /*~X*/, 1 /*~B*/, 0 /*W*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cg1InsertModRmWithRegFieldsAndVvvv(pThis, off, 2, 1, 0); + break; + case 4: + off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, 1 /*L - ignored*/, 1 /*~R*/, 1 /*~X*/, 1 /*~B*/, 0 /*W*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cg1InsertModRmWithRegFieldsAndVvvv(pThis, off, 2, 1, 0); + break; + case 5: + off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 0xc /*~V*/, 0 /*L*/, 1 /*~R*/, 1 /*~X*/, 1 /*~B*/, 1 /*W-ignored*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cg1InsertModRmWithRegFieldsAndVvvv(pThis, off, 2, 1, 3); + break; + case 6: + off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 0 /*~V*/, 0 /*L*/, 1 /*~R*/, 1 /*~X*/, 1 /*~B*/, 1 /*W-ignored*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cg1InsertModRmWithRegFieldsAndVvvv(pThis, off, 2, 1, BS3CG1_IS_64BIT_TARGET(pThis) ? 15 : 7); + break; + case 7: + off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 0 /*~V*/, 0 /*L*/, 1 /*~R*/, 1 /*~X*/, 1 /*~B*/, 0 /*W*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cg1InsertModRmWithRegFieldsAndVvvv(pThis, off, 2, 1, BS3CG1_IS_64BIT_TARGET(pThis) ? 15 : 7); + break; + default: + return 0; + } + pThis->cbCurInstr = off; + return iEncoding + 1; +} + + +/** + * Wip - VEX.W ignored. + */ +static unsigned BS3_NEAR_CODE +Bs3Cg1EncodeNext_VEX_MODRM_VsomethingWO_HdqCsomething_Usomething_Wip_OR_ViceVersa(PBS3CG1STATE pThis, unsigned iEncoding) +{ + unsigned off; + switch (iEncoding) + { + case 0: + off = Bs3Cg1InsertVex2bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, 0 /*L*/, 1 /*~R*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cg1InsertModRmWithRegFieldsAndVvvv(pThis, off, 2, 1, 0); + break; + case 1: + off = Bs3Cg1InsertVex2bPrefix(pThis, 0 /*offDst*/, 0x8 /*~V*/, 1 /*L-ignored*/, 1 /*~R*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cg1InsertModRmWithRegFieldsAndVvvv(pThis, off, 3, 1, 7); + pThis->fInvalidEncoding = true; + iEncoding += !BS3CG1_IS_64BIT_TARGET(pThis) ? 1 : 0; + break; + case 2: +#if ARCH_BITS == 64 + off = Bs3Cg1InsertVex2bPrefix(pThis, 0 /*offDst*/, 0 /*~V*/, 0 /*L*/, 0 /*~R*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cg1InsertModRmWithRegFieldsAndVvvv(pThis, off, 3+8, 2, 15); + break; +#endif + case 3: + off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, 0 /*L*/, 1 /*~R*/, 1 /*~X*/, 1 /*~B*/, 0 /*W*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cg1InsertModRmWithRegFieldsAndVvvv(pThis, off, 2, 1, 0); + break; + case 4: + off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, 1 /*L - ignored*/, 1 /*~R*/, 1 /*~X*/, 1 /*~B*/, 0 /*W*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cg1InsertModRmWithRegFieldsAndVvvv(pThis, off, 2, 1, 0); + pThis->fInvalidEncoding = true; + break; + case 5: + off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 0xc /*~V*/, 0 /*L*/, 1 /*~R*/, 1 /*~X*/, 1 /*~B*/, 1 /*W-ignored*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cg1InsertModRmWithRegFieldsAndVvvv(pThis, off, 2, 1, 3); + break; + case 6: + off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 0 /*~V*/, 0 /*L*/, 1 /*~R*/, 1 /*~X*/, 1 /*~B*/, 1 /*W-ignored*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cg1InsertModRmWithRegFieldsAndVvvv(pThis, off, 2, 1, BS3CG1_IS_64BIT_TARGET(pThis) ? 15 : 7); + break; + case 7: + off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 0 /*~V*/, 0 /*L*/, 1 /*~R*/, 1 /*~X*/, 1 /*~B*/, 0 /*W*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cg1InsertModRmWithRegFieldsAndVvvv(pThis, off, 2, 1, BS3CG1_IS_64BIT_TARGET(pThis) ? 15 : 7); + break; + default: + return 0; + } + pThis->cbCurInstr = off; + return iEncoding + 1; +} + + +/** + * Wip - VEX.W ignored. + */ +static unsigned BS3_NEAR_CODE +Bs3Cg1EncodeNext_VEX_MODRM_VsomethingWO_Msomething_Wip_OR_ViceVersa(PBS3CG1STATE pThis, unsigned iEncoding) +{ + unsigned off; + switch (iEncoding) + { + case 20: /* Switch to 256-bit operands. */ + pThis->aOperands[pThis->iRegOp].idxFieldBase = BS3CG1DST_YMM0; + pThis->aOperands[pThis->iRegOp].cbOp = 32; + pThis->aOperands[pThis->iRmOp ].cbOp = 32; + RT_FALL_THRU(); + case 0: + off = Bs3Cg1InsertVex2bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, iEncoding >= 20 /*L*/, 1 /*~R*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 0); + iEncoding += !BS3CG1_IS_64BIT_TARGET(pThis) ? 1 : 0; + break; +#if ARCH_BITS == 64 + case 1: + case 21: + off = Bs3Cg1InsertVex2bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, iEncoding >= 20 /*L*/, 0 /*~R*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 7 + 8); + break; +#endif + case 2: + case 22: + off = Bs3Cg1InsertVex2bPrefix(pThis, 0 /*offDst*/, 0xe /*~V*/, iEncoding >= 20 /*L*/, 1 /*~R*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 0); + pThis->fInvalidEncoding = true; + break; + case 3: + case 23: + off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, iEncoding >= 20 /*L*/, 1 /*~R*/, 1 /*~X*/, 1 /*~B*/, 0 /*W*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 1); + break; + case 4: + case 24: + off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, iEncoding >= 20 /*L*/, 1 /*~R*/, 1 /*~X*/, 1 /*~B*/, 1 /*W-ignored*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 5); + iEncoding += !BS3CG1_IS_64BIT_TARGET(pThis) ? 3 : 0; + break; +#if ARCH_BITS == 64 + case 5: + case 25: + off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, iEncoding >= 20 /*L*/, 0 /*~R*/, 1 /*~X*/, 1 /*~B*/, 0 /*W*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 5+8); + break; + case 6: + case 26: + off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, iEncoding >= 20 /*L*/, 1 /*~R*/, 1 /*~X*/, 0 /*~B-ignored*/, 0 /*W*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 1); + break; + case 7: + case 27: + off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, iEncoding >= 20 /*L*/, 1 /*~R*/, 0 /*~X-ignored*/, 1 /*~B*/, 0 /*W*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 2); + break; +#endif + case 8: + case 28: + off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 0 /*~V*/, iEncoding >= 20 /*L*/, 1 /*~R*/, 1 /*~X*/, 1 /*~B*/, 0 /*W*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 5); + pThis->fInvalidEncoding = true; + break; + case 9: + case 29: + off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 7 /*~V*/, iEncoding >= 20 /*L*/, 1 /*~R*/, 1 /*~X*/, 1 /*~B*/, 0 /*W*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 2); + pThis->fInvalidEncoding = true; + iEncoding += 10; + break; + + default: + return 0; + } + pThis->cbCurInstr = off; + return iEncoding + 1; +} + + + +/** + * Wip - VEX.W ignored. + * Lig - VEX.L ignored. + */ +static unsigned BS3_NEAR_CODE +Bs3Cg1EncodeNext_VEX_MODRM_VsomethingWO_Msomething_Wip_Lig_OR_ViceVersa(PBS3CG1STATE pThis, unsigned iEncoding) +{ + unsigned off; + switch (iEncoding) + { + case 0: + off = Bs3Cg1InsertVex2bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, 0 /*L*/, 1 /*~R*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 0); + break; + case 1: + off = Bs3Cg1InsertVex2bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, 1 /*L - ignored*/, 1 /*~R*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 7); + iEncoding += !BS3CG1_IS_64BIT_TARGET(pThis) ? 1 : 0; + break; +#if ARCH_BITS == 64 + case 2: + off = Bs3Cg1InsertVex2bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, 1 /*L - ignored*/, 0 /*~R*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 7 + 8); + break; +#endif + case 3: + iEncoding = 3; + off = Bs3Cg1InsertVex2bPrefix(pThis, 0 /*offDst*/, 0xe /*~V*/, 0 /*L*/, 1 /*~R*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 0); + pThis->fInvalidEncoding = true; + break; + case 4: + off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, 0 /*L*/, 1 /*~R*/, 1 /*~X*/, 1 /*~B*/, 0 /*W*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 1); + break; + case 5: + off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, 1 /*L-ignored*/, 1 /*~R*/, 1 /*~X*/, 1 /*~B*/, 0 /*W*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 1); + break; + case 6: + off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, 0 /*L*/, 1 /*~R*/, 1 /*~X*/, 1 /*~B*/, 1 /*W-ignored*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 5); + iEncoding += !BS3CG1_IS_64BIT_TARGET(pThis) ? 3 : 0; + break; +#if ARCH_BITS == 64 + case 7: + off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, 0 /*L*/, 0 /*~R*/, 1 /*~X*/, 1 /*~B*/, 0 /*W*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 5+8); + break; + case 8: + off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, 0 /*L*/, 1 /*~R*/, 1 /*~X*/, 0 /*~B-ignored*/, 0 /*W*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 1); + break; + case 9: + off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, 0 /*L*/, 1 /*~R*/, 0 /*~X-ignored*/, 1 /*~B*/, 0 /*W*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 2); + break; +#endif + case 10: + off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 0 /*~V*/, 0 /*L*/, 1 /*~R*/, 1 /*~X*/, 1 /*~B*/, 0 /*W*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 5); + pThis->fInvalidEncoding = true; + break; + case 11: + off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 7 /*~V*/, 0 /*L*/, 1 /*~R*/, 1 /*~X*/, 1 /*~B*/, 0 /*W*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 2); + pThis->fInvalidEncoding = true; + break; + default: + return 0; + } + pThis->cbCurInstr = off; + return iEncoding + 1; +} + + +/** + * Wip - VEX.W ignored. + * L0 - VEX.L must be zero. + */ +static unsigned BS3_NEAR_CODE +Bs3Cg1EncodeNext_VEX_MODRM_VsomethingWO_Msomething_Wip_Lmbz_OR_ViceVersa(PBS3CG1STATE pThis, unsigned iEncoding) +{ + unsigned off; + switch (iEncoding) + { + case 0: + off = Bs3Cg1InsertVex2bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, 0 /*L*/, 1 /*~R*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 0); + break; + case 1: + off = Bs3Cg1InsertVex2bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, 1 /*L - invalid*/, 1 /*~R*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 7); + pThis->fInvalidEncoding = true; + iEncoding += !BS3CG1_IS_64BIT_TARGET(pThis) ? 2 : 0; + break; +#if ARCH_BITS == 64 + case 2: + off = Bs3Cg1InsertVex2bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, 0 /*L*/, 0 /*~R*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 7 + 8); + break; + case 3: + off = Bs3Cg1InsertVex2bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, 1 /*L - invalid*/, 0 /*~R*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 5 + 8); + pThis->fInvalidEncoding = true; + break; +#endif + case 4: + off = Bs3Cg1InsertVex2bPrefix(pThis, 0 /*offDst*/, 0xe /*~V*/, 0 /*L*/, 1 /*~R*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 0); + pThis->fInvalidEncoding = true; + break; + case 5: + off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, 0 /*L*/, 1 /*~R*/, 1 /*~X*/, 1 /*~B*/, 0 /*W*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 1); + break; + case 6: + off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, 1 /*L - invalid*/, 1 /*~R*/, 1 /*~X*/, 1 /*~B*/, 0 /*W*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 1); + pThis->fInvalidEncoding = true; + break; + case 7: + off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, 0 /*L*/, 1 /*~R*/, 1 /*~X*/, 1 /*~B*/, 1 /*W-ignored*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 5); + iEncoding += !BS3CG1_IS_64BIT_TARGET(pThis) ? 3 : 0; + break; +#if ARCH_BITS == 64 + case 8: + off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, 0 /*L*/, 0 /*~R*/, 1 /*~X*/, 1 /*~B*/, 0 /*W*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 5+8); + break; + case 9: + off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, 0 /*L*/, 1 /*~R*/, 1 /*~X*/, 0 /*~B-ignored*/, 0 /*W*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 1); + break; + case 10: + off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, 0 /*L*/, 1 /*~R*/, 0 /*~X-ignored*/, 1 /*~B*/, 0 /*W*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 2); + break; +#endif + case 11: + off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 0 /*~V*/, 0 /*L*/, 1 /*~R*/, 1 /*~X*/, 1 /*~B*/, 0 /*W*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 5); + pThis->fInvalidEncoding = true; + break; + case 12: + off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 7 /*~V*/, 0 /*L*/, 1 /*~R*/, 1 /*~X*/, 1 /*~B*/, 0 /*W*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 2); + pThis->fInvalidEncoding = true; + break; + default: + return 0; + } + pThis->cbCurInstr = off; + return iEncoding + 1; +} + + +/** + * Wip - VEX.W ignored. + */ +static unsigned BS3_NEAR_CODE +Bs3Cg1EncodeNext_VEX_MODRM_VsomethingWO_Msomething_Wip_Lxx_OR_ViceVersa(PBS3CG1STATE pThis, unsigned iEncoding, uint8_t uVexL) +{ + unsigned off; + switch (iEncoding) + { + case 0: + off = Bs3Cg1InsertVex2bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, uVexL, 1 /*~R*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 0); + iEncoding += !BS3CG1_IS_64BIT_TARGET(pThis) ? 1 : 0; + break; +#if ARCH_BITS == 64 + case 1: + off = Bs3Cg1InsertVex2bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, uVexL, 0 /*~R*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 7 + 8); + break; +#endif + case 2: + off = Bs3Cg1InsertVex2bPrefix(pThis, 0 /*offDst*/, 0xe /*~V*/, uVexL, 1 /*~R*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 0); + pThis->fInvalidEncoding = true; + break; + case 3: + off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, uVexL, 1 /*~R*/, 1 /*~X*/, 1 /*~B*/, 0 /*W*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 1); + break; + case 4: + off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, uVexL, 1 /*~R*/, 1 /*~X*/, 1 /*~B*/, 1 /*W-ignored*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 5); + iEncoding += !BS3CG1_IS_64BIT_TARGET(pThis) ? 3 : 0; + break; +#if ARCH_BITS == 64 + case 5: + off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, uVexL, 0 /*~R*/, 1 /*~X*/, 1 /*~B*/, 0 /*W*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 5+8); + break; + case 6: + off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, uVexL, 1 /*~R*/, 1 /*~X*/, 0 /*~B-ignored*/, 0 /*W*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 1); + break; + case 7: + off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, uVexL, 1 /*~R*/, 0 /*~X-ignored*/, 1 /*~B*/, 0 /*W*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 2); + break; +#endif + case 8: + off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 0 /*~V*/, uVexL, 1 /*~R*/, 1 /*~X*/, 1 /*~B*/, 0 /*W*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 5); + pThis->fInvalidEncoding = true; + break; + case 9: + off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 7 /*~V*/, uVexL, 1 /*~R*/, 1 /*~X*/, 1 /*~B*/, 0 /*W*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 2); + pThis->fInvalidEncoding = true; + break; + default: + return 0; + } + pThis->cbCurInstr = off; + return iEncoding + 1; +} + + +/** + * Wip - VEX.W ignored. + * L0 - VEX.L is zero (encoding may exist where it isn't). + */ +static unsigned BS3_NEAR_CODE +Bs3Cg1EncodeNext_VEX_MODRM_VsomethingWO_Msomething_Wip_L0_OR_ViceVersa(PBS3CG1STATE pThis, unsigned iEncoding) +{ + return Bs3Cg1EncodeNext_VEX_MODRM_VsomethingWO_Msomething_Wip_Lxx_OR_ViceVersa(pThis, iEncoding, 0 /*uVexL*/); +} + + +/** + * Wip - VEX.W ignored. + * L1 - VEX.L is one (encoding may exist where it isn't). + */ +static unsigned BS3_NEAR_CODE +Bs3Cg1EncodeNext_VEX_MODRM_VsomethingWO_Msomething_Wip_L1_OR_ViceVersa(PBS3CG1STATE pThis, unsigned iEncoding) +{ + return Bs3Cg1EncodeNext_VEX_MODRM_VsomethingWO_Msomething_Wip_Lxx_OR_ViceVersa(pThis, iEncoding, 1 /*uVexL*/); +} + + + +/** + * Wip - VEX.W ignored. + */ +static unsigned BS3_NEAR_CODE +Bs3Cg1EncodeNext_VEX_MODRM_VsomethingWO_Hsomething_Msomething_Wip_OR_ViceVersa(PBS3CG1STATE pThis, unsigned iEncoding) +{ + unsigned off; + switch (iEncoding) + { + case 0: + off = Bs3Cg1InsertVex2bPrefix(pThis, 0 /*offDst*/, 0xc /*~V*/, 0 /*L*/, 1 /*~R*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 0); + pThis->aOperands[1].idxField = pThis->aOperands[1].idxFieldBase + 3; + break; + case 1: + off = Bs3Cg1InsertVex2bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, 1 /*L*/, 1 /*~R*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 7); + pThis->aOperands[1].idxField = pThis->aOperands[1].idxFieldBase + 0; + pThis->fInvalidEncoding = true; + iEncoding += !BS3CG1_IS_64BIT_TARGET(pThis) ? 1 : 0; + break; +#if ARCH_BITS == 64 + case 2: + off = Bs3Cg1InsertVex2bPrefix(pThis, 0 /*offDst*/, 0x1 /*~V*/, 0 /*L*/, 0 /*~R*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 7 + 8); + pThis->aOperands[1].idxField = pThis->aOperands[1].idxFieldBase + 14; + break; +#endif + case 3: + off = Bs3Cg1InsertVex2bPrefix(pThis, 0 /*offDst*/, 0xe /*~V*/, 0 /*L*/, 1 /*~R*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 0); + pThis->aOperands[1].idxField = pThis->aOperands[1].idxFieldBase + 1; + break; + case 4: + off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, 0 /*L*/, 1 /*~R*/, 1 /*~X*/, 1 /*~B*/, 0 /*W*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 1); + pThis->aOperands[1].idxField = pThis->aOperands[1].idxFieldBase + 0; + break; + case 5: + off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, 1 /*L-ignored*/, 1 /*~R*/, 1 /*~X*/, 1 /*~B*/, 0 /*W*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 1); + pThis->aOperands[1].idxField = pThis->aOperands[1].idxFieldBase + 0; + pThis->fInvalidEncoding = true; + break; + case 6: + off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, 0 /*L*/, 1 /*~R*/, 1 /*~X*/, 1 /*~B*/, 1 /*W-ignored*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 5); + pThis->aOperands[1].idxField = pThis->aOperands[1].idxFieldBase + 0; + iEncoding += !BS3CG1_IS_64BIT_TARGET(pThis) ? 3 : 0; + break; +#if ARCH_BITS == 64 + case 7: + off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, 0 /*L*/, 0 /*~R*/, 1 /*~X*/, 1 /*~B*/, 0 /*W*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 5+8); + pThis->aOperands[1].idxField = pThis->aOperands[1].idxFieldBase + 0; + break; + case 8: + off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, 0 /*L*/, 1 /*~R*/, 1 /*~X*/, 0 /*~B-ignored*/, 0 /*W*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 1); + pThis->aOperands[1].idxField = pThis->aOperands[1].idxFieldBase + 0; + break; + case 9: + off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, 0 /*L*/, 1 /*~R*/, 0 /*~X-ignored*/, 1 /*~B*/, 0 /*W*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 2); + pThis->aOperands[1].idxField = pThis->aOperands[1].idxFieldBase + 0; + break; +#endif + case 10: + off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 0 /*~V*/, 1 /*L*/, 1 /*~R*/, 1 /*~X*/, 1 /*~B*/, 0 /*W*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 5); + pThis->aOperands[1].idxField = pThis->aOperands[1].idxFieldBase + (BS3CG1_IS_64BIT_TARGET(pThis) ? 15 : 7); + pThis->fInvalidEncoding = true; + break; + default: + return 0; + } + pThis->cbCurInstr = off; + return iEncoding + 1; +} + + +static unsigned BS3_NEAR_CODE Bs3Cg1EncodeNext_VEX_MODRM_Md_WO(PBS3CG1STATE pThis, unsigned iEncoding) +{ + unsigned off; + switch (iEncoding) + { + case 0: + off = Bs3Cg1InsertVex2bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, 0 /*L*/, 1 /*~R*/); + off = Bs3Cg1InsertOpcodes(pThis, off) - 1; + off = Bs3Cfg1EncodeMemMod0DispWithDefaultsAndNoReg(pThis, off); + break; + case 1: + off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, 0 /*L*/, 1 /*~R*/, 1 /*~X*/, 1 /*~B*/, 0 /*W*/); + off = Bs3Cg1InsertOpcodes(pThis, off) - 1; + off = Bs3Cfg1EncodeMemMod0DispWithDefaultsAndNoReg(pThis, off); + break; + case 2: + off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 0x7 /*~V-invalid*/, 0 /*L*/, 1 /*~R*/, 1 /*~X*/, 1 /*~B*/, 0 /*W*/); + off = Bs3Cg1InsertOpcodes(pThis, off) - 1; + off = Bs3Cfg1EncodeMemMod0DispWithDefaultsAndNoReg(pThis, off); + pThis->fInvalidEncoding = true; + break; + case 3: + off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, 1 /*L*/, 1 /*~R*/, 1 /*~X*/, 1 /*~B*/, 0 /*W*/); + off = Bs3Cg1InsertOpcodes(pThis, off) - 1; + off = Bs3Cfg1EncodeMemMod0DispWithDefaultsAndNoReg(pThis, off); + pThis->fInvalidEncoding = true; + break; + case 4: + pThis->abCurInstr[0] = P_OZ; + off = Bs3Cg1InsertVex3bPrefix(pThis, 1 /*offDst*/, 0xf /*~V*/, 0 /*L*/, 1 /*~R*/, 1 /*~X*/, 1 /*~B*/, 0 /*W*/); + off = Bs3Cg1InsertOpcodes(pThis, off) - 1; + off = Bs3Cfg1EncodeMemMod0DispWithDefaultsAndNoReg(pThis, off); + pThis->fInvalidEncoding = true; + break; + case 5: + pThis->abCurInstr[0] = P_RZ; + off = Bs3Cg1InsertVex3bPrefix(pThis, 1 /*offDst*/, 0xf /*~V*/, 0 /*L*/, 1 /*~R*/, 1 /*~X*/, 1 /*~B*/, 0 /*W*/); + off = Bs3Cg1InsertOpcodes(pThis, off) - 1; + off = Bs3Cfg1EncodeMemMod0DispWithDefaultsAndNoReg(pThis, off); + pThis->fInvalidEncoding = true; + break; + case 6: + pThis->abCurInstr[0] = P_RN; + off = Bs3Cg1InsertVex3bPrefix(pThis, 1 /*offDst*/, 0xf /*~V*/, 0 /*L*/, 1 /*~R*/, 1 /*~X*/, 1 /*~B*/, 0 /*W*/); + off = Bs3Cg1InsertOpcodes(pThis, off) - 1; + off = Bs3Cfg1EncodeMemMod0DispWithDefaultsAndNoReg(pThis, off); + pThis->fInvalidEncoding = true; + break; + case 7: + off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, 0 /*L*/, 1 /*~R*/, 1 /*~X*/, 1 /*~B*/, 1 /*W*/); + off = Bs3Cg1InsertOpcodes(pThis, off) - 1; + off = Bs3Cfg1EncodeMemMod0DispWithDefaultsAndNoReg(pThis, off); + iEncoding += !BS3CG1_IS_64BIT_TARGET(pThis) ? 1 : 0; + break; +#if ARCH_BITS == 64 + case 8: + pThis->abCurInstr[0] = REX_____; + off = Bs3Cg1InsertVex3bPrefix(pThis, 1 /*offDst*/, 0xf /*~V*/, 0 /*L*/, 1 /*~R*/, 1 /*~X*/, 1 /*~B*/, 0 /*W*/); + off = Bs3Cg1InsertOpcodes(pThis, off) - 1; + off = Bs3Cfg1EncodeMemMod0DispWithDefaultsAndNoReg(pThis, off); + pThis->fInvalidEncoding = true; + break; +#endif + default: + return 0; + } + + pThis->cbCurInstr = off; + return iEncoding + 1; +} + + +/** + * Wip = VEX.W ignored. + * Lmbz = VEX.L must be zero. + */ +static unsigned BS3_NEAR_CODE +Bs3Cg1EncodeNext_VEX_MODRM_WsomethingWO_Vsomething_Wip_Lmbz_OR_ViceVersa(PBS3CG1STATE pThis, unsigned iEncoding) +{ + unsigned off; + switch (iEncoding) + { + /* 128-bit wide stuff goes first, then we'll update the operand widths afterwards. */ + case 0: + pThis->aOperands[pThis->iRmOp ].enmLocation = pThis->aOperands[pThis->iRmOp].enmLocationReg; + off = Bs3Cg1InsertVex2bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, 0 /*L*/, 1 /*~R*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cg1InsertModRmWithRegFields(pThis, off, 1, 0); + break; + + case 1: + off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, 0 /*L*/, 1 /*~R*/, 1 /*~X*/, 1 /*~B*/, 0 /*W*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cg1InsertModRmWithRegFields(pThis, off, 4, 5); + break; + case 2: + off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, 0 /*L*/, 1 /*~R*/, 1 /*~X*/, 1 /*~B*/, 1 /*W - ignored*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cg1InsertModRmWithRegFields(pThis, off, 5, 4); + break; + case 3: + pThis->aOperands[pThis->iRmOp].enmLocation = pThis->aOperands[pThis->iRmOp].enmLocationMem; + off = Bs3Cg1InsertVex2bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, 0 /*L*/, 1 /*~R*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 2 /*iReg*/); + break; + case 4: + off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, 0 /*L*/, 1 /*~R*/, 1 /*~X*/, 1 /*~B*/, 0 /*W*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 3 /*iReg*/); + break; + case 5: + off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, 0 /*L*/, 1 /*~R*/, 1 /*~X*/, 1 /*~B*/, 1 /*W - ignored */); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 3 /*iReg*/); + break; + case 6: + off = Bs3Cg1InsertVex2bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, 0 /*L*/, 1 /*~R*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaultsMisaligned(pThis, off, 3 /*iReg*/, 1 /*cbMisalign*/); + if (!Bs3Cg1XcptTypeIsVexUnaligned(pThis->enmXcptType)) + pThis->bAlignmentXcpt = X86_XCPT_GP; + break; + case 7: + off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, 0 /*L*/, 1 /*~R*/, 1 /*~X*/, 1 /*~B*/, 0 /*W*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaultsMisaligned(pThis, off, 3 /*iReg*/, 1 /*cbMisalign*/); + if (!Bs3Cg1XcptTypeIsVexUnaligned(pThis->enmXcptType)) + pThis->bAlignmentXcpt = X86_XCPT_GP; + break; + /* 128-bit invalid encodings: */ + case 8: + pThis->aOperands[pThis->iRmOp ].enmLocation = pThis->aOperands[pThis->iRmOp].enmLocationReg; + off = Bs3Cg1InsertVex2bPrefix(pThis, 0 /*offDst*/, 0xe /*~V*/, 0 /*L*/, 1 /*~R*/); /* Bad V value */ + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cg1InsertModRmWithRegFields(pThis, off, 1, 0); + pThis->fInvalidEncoding = true; + break; + case 9: + off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 0 /*~V*/, 0 /*L*/, 1 /*~R*/, 1 /*~X*/, 1 /*~B*/, 0 /*W*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cg1InsertModRmWithRegFields(pThis, off, 4, 5); + pThis->fInvalidEncoding = true; + iEncoding = 20-1; + break; + + default: + return 0; + } + + pThis->cbCurInstr = off; + return iEncoding + 1; +} + + +/** + * Wip = VEX.W ignored. + */ +static unsigned BS3_NEAR_CODE +Bs3Cg1EncodeNext_VEX_MODRM_WsomethingWO_Vsomething_Wip_OR_ViceVersa(PBS3CG1STATE pThis, unsigned iEncoding) +{ + unsigned off; + + switch (iEncoding) + { + case 20: /* switch to 256-bit */ + pThis->aOperands[pThis->iRmOp ].cbOp = 32; + pThis->aOperands[pThis->iRmOp ].idxFieldBase = BS3CG1DST_YMM0; + pThis->aOperands[pThis->iRegOp].cbOp = 32; + pThis->aOperands[pThis->iRegOp].idxFieldBase = BS3CG1DST_YMM0; + RT_FALL_THRU(); + case 0: + pThis->aOperands[pThis->iRmOp ].enmLocation = pThis->aOperands[pThis->iRmOp].enmLocationReg; + off = Bs3Cg1InsertVex2bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, iEncoding >= 20 /*L*/, 1 /*~R*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cg1InsertModRmWithRegFields(pThis, off, 1, 0); + break; + + case 1: + case 21: + off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, iEncoding >= 20 /*L*/, 1 /*~R*/, 1 /*~X*/, 1 /*~B*/, 0 /*W*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cg1InsertModRmWithRegFields(pThis, off, 4, 5); + break; + case 2: + case 22: + off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, iEncoding >= 20 /*L*/, 1 /*~R*/, 1 /*~X*/, 1 /*~B*/, 1 /*W - ignored*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cg1InsertModRmWithRegFields(pThis, off, 5, 4); + break; + case 3: + case 23: + pThis->aOperands[pThis->iRmOp].enmLocation = pThis->aOperands[pThis->iRmOp].enmLocationMem; + off = Bs3Cg1InsertVex2bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, iEncoding >= 20 /*L*/, 1 /*~R*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 2 /*iReg*/); + break; + case 4: + case 24: + off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, iEncoding >= 20 /*L*/, 1 /*~R*/, 1 /*~X*/, 1 /*~B*/, 0 /*W*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 3 /*iReg*/); + break; + case 5: + case 25: + off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, iEncoding >= 20 /*L*/, 1 /*~R*/, 1 /*~X*/, 1 /*~B*/, 1 /*W - ignored */); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaults(pThis, off, 3 /*iReg*/); + break; + case 6: + case 26: + off = Bs3Cg1InsertVex2bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, iEncoding >= 20 /*L*/, 1 /*~R*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaultsMisaligned(pThis, off, 3 /*iReg*/, 1 /*cbMisalign*/); + if (!Bs3Cg1XcptTypeIsVexUnaligned(pThis->enmXcptType)) + pThis->bAlignmentXcpt = X86_XCPT_GP; + break; + case 7: + case 27: + off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, iEncoding >= 20 /*L*/, 1 /*~R*/, 1 /*~X*/, 1 /*~B*/, 0 /*W*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cfg1EncodeMemMod0DispWithRegFieldAndDefaultsMisaligned(pThis, off, 3 /*iReg*/, 1 /*cbMisalign*/); + if (!Bs3Cg1XcptTypeIsVexUnaligned(pThis->enmXcptType)) + pThis->bAlignmentXcpt = X86_XCPT_GP; + break; + /* invalid encodings: */ + case 8: + case 28: + pThis->aOperands[pThis->iRmOp ].enmLocation = pThis->aOperands[pThis->iRmOp].enmLocationReg; + off = Bs3Cg1InsertVex2bPrefix(pThis, 0 /*offDst*/, 0xe /*~V*/, iEncoding >= 20 /*L*/, 1 /*~R*/); /* Bad V value */ + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cg1InsertModRmWithRegFields(pThis, off, 1, 0); + pThis->fInvalidEncoding = true; + break; + case 9: + case 29: + off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 0 /*~V*/, iEncoding >= 20 /*L*/, 1 /*~R*/, 1 /*~X*/, 1 /*~B*/, 0 /*W*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cg1InsertModRmWithRegFields(pThis, off, 4, 5); + pThis->fInvalidEncoding = true; + break; + + case 10: + case 30: + pThis->abCurInstr[0] = P_RN; + off = Bs3Cg1InsertVex3bPrefix(pThis, 1 /*offDst*/, 0xf /*~V*/, iEncoding >= 20 /*L*/, 1 /*~R*/, 1 /*~X*/, 1 /*~B*/, 0 /*W*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cg1InsertModRmWithRegFields(pThis, off, 4, 5); + pThis->fInvalidEncoding = true; + break; + case 11: + case 31: + pThis->abCurInstr[0] = P_RZ; + off = Bs3Cg1InsertVex3bPrefix(pThis, 1 /*offDst*/, 0xf /*~V*/, iEncoding >= 20 /*L*/, 1 /*~R*/, 1 /*~X*/, 1 /*~B*/, 0 /*W*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cg1InsertModRmWithRegFields(pThis, off, 4, 5); + pThis->fInvalidEncoding = true; + break; + case 12: + case 32: + pThis->abCurInstr[0] = P_OZ; + off = Bs3Cg1InsertVex3bPrefix(pThis, 1 /*offDst*/, 0xf /*~V*/, iEncoding >= 20 /*L*/, 1 /*~R*/, 1 /*~X*/, 1 /*~B*/, 0 /*W*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cg1InsertModRmWithRegFields(pThis, off, 4, 5); + pThis->fInvalidEncoding = true; + break; + case 13: + case 33: + pThis->abCurInstr[0] = P_LK; + off = Bs3Cg1InsertVex3bPrefix(pThis, 1 /*offDst*/, 0xf /*~V*/, iEncoding >= 20 /*L*/, 1 /*~R*/, 1 /*~X*/, 1 /*~B*/, 0 /*W*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cg1InsertModRmWithRegFields(pThis, off, 4, 5); + pThis->fInvalidEncoding = true; + iEncoding += !BS3CG1_IS_64BIT_TARGET(pThis) ? 2 + 4 : 0; + break; + +#if ARCH_BITS == 64 + /* 64-bit mode registers */ + case 14: + case 34: + off = Bs3Cg1InsertVex2bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, iEncoding >= 20 /*L*/, 0 /*~R*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cg1InsertModRmWithRegFields(pThis, off, 3+8, 4); + break; + case 15: + case 35: + off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, iEncoding >= 20 /*L*/, 0 /*~R*/, 1 /*~X*/, 0 /*~B*/, 0 /*W*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + off = Bs3Cg1InsertModRmWithRegFields(pThis, off, 1+8, 4+8); + iEncoding += 4; + break; +#endif + default: + return 0; + } + + pThis->cbCurInstr = off; + return iEncoding + 1; +} + + +//static unsigned BS3_NEAR_CODE Bs3Cg1EncodeNext_VEX_FIXED(PBS3CG1STATE pThis, unsigned iEncoding) +//{ +// unsigned off; +// if (iEncoding == 0) +// off = Bs3Cg1InsertVex2bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, 0 /*L*/, 1 /*~R*/); +// else if (iEncoding == 0) +// off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, 0 /*L*/, 1 /*~R*/, 1 /*~X*/, 1 /*~B*/, 0 /*W*/); +// else +// return 0; +// pThis->cbCurInstr = off; +// return iEncoding + 1; +//} + + +static unsigned BS3_NEAR_CODE Bs3Cg1EncodeNext_VEX_MODRM_MOD_EQ_3(PBS3CG1STATE pThis, unsigned iEncoding) +{ + unsigned off; + if (iEncoding < 8) + { + if (iEncoding & 1) + off = Bs3Cg1InsertVex2bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, 0 /*L*/, 1 /*~R*/); + else + off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, 0 /*L*/, 1 /*~R*/, 1 /*~X*/, 1 /*~B*/, 0 /*W*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + pThis->abCurInstr[off++] = X86_MODRM_MAKE(3, iEncoding, 1); + } + else if (iEncoding < 16) + { + if (iEncoding & 1) + off = Bs3Cg1InsertVex2bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, 1 /*L*/, 1 /*~R*/); + else + off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, 1 /*L*/, 1 /*~R*/, 1 /*~X*/, 1 /*~B*/, 0 /*W*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + pThis->abCurInstr[off++] = X86_MODRM_MAKE(3, iEncoding & 7, 1); + } + else if (iEncoding < 24) + { + if (iEncoding & 1) + off = Bs3Cg1InsertVex2bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, 0 /*L*/, 1 /*~R*/); + else + off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, 0 /*L*/, 1 /*~R*/, 1 /*~X*/, 1 /*~B*/, 0 /*W*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + pThis->abCurInstr[off++] = X86_MODRM_MAKE(3, 0, iEncoding & 7); + } + else if (iEncoding < 32) + { + if (iEncoding & 1) + off = Bs3Cg1InsertVex2bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, (iEncoding & 3) != 0 /*L*/, 1 /*~R*/); + else + off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, (iEncoding & 2) != 0 /*L*/, 1 /*~R*/, 1 /*~X*/, + 1 /*~B*/, (iEncoding & 4) != 0 /*W*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + pThis->abCurInstr[off++] = X86_MODRM_MAKE(3, 0, iEncoding & 7); + } + else + return 0; + pThis->cbCurInstr = off; + + return iEncoding + 1; +} + + +static unsigned BS3_NEAR_CODE Bs3Cg1EncodeNext_VEX_MODRM_MOD_NE_3(PBS3CG1STATE pThis, unsigned iEncoding) +{ + unsigned off; + if (iEncoding < 8) + { + unsigned iMod = iEncoding % 3; + if (iEncoding & 1) + off = Bs3Cg1InsertVex2bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, (iEncoding & 2) != 0 /*L*/, 1 /*~R*/); + else + off = Bs3Cg1InsertVex3bPrefix(pThis, 0 /*offDst*/, 0xf /*~V*/, (iEncoding & 2) != 0 /*L*/, 1 /*~R*/, + 1 /*~X*/, 1 /*~B*/, (iEncoding & 4) != 0 /*W*/); + off = Bs3Cg1InsertOpcodes(pThis, off); + pThis->abCurInstr[off++] = X86_MODRM_MAKE(iMod, 0, 1); + if (iMod >= 1) + pThis->abCurInstr[off++] = 0x7f; + if (iMod == 2) + { + pThis->abCurInstr[off++] = 0x5f; + if (!BS3_MODE_IS_16BIT_CODE(pThis->bMode)) + { + pThis->abCurInstr[off++] = 0x3f; + pThis->abCurInstr[off++] = 0x1f; + } + } + } + else + return 0; + pThis->cbCurInstr = off; + return iEncoding + 1; +} + + +static unsigned BS3_NEAR_CODE Bs3Cg1EncodeNext_VEX_MODRM(PBS3CG1STATE pThis, unsigned iEncoding) +{ + const unsigned cFirstEncodings = 32; + if (iEncoding < cFirstEncodings) + { + unsigned iRet = Bs3Cg1EncodeNext_VEX_MODRM_MOD_EQ_3(pThis, iEncoding); + BS3_ASSERT(iRet > iEncoding); + return iRet; + } + return Bs3Cg1EncodeNext_VEX_MODRM_MOD_NE_3(pThis, iEncoding - cFirstEncodings) + cFirstEncodings; +} + +#endif /* BS3CG1_WITH_VEX */ + + +/** + * Encodes the next instruction. + * + * @returns Next iEncoding value. Returns @a iEncoding unchanged to indicate + * that there are no more encodings to test. + * @param pThis The state. + * @param iEncoding The encoding to produce. Meaning is specific to + * each BS3CG1ENC_XXX value and should be considered + * internal. + */ +static unsigned BS3_NEAR_CODE Bs3Cg1EncodeNext(PBS3CG1STATE pThis, unsigned iEncoding) +{ + pThis->bAlignmentXcpt = UINT8_MAX; + pThis->uVexL = UINT8_MAX; + if (pThis->pfnEncoder) + return pThis->pfnEncoder(pThis, iEncoding); + + Bs3TestFailedF("Internal error! BS3CG1ENC_XXX = %u not implemented", pThis->enmEncoding); + return iEncoding; +} + + +/** + * Prepares doing instruction encodings. + * + * This is in part specific to how the instruction is encoded, but generally it + * sets up basic operand values that doesn't change (much) when Bs3Cg1EncodeNext + * is called from within the loop. + * + * @returns Success indicator (true/false). + * @param pThis The state. + */ +#define Bs3Cg1EncodePrep BS3_CMN_NM(Bs3Cg1EncodePrep) +bool BS3_NEAR_CODE Bs3Cg1EncodePrep(PBS3CG1STATE pThis) +{ + unsigned i = 4; + while (i-- > 0) + pThis->aSavedSegRegs[i].ds = pThis->aInitialCtxs[i].ds; + + i = RT_ELEMENTS(pThis->aOperands); + while (i-- > 0) + { + pThis->aOperands[i].enmLocationReg = BS3CG1OPLOC_INVALID; + pThis->aOperands[i].enmLocationMem = BS3CG1OPLOC_INVALID; + pThis->aOperands[i].idxFieldBase = BS3CG1DST_INVALID; + } + + pThis->iRmOp = RT_ELEMENTS(pThis->aOperands) - 1; + pThis->iRegOp = RT_ELEMENTS(pThis->aOperands) - 1; + pThis->fSameRingNotOkay = false; + pThis->cbOperand = 0; + pThis->pfnEncoder = NULL; + + switch (pThis->enmEncoding) + { + case BS3CG1ENC_MODRM_Eb_Gb: + pThis->pfnEncoder = Bs3Cg1EncodeNext_MODRM_Eb_Gb_OR_ViceVersa; + pThis->iRmOp = 0; + pThis->iRegOp = 1; + pThis->aOperands[0].cbOp = 1; + pThis->aOperands[1].cbOp = 1; + pThis->aOperands[0].idxFieldBase = BS3CG1DST_AL; + pThis->aOperands[1].idxFieldBase = BS3CG1DST_AL; + pThis->aOperands[0].enmLocationReg = BS3CG1OPLOC_CTX; + pThis->aOperands[0].enmLocationMem = BS3CG1OPLOC_MEM_RW; + pThis->aOperands[1].enmLocation = BS3CG1OPLOC_CTX; + break; + + case BS3CG1ENC_MODRM_Ev_Gv: + pThis->pfnEncoder = Bs3Cg1EncodeNext_MODRM_Gv_Ev__OR__MODRM_Ev_Gv; + pThis->iRmOp = 0; + pThis->iRegOp = 1; + pThis->cbOperand = 2; + pThis->aOperands[0].idxFieldBase = BS3CG1DST_OZ_RAX; + pThis->aOperands[1].idxFieldBase = BS3CG1DST_OZ_RAX; + pThis->aOperands[0].enmLocationReg = BS3CG1OPLOC_CTX; + pThis->aOperands[0].enmLocationMem = BS3CG1OPLOC_MEM_RW; + pThis->aOperands[1].enmLocation = BS3CG1OPLOC_CTX; + break; + + case BS3CG1ENC_MODRM_Ed_WO_Pd_WZ: + pThis->pfnEncoder = Bs3Cg1EncodeNext_MODRM_PdZx_WO_Ed_WZ; + pThis->iRmOp = 0; + pThis->iRegOp = 1; + pThis->aOperands[0].cbOp = 4; + pThis->aOperands[1].cbOp = 4; + pThis->aOperands[0].idxFieldBase = BS3CG1DST_EAX; + pThis->aOperands[1].idxFieldBase = BS3CG1DST_MM0; + pThis->aOperands[0].enmLocation = BS3CG1OPLOC_CTX; + pThis->aOperands[0].enmLocationReg = BS3CG1OPLOC_CTX; + pThis->aOperands[0].enmLocationMem = BS3CG1OPLOC_MEM_WO; + pThis->aOperands[1].enmLocation = BS3CG1OPLOC_CTX; + break; + + case BS3CG1ENC_MODRM_Eq_WO_Pq_WNZ: + pThis->pfnEncoder = Bs3Cg1EncodeNext_MODRM_Pq_WO_Eq_WNZ; + pThis->iRmOp = 0; + pThis->iRegOp = 1; + pThis->aOperands[0].cbOp = 8; + pThis->aOperands[1].cbOp = 8; + pThis->aOperands[0].idxFieldBase = BS3CG1DST_RAX; + pThis->aOperands[1].idxFieldBase = BS3CG1DST_MM0; + pThis->aOperands[0].enmLocation = BS3CG1OPLOC_CTX; + pThis->aOperands[0].enmLocationReg = BS3CG1OPLOC_CTX; + pThis->aOperands[0].enmLocationMem = BS3CG1OPLOC_MEM_WO; + pThis->aOperands[1].enmLocation = BS3CG1OPLOC_CTX; + break; + + case BS3CG1ENC_MODRM_Ed_WO_Vd_WZ: + pThis->pfnEncoder = Bs3Cg1EncodeNext_MODRM_Vd_WO_Ed_WZ; + pThis->iRmOp = 0; + pThis->iRegOp = 1; + pThis->aOperands[0].cbOp = 4; + pThis->aOperands[1].cbOp = 4; + pThis->aOperands[0].idxFieldBase = BS3CG1DST_EAX; + pThis->aOperands[1].idxFieldBase = BS3CG1DST_XMM0; + pThis->aOperands[0].enmLocation = BS3CG1OPLOC_CTX; + pThis->aOperands[0].enmLocationReg = BS3CG1OPLOC_CTX; + pThis->aOperands[0].enmLocationMem = BS3CG1OPLOC_MEM_WO; + pThis->aOperands[1].enmLocation = BS3CG1OPLOC_CTX; + break; + + case BS3CG1ENC_MODRM_Eq_WO_Vq_WNZ: + pThis->pfnEncoder = Bs3Cg1EncodeNext_MODRM_Vq_WO_Eq_WNZ; + pThis->iRmOp = 0; + pThis->iRegOp = 1; + pThis->aOperands[0].cbOp = 8; + pThis->aOperands[1].cbOp = 8; + pThis->aOperands[0].idxFieldBase = BS3CG1DST_RAX; + pThis->aOperands[1].idxFieldBase = BS3CG1DST_XMM0; + pThis->aOperands[0].enmLocation = BS3CG1OPLOC_CTX; + pThis->aOperands[0].enmLocationReg = BS3CG1OPLOC_CTX; + pThis->aOperands[0].enmLocationMem = BS3CG1OPLOC_MEM_WO; + pThis->aOperands[1].enmLocation = BS3CG1OPLOC_CTX; + break; + + case BS3CG1ENC_MODRM_Gb_Eb: + pThis->pfnEncoder = Bs3Cg1EncodeNext_MODRM_Eb_Gb_OR_ViceVersa; + pThis->iRegOp = 0; + pThis->iRmOp = 1; + pThis->aOperands[0].cbOp = 1; + pThis->aOperands[1].cbOp = 1; + pThis->aOperands[0].idxFieldBase = BS3CG1DST_AL; + pThis->aOperands[1].idxFieldBase = BS3CG1DST_AL; + pThis->aOperands[0].enmLocation = BS3CG1OPLOC_CTX; + pThis->aOperands[1].enmLocationReg = BS3CG1OPLOC_CTX; + pThis->aOperands[1].enmLocationMem = BS3CG1OPLOC_MEM; + break; + + case BS3CG1ENC_MODRM_Gv_Ev: + pThis->pfnEncoder = Bs3Cg1EncodeNext_MODRM_Gv_Ev__OR__MODRM_Ev_Gv; + pThis->iRegOp = 0; + pThis->iRmOp = 1; + pThis->cbOperand = 2; + pThis->aOperands[0].idxFieldBase = BS3CG1DST_OZ_RAX; + pThis->aOperands[1].idxFieldBase = BS3CG1DST_OZ_RAX; + pThis->aOperands[0].enmLocation = BS3CG1OPLOC_CTX; + pThis->aOperands[1].enmLocationReg = BS3CG1OPLOC_CTX; + pThis->aOperands[1].enmLocationMem = BS3CG1OPLOC_MEM; + break; + + case BS3CG1ENC_MODRM_Gv_RO_Ma: /* bound instr */ + pThis->pfnEncoder = Bs3Cg1EncodeNext_MODRM_Gv_RO_Ma; + pThis->iRmOp = 1; + pThis->iRegOp = 0; + pThis->cbOperand = 2; + pThis->aOperands[0].cbOp = 2; + pThis->aOperands[1].cbOp = 4; + pThis->aOperands[0].enmLocation = BS3CG1OPLOC_CTX; + pThis->aOperands[1].enmLocation = BS3CG1OPLOC_MEM; + pThis->aOperands[0].idxFieldBase = BS3CG1DST_OZ_RAX; + break; + + case BS3CG1ENC_MODRM_Wss_WO_Vss: + pThis->pfnEncoder = Bs3Cg1EncodeNext_MODRM_Vsomething_Wsomething_OR_ViceVersa; + pThis->iRmOp = 0; + pThis->iRegOp = 1; + pThis->aOperands[0].cbOp = 4; + pThis->aOperands[1].cbOp = 4; + pThis->aOperands[0].idxFieldBase = BS3CG1DST_XMM0_DW0; + pThis->aOperands[1].idxFieldBase = BS3CG1DST_XMM0_DW0; + pThis->aOperands[0].enmLocationMem = BS3CG1OPLOC_MEM_WO; + pThis->aOperands[0].enmLocationReg = BS3CG1OPLOC_CTX; + pThis->aOperands[1].enmLocation = BS3CG1OPLOC_CTX; + break; + + case BS3CG1ENC_MODRM_Wsd_WO_Vsd: + pThis->pfnEncoder = Bs3Cg1EncodeNext_MODRM_Vsomething_Wsomething_OR_ViceVersa; + pThis->iRmOp = 0; + pThis->iRegOp = 1; + pThis->aOperands[0].cbOp = 8; + pThis->aOperands[1].cbOp = 8; + pThis->aOperands[0].idxFieldBase = BS3CG1DST_XMM0_LO; + pThis->aOperands[1].idxFieldBase = BS3CG1DST_XMM0_LO; + pThis->aOperands[0].enmLocationMem = BS3CG1OPLOC_MEM_WO; + pThis->aOperands[0].enmLocationReg = BS3CG1OPLOC_CTX; + pThis->aOperands[1].enmLocation = BS3CG1OPLOC_CTX; + break; + + case BS3CG1ENC_MODRM_WqZxReg_WO_Vq: + pThis->pfnEncoder = Bs3Cg1EncodeNext_MODRM_Vsomething_Wsomething_OR_ViceVersa; + pThis->iRmOp = 0; + pThis->iRegOp = 1; + pThis->aOperands[0].cbOp = 8; + pThis->aOperands[1].cbOp = 8; + pThis->aOperands[0].idxFieldBase = BS3CG1DST_XMM0_LO_ZX; + pThis->aOperands[1].idxFieldBase = BS3CG1DST_XMM0_LO; + pThis->aOperands[0].enmLocationReg = BS3CG1OPLOC_CTX; + pThis->aOperands[0].enmLocationMem = BS3CG1OPLOC_MEM_WO; + pThis->aOperands[1].enmLocation = BS3CG1OPLOC_CTX; + break; + + case BS3CG1ENC_MODRM_Wps_WO_Vps: + case BS3CG1ENC_MODRM_Wpd_WO_Vpd: + pThis->pfnEncoder = Bs3Cg1EncodeNext_MODRM_Vsomething_Wsomething_OR_ViceVersa; + pThis->iRmOp = 0; + pThis->iRegOp = 1; + pThis->aOperands[0].cbOp = 16; + pThis->aOperands[1].cbOp = 16; + pThis->aOperands[0].idxFieldBase = BS3CG1DST_XMM0; + pThis->aOperands[1].idxFieldBase = BS3CG1DST_XMM0; + pThis->aOperands[0].enmLocationReg = BS3CG1OPLOC_CTX; + pThis->aOperands[0].enmLocationMem = BS3CG1OPLOC_MEM_WO; + pThis->aOperands[1].enmLocation = BS3CG1OPLOC_CTX; + break; + + case BS3CG1ENC_MODRM_Vdq_WO_Mdq: + pThis->pfnEncoder = Bs3Cg1EncodeNext_MODRM_Msomething_Vsomething_OR_ViceVersa; + pThis->iRegOp = 0; + pThis->iRmOp = 1; + pThis->aOperands[0].cbOp = 16; + pThis->aOperands[1].cbOp = 16; + pThis->aOperands[0].enmLocation = BS3CG1OPLOC_CTX; + pThis->aOperands[1].enmLocation = BS3CG1OPLOC_MEM; + pThis->aOperands[0].idxFieldBase = BS3CG1DST_XMM0; + break; + + case BS3CG1ENC_MODRM_Vdq_WO_Wdq: + case BS3CG1ENC_MODRM_Vpd_WO_Wpd: + case BS3CG1ENC_MODRM_Vps_WO_Wps: + pThis->pfnEncoder = Bs3Cg1EncodeNext_MODRM_Vsomething_Wsomething_OR_ViceVersa; + pThis->iRegOp = 0; + pThis->iRmOp = 1; + pThis->aOperands[0].cbOp = 16; + pThis->aOperands[1].cbOp = 16; + pThis->aOperands[0].idxFieldBase = BS3CG1DST_XMM0; + pThis->aOperands[1].idxFieldBase = BS3CG1DST_XMM0; + pThis->aOperands[0].enmLocation = BS3CG1OPLOC_CTX; + pThis->aOperands[1].enmLocationReg = BS3CG1OPLOC_CTX; + pThis->aOperands[1].enmLocationMem = BS3CG1OPLOC_MEM; + break; + + case BS3CG1ENC_MODRM_Pq_WO_Qq: + pThis->pfnEncoder = Bs3Cg1EncodeNext_MODRM_Pq_WO_Qq; + pThis->iRegOp = 0; + pThis->iRmOp = 1; + pThis->aOperands[0].cbOp = 8; + pThis->aOperands[1].cbOp = 8; + pThis->aOperands[0].idxFieldBase = BS3CG1DST_MM0; + pThis->aOperands[1].idxFieldBase = BS3CG1DST_MM0; + pThis->aOperands[0].enmLocation = BS3CG1OPLOC_CTX; + pThis->aOperands[1].enmLocation = BS3CG1OPLOC_CTX; + pThis->aOperands[1].enmLocationReg = BS3CG1OPLOC_CTX; + pThis->aOperands[1].enmLocationMem = BS3CG1OPLOC_MEM; + break; + + case BS3CG1ENC_MODRM_Pq_WO_Uq: + pThis->pfnEncoder = Bs3Cg1EncodeNext_MODRM_Pq_WO_Uq; + pThis->iRegOp = 0; + pThis->iRmOp = 1; + pThis->aOperands[0].cbOp = 8; + pThis->aOperands[1].cbOp = 8; + pThis->aOperands[0].idxFieldBase = BS3CG1DST_MM0; + pThis->aOperands[1].idxFieldBase = BS3CG1DST_XMM0_LO; + pThis->aOperands[0].enmLocation = BS3CG1OPLOC_CTX; + pThis->aOperands[1].enmLocation = BS3CG1OPLOC_CTX; /* reg only */ + break; + + case BS3CG1ENC_MODRM_PdZx_WO_Ed_WZ: + pThis->pfnEncoder = Bs3Cg1EncodeNext_MODRM_PdZx_WO_Ed_WZ; + pThis->iRegOp = 0; + pThis->iRmOp = 1; + pThis->aOperands[0].cbOp = 4; + pThis->aOperands[1].cbOp = 4; + pThis->aOperands[0].idxFieldBase = BS3CG1DST_MM0_LO_ZX; + pThis->aOperands[1].idxFieldBase = BS3CG1DST_EAX; + pThis->aOperands[0].enmLocation = BS3CG1OPLOC_CTX; + pThis->aOperands[1].enmLocation = BS3CG1OPLOC_CTX; + pThis->aOperands[1].enmLocationReg = BS3CG1OPLOC_CTX; + pThis->aOperands[1].enmLocationMem = BS3CG1OPLOC_MEM; + break; + + case BS3CG1ENC_MODRM_Pq_WO_Eq_WNZ: + pThis->pfnEncoder = Bs3Cg1EncodeNext_MODRM_Pq_WO_Eq_WNZ; + pThis->iRegOp = 0; + pThis->iRmOp = 1; + pThis->aOperands[0].cbOp = 8; + pThis->aOperands[1].cbOp = 8; + pThis->aOperands[0].idxFieldBase = BS3CG1DST_MM0; + pThis->aOperands[1].idxFieldBase = BS3CG1DST_RAX; + pThis->aOperands[0].enmLocation = BS3CG1OPLOC_CTX; + pThis->aOperands[1].enmLocation = BS3CG1OPLOC_CTX; + pThis->aOperands[1].enmLocationReg = BS3CG1OPLOC_CTX; + pThis->aOperands[1].enmLocationMem = BS3CG1OPLOC_MEM; + break; + + case BS3CG1ENC_MODRM_VdZx_WO_Ed_WZ: + pThis->pfnEncoder = Bs3Cg1EncodeNext_MODRM_Vd_WO_Ed_WZ; + pThis->iRegOp = 0; + pThis->iRmOp = 1; + pThis->aOperands[0].cbOp = 4; + pThis->aOperands[1].cbOp = 4; + pThis->aOperands[0].idxFieldBase = BS3CG1DST_XMM0_DW0_ZX; + pThis->aOperands[1].idxFieldBase = BS3CG1DST_EAX; + pThis->aOperands[0].enmLocation = BS3CG1OPLOC_CTX; + pThis->aOperands[1].enmLocation = BS3CG1OPLOC_CTX; + pThis->aOperands[1].enmLocationReg = BS3CG1OPLOC_CTX; + pThis->aOperands[1].enmLocationMem = BS3CG1OPLOC_MEM; + break; + + case BS3CG1ENC_MODRM_VqZx_WO_Eq_WNZ: + pThis->pfnEncoder = Bs3Cg1EncodeNext_MODRM_Vq_WO_Eq_WNZ; + pThis->iRegOp = 0; + pThis->iRmOp = 1; + pThis->aOperands[0].cbOp = 8; + pThis->aOperands[1].cbOp = 8; + pThis->aOperands[0].idxFieldBase = BS3CG1DST_XMM0_LO_ZX; + pThis->aOperands[1].idxFieldBase = BS3CG1DST_RAX; + pThis->aOperands[0].enmLocation = BS3CG1OPLOC_CTX; + pThis->aOperands[1].enmLocation = BS3CG1OPLOC_CTX; + pThis->aOperands[1].enmLocationReg = BS3CG1OPLOC_CTX; + pThis->aOperands[1].enmLocationMem = BS3CG1OPLOC_MEM; + break; + + case BS3CG1ENC_MODRM_Vq_WO_UqHi: + pThis->pfnEncoder = Bs3Cg1EncodeNext_MODRM_Vsomething_Usomething_OR_ViceVersa; + pThis->iRegOp = 0; + pThis->iRmOp = 1; + pThis->aOperands[0].cbOp = 8; + pThis->aOperands[1].cbOp = 8; + pThis->aOperands[0].idxFieldBase = BS3CG1DST_XMM0_LO; + pThis->aOperands[1].idxFieldBase = BS3CG1DST_XMM0_HI; + pThis->aOperands[0].enmLocation = BS3CG1OPLOC_CTX; + pThis->aOperands[1].enmLocation = BS3CG1OPLOC_CTX; + break; + + case BS3CG1ENC_MODRM_VqHi_WO_Uq: + pThis->pfnEncoder = Bs3Cg1EncodeNext_MODRM_Vsomething_Usomething_OR_ViceVersa; + pThis->iRegOp = 0; + pThis->iRmOp = 1; + pThis->aOperands[0].cbOp = 8; + pThis->aOperands[1].cbOp = 8; + pThis->aOperands[0].idxFieldBase = BS3CG1DST_XMM0_HI; + pThis->aOperands[1].idxFieldBase = BS3CG1DST_XMM0_LO; + pThis->aOperands[0].enmLocation = BS3CG1OPLOC_CTX; + pThis->aOperands[1].enmLocation = BS3CG1OPLOC_CTX; + break; + + case BS3CG1ENC_MODRM_VqHi_WO_Mq: + pThis->pfnEncoder = Bs3Cg1EncodeNext_MODRM_Msomething_Vsomething_OR_ViceVersa; + pThis->iRegOp = 0; + pThis->iRmOp = 1; + pThis->aOperands[0].cbOp = 8; + pThis->aOperands[1].cbOp = 8; + pThis->aOperands[0].idxFieldBase = BS3CG1DST_XMM0_HI; + pThis->aOperands[0].enmLocation = BS3CG1OPLOC_CTX; + pThis->aOperands[1].enmLocation = BS3CG1OPLOC_MEM; + break; + + case BS3CG1ENC_MODRM_Vq_WO_Mq: + pThis->pfnEncoder = Bs3Cg1EncodeNext_MODRM_Msomething_Vsomething_OR_ViceVersa; + pThis->iRegOp = 0; + pThis->iRmOp = 1; + pThis->aOperands[0].cbOp = 8; + pThis->aOperands[1].cbOp = 8; + pThis->aOperands[0].idxFieldBase = BS3CG1DST_XMM0_LO; + pThis->aOperands[0].enmLocation = BS3CG1OPLOC_CTX; + pThis->aOperands[1].enmLocation = BS3CG1OPLOC_MEM; + break; + + case BS3CG1ENC_MODRM_VssZx_WO_Wss: + pThis->pfnEncoder = Bs3Cg1EncodeNext_MODRM_Vsomething_Wsomething_OR_ViceVersa; + pThis->iRegOp = 0; + pThis->iRmOp = 1; + pThis->aOperands[0].cbOp = 4; + pThis->aOperands[1].cbOp = 4; + pThis->aOperands[0].enmLocation = BS3CG1OPLOC_CTX; + pThis->aOperands[1].enmLocationReg = BS3CG1OPLOC_CTX; + pThis->aOperands[1].enmLocationMem = BS3CG1OPLOC_MEM; + pThis->aOperands[0].idxFieldBase = BS3CG1DST_XMM0_DW0_ZX; + pThis->aOperands[1].idxFieldBase = BS3CG1DST_XMM0_LO; + break; + + case BS3CG1ENC_MODRM_VqZx_WO_Nq: + pThis->pfnEncoder = Bs3Cg1EncodeNext_MODRM_Vsomething_Nsomething; + pThis->iRegOp = 0; + pThis->iRmOp = 1; + pThis->aOperands[0].cbOp = 8; + pThis->aOperands[1].cbOp = 8; + pThis->aOperands[0].enmLocation = BS3CG1OPLOC_CTX; + pThis->aOperands[1].enmLocation = BS3CG1OPLOC_CTX; + pThis->aOperands[0].idxFieldBase = BS3CG1DST_XMM0_LO_ZX; + pThis->aOperands[1].idxFieldBase = BS3CG1DST_MM0; + break; + + case BS3CG1ENC_MODRM_VsdZx_WO_Wsd: + case BS3CG1ENC_MODRM_VqZx_WO_Wq: + pThis->pfnEncoder = Bs3Cg1EncodeNext_MODRM_Vsomething_Wsomething_OR_ViceVersa; + pThis->iRegOp = 0; + pThis->iRmOp = 1; + pThis->aOperands[0].cbOp = 8; + pThis->aOperands[1].cbOp = 8; + pThis->aOperands[0].enmLocation = BS3CG1OPLOC_CTX; + pThis->aOperands[1].enmLocation = BS3CG1OPLOC_CTX; + pThis->aOperands[1].enmLocationReg = BS3CG1OPLOC_CTX; + pThis->aOperands[1].enmLocationMem = BS3CG1OPLOC_MEM; + pThis->aOperands[0].idxFieldBase = BS3CG1DST_XMM0_LO_ZX; + pThis->aOperands[1].idxFieldBase = BS3CG1DST_XMM0_LO; + break; + + case BS3CG1ENC_MODRM_Mb_RO: + pThis->pfnEncoder = Bs3Cg1EncodeNext_MODRM_Msomething; + pThis->iRmOp = 0; + pThis->aOperands[0].cbOp = 1; + pThis->aOperands[0].enmLocation = BS3CG1OPLOC_MEM; + pThis->aOperands[0].enmLocationMem = BS3CG1OPLOC_MEM; + break; + + case BS3CG1ENC_MODRM_Md_RO: + pThis->pfnEncoder = Bs3Cg1EncodeNext_MODRM_Msomething; + pThis->iRmOp = 0; + pThis->aOperands[0].cbOp = 4; + pThis->aOperands[0].enmLocation = BS3CG1OPLOC_MEM; + pThis->aOperands[0].enmLocationMem = BS3CG1OPLOC_MEM; + break; + + case BS3CG1ENC_MODRM_Md_WO: + pThis->pfnEncoder = Bs3Cg1EncodeNext_MODRM_Msomething; + pThis->iRmOp = 0; + pThis->aOperands[0].cbOp = 4; + pThis->aOperands[0].enmLocation = BS3CG1OPLOC_MEM_WO; + pThis->aOperands[0].enmLocationMem = BS3CG1OPLOC_MEM_WO; + break; + + case BS3CG1ENC_MODRM_Mdq_WO_Vdq: + pThis->pfnEncoder = Bs3Cg1EncodeNext_MODRM_Msomething_Vsomething_OR_ViceVersa; + pThis->iRmOp = 0; + pThis->iRegOp = 1; + pThis->aOperands[0].cbOp = 16; + pThis->aOperands[1].cbOp = 16; + pThis->aOperands[0].enmLocation = BS3CG1OPLOC_MEM_WO; + pThis->aOperands[1].enmLocation = BS3CG1OPLOC_CTX; + pThis->aOperands[1].idxFieldBase = BS3CG1DST_XMM0; + break; + + case BS3CG1ENC_MODRM_Mq_WO_Pq: + pThis->pfnEncoder = Bs3Cg1EncodeNext_MODRM_Msomething_Psomething; + pThis->iRmOp = 0; + pThis->iRegOp = 1; + pThis->aOperands[0].cbOp = 8; + pThis->aOperands[1].cbOp = 8; + pThis->aOperands[1].idxFieldBase = BS3CG1DST_MM0; + pThis->aOperands[0].enmLocation = BS3CG1OPLOC_MEM_WO; + pThis->aOperands[1].enmLocation = BS3CG1OPLOC_CTX; + break; + + case BS3CG1ENC_MODRM_Mq_WO_Vq: + case BS3CG1ENC_MODRM_Mq_WO_VqHi: + pThis->pfnEncoder = Bs3Cg1EncodeNext_MODRM_Msomething_Vsomething_OR_ViceVersa; + pThis->iRmOp = 0; + pThis->iRegOp = 1; + pThis->aOperands[0].cbOp = 8; + pThis->aOperands[1].cbOp = 8; + pThis->aOperands[0].enmLocation = BS3CG1OPLOC_MEM_WO; + pThis->aOperands[0].enmLocationMem = BS3CG1OPLOC_MEM_WO; + pThis->aOperands[1].enmLocation = BS3CG1OPLOC_CTX; + pThis->aOperands[1].idxFieldBase = pThis->enmEncoding == BS3CG1ENC_MODRM_Mq_WO_Vq + ? BS3CG1DST_XMM0_LO : BS3CG1DST_XMM0_HI; + break; + + case BS3CG1ENC_MODRM_Mps_WO_Vps: + case BS3CG1ENC_MODRM_Mpd_WO_Vpd: + pThis->pfnEncoder = Bs3Cg1EncodeNext_MODRM_Msomething_Vsomething_OR_ViceVersa; + pThis->iRmOp = 0; + pThis->iRegOp = 1; + pThis->aOperands[0].cbOp = 16; + pThis->aOperands[1].cbOp = 16; + pThis->aOperands[0].enmLocation = BS3CG1OPLOC_MEM_WO; + pThis->aOperands[1].enmLocation = BS3CG1OPLOC_CTX; + pThis->aOperands[1].idxFieldBase = BS3CG1DST_XMM0; + break; + + case BS3CG1ENC_FIXED: + pThis->pfnEncoder = Bs3Cg1EncodeNext_FIXED; + break; + + case BS3CG1ENC_FIXED_AL_Ib: + pThis->pfnEncoder = Bs3Cg1EncodeNext_FIXED_AL_Ib; + pThis->aOperands[0].cbOp = 1; + pThis->aOperands[1].cbOp = 1; + pThis->aOperands[0].enmLocation = BS3CG1OPLOC_CTX; + pThis->aOperands[1].enmLocation = BS3CG1OPLOC_IMM; + pThis->aOperands[0].idxField = BS3CG1DST_AL; + pThis->aOperands[1].idxField = BS3CG1DST_INVALID; + break; + + case BS3CG1ENC_FIXED_rAX_Iz: + pThis->pfnEncoder = Bs3Cg1EncodeNext_FIXED_rAX_Iz; + pThis->aOperands[0].cbOp = 2; + pThis->aOperands[1].cbOp = 2; + pThis->aOperands[0].enmLocation = BS3CG1OPLOC_CTX; + pThis->aOperands[1].enmLocation = BS3CG1OPLOC_IMM; + pThis->aOperands[0].idxField = BS3CG1DST_OZ_RAX; + pThis->aOperands[1].idxField = BS3CG1DST_INVALID; + break; + + /* Unused or invalid instructions mostly. */ + case BS3CG1ENC_MODRM_MOD_EQ_3: + pThis->pfnEncoder = Bs3Cg1EncodeNext_MODRM_MOD_EQ_3; + break; + case BS3CG1ENC_MODRM_MOD_NE_3: + pThis->pfnEncoder = Bs3Cg1EncodeNext_MODRM_MOD_NE_3; + break; + +#ifdef BS3CG1_WITH_VEX + + case BS3CG1ENC_VEX_MODRM_Vd_WO_Ed_WZ: + pThis->pfnEncoder = Bs3Cg1EncodeNext_VEX_MODRM_Vd_WO_Ed_WZ; + pThis->iRegOp = 0; + pThis->iRmOp = 1; + pThis->aOperands[0].cbOp = 4; + pThis->aOperands[1].cbOp = 4; + pThis->aOperands[0].idxFieldBase = BS3CG1DST_XMM0_DW0_ZX; + pThis->aOperands[1].idxFieldBase = BS3CG1DST_EAX; + pThis->aOperands[0].enmLocation = BS3CG1OPLOC_CTX_ZX_VLMAX; + pThis->aOperands[1].enmLocation = BS3CG1OPLOC_CTX; + pThis->aOperands[1].enmLocationReg = BS3CG1OPLOC_CTX; + pThis->aOperands[1].enmLocationMem = BS3CG1OPLOC_MEM; + break; + + case BS3CG1ENC_VEX_MODRM_Vq_WO_Eq_WNZ: + pThis->pfnEncoder = Bs3Cg1EncodeNext_VEX_MODRM_Vq_WO_Eq_WNZ; + pThis->iRegOp = 0; + pThis->iRmOp = 1; + pThis->aOperands[0].cbOp = 8; + pThis->aOperands[1].cbOp = 8; + pThis->aOperands[0].idxFieldBase = BS3CG1DST_XMM0_LO_ZX; + pThis->aOperands[1].idxFieldBase = BS3CG1DST_RAX; + pThis->aOperands[0].enmLocation = BS3CG1OPLOC_CTX_ZX_VLMAX; + pThis->aOperands[1].enmLocation = BS3CG1OPLOC_CTX; + pThis->aOperands[1].enmLocationReg = BS3CG1OPLOC_CTX; + pThis->aOperands[1].enmLocationMem = BS3CG1OPLOC_MEM; + break; + + case BS3CG1ENC_VEX_MODRM_Vps_WO_Wps: + case BS3CG1ENC_VEX_MODRM_Vpd_WO_Wpd: + pThis->pfnEncoder = Bs3Cg1EncodeNext_VEX_MODRM_WsomethingWO_Vsomething_Wip_OR_ViceVersa; + pThis->iRegOp = 0; + pThis->iRmOp = 1; + pThis->aOperands[0].cbOp = 16; + pThis->aOperands[1].cbOp = 16; + pThis->aOperands[0].enmLocation = BS3CG1OPLOC_CTX_ZX_VLMAX; + pThis->aOperands[1].enmLocation = BS3CG1OPLOC_CTX; + pThis->aOperands[1].enmLocationReg = BS3CG1OPLOC_CTX; + pThis->aOperands[1].enmLocationMem = BS3CG1OPLOC_MEM; + pThis->aOperands[0].idxFieldBase = BS3CG1DST_XMM0; + pThis->aOperands[1].idxFieldBase = BS3CG1DST_XMM0; + break; + + case BS3CG1ENC_VEX_MODRM_VssZx_WO_Md: + pThis->pfnEncoder = Bs3Cg1EncodeNext_VEX_MODRM_VsomethingWO_Msomething_Wip_Lig_OR_ViceVersa; + pThis->iRmOp = 1; + pThis->iRegOp = 0; + pThis->aOperands[0].cbOp = 4; + pThis->aOperands[1].cbOp = 4; + pThis->aOperands[0].enmLocation = BS3CG1OPLOC_CTX_ZX_VLMAX; + pThis->aOperands[1].enmLocation = BS3CG1OPLOC_MEM; + pThis->aOperands[0].idxFieldBase = BS3CG1DST_XMM0_DW0; + pThis->aOperands[1].idxFieldBase = BS3CG1DST_INVALID; + break; + + case BS3CG1ENC_VEX_MODRM_Vss_WO_HssHi_Uss: + pThis->pfnEncoder = Bs3Cg1EncodeNext_VEX_MODRM_VsomethingWO_Hsomething_Usomething_Lip_Wip_OR_ViceVersa; + pThis->iRegOp = 0; + pThis->iRmOp = 2; + pThis->aOperands[0].cbOp = 16; + pThis->aOperands[1].cbOp = 12; + pThis->aOperands[2].cbOp = 4; + pThis->aOperands[0].enmLocation = BS3CG1OPLOC_CTX_ZX_VLMAX; + pThis->aOperands[1].enmLocation = BS3CG1OPLOC_CTX; + pThis->aOperands[2].enmLocation = BS3CG1OPLOC_CTX; + pThis->aOperands[0].idxFieldBase = BS3CG1DST_XMM0; + pThis->aOperands[1].idxFieldBase = BS3CG1DST_XMM0_HI96; + pThis->aOperands[2].idxFieldBase = BS3CG1DST_XMM0_DW0; + break; + + case BS3CG1ENC_VEX_MODRM_VsdZx_WO_Mq: + pThis->pfnEncoder = Bs3Cg1EncodeNext_VEX_MODRM_VsomethingWO_Msomething_Wip_Lig_OR_ViceVersa; + pThis->iRmOp = 1; + pThis->iRegOp = 0; + pThis->aOperands[0].cbOp = 8; + pThis->aOperands[1].cbOp = 8; + pThis->aOperands[0].enmLocation = BS3CG1OPLOC_CTX_ZX_VLMAX; + pThis->aOperands[1].enmLocation = BS3CG1OPLOC_MEM; + pThis->aOperands[0].idxFieldBase = BS3CG1DST_XMM0_LO; + pThis->aOperands[1].idxFieldBase = BS3CG1DST_INVALID; + break; + + case BS3CG1ENC_VEX_MODRM_Vx_WO_Mx_L0: + BS3_ASSERT(!(pThis->fFlags & BS3CG1INSTR_F_VEX_L_ZERO)); + pThis->pfnEncoder = Bs3Cg1EncodeNext_VEX_MODRM_VsomethingWO_Msomething_Wip_L0_OR_ViceVersa; + pThis->iRegOp = 0; + pThis->iRmOp = 1; + pThis->aOperands[0].cbOp = 16; + pThis->aOperands[1].cbOp = 16; + pThis->aOperands[0].enmLocation = BS3CG1OPLOC_CTX_ZX_VLMAX; + pThis->aOperands[1].enmLocation = BS3CG1OPLOC_MEM; + pThis->aOperands[0].idxFieldBase = BS3CG1DST_XMM0; + break; + + case BS3CG1ENC_VEX_MODRM_Vx_WO_Mx_L1: + pThis->pfnEncoder = Bs3Cg1EncodeNext_VEX_MODRM_VsomethingWO_Msomething_Wip_L1_OR_ViceVersa; + pThis->iRegOp = 0; + pThis->iRmOp = 1; + pThis->aOperands[0].cbOp = 32; + pThis->aOperands[1].cbOp = 32; + pThis->aOperands[0].enmLocation = BS3CG1OPLOC_CTX_ZX_VLMAX; + pThis->aOperands[1].enmLocation = BS3CG1OPLOC_MEM; + pThis->aOperands[0].idxFieldBase = BS3CG1DST_YMM0; + break; + + case BS3CG1ENC_VEX_MODRM_Vsd_WO_HsdHi_Usd: + pThis->pfnEncoder = Bs3Cg1EncodeNext_VEX_MODRM_VsomethingWO_Hsomething_Usomething_Lip_Wip_OR_ViceVersa; + pThis->iRegOp = 0; + pThis->iRmOp = 2; + pThis->aOperands[0].cbOp = 16; + pThis->aOperands[1].cbOp = 8; + pThis->aOperands[2].cbOp = 8; + pThis->aOperands[0].enmLocation = BS3CG1OPLOC_CTX_ZX_VLMAX; + pThis->aOperands[1].enmLocation = BS3CG1OPLOC_CTX; + pThis->aOperands[2].enmLocation = BS3CG1OPLOC_CTX; + pThis->aOperands[0].idxFieldBase = BS3CG1DST_XMM0; + pThis->aOperands[1].idxFieldBase = BS3CG1DST_XMM0_HI; + pThis->aOperands[2].idxFieldBase = BS3CG1DST_XMM0_LO; + break; + + case BS3CG1ENC_VEX_MODRM_Vq_WO_HqHi_UqHi: + pThis->pfnEncoder = Bs3Cg1EncodeNext_VEX_MODRM_VsomethingWO_HdqCsomething_Usomething_Wip_OR_ViceVersa; + pThis->iRegOp = 0; + pThis->iRmOp = 2; + pThis->aOperands[0].cbOp = 16; + pThis->aOperands[1].cbOp = 8; + pThis->aOperands[2].cbOp = 8; + pThis->aOperands[0].enmLocation = BS3CG1OPLOC_CTX_ZX_VLMAX; + pThis->aOperands[1].enmLocation = BS3CG1OPLOC_CTX; + pThis->aOperands[2].enmLocation = BS3CG1OPLOC_CTX; + pThis->aOperands[0].idxFieldBase = BS3CG1DST_XMM0; + pThis->aOperands[1].idxFieldBase = BS3CG1DST_XMM0_HI; + pThis->aOperands[2].idxFieldBase = BS3CG1DST_XMM0_HI; + break; + + case BS3CG1ENC_VEX_MODRM_Vq_WO_HqHi_Mq: + pThis->pfnEncoder = Bs3Cg1EncodeNext_VEX_MODRM_VsomethingWO_Hsomething_Msomething_Wip_OR_ViceVersa; + pThis->iRegOp = 0; + pThis->iRmOp = 2; + pThis->aOperands[0].cbOp = 16; + pThis->aOperands[1].cbOp = 8; + pThis->aOperands[2].cbOp = 8; + pThis->aOperands[0].enmLocation = BS3CG1OPLOC_CTX_ZX_VLMAX; + pThis->aOperands[1].enmLocation = BS3CG1OPLOC_CTX; + pThis->aOperands[2].enmLocation = BS3CG1OPLOC_MEM; + pThis->aOperands[0].idxFieldBase = BS3CG1DST_XMM0; + pThis->aOperands[1].idxFieldBase = BS3CG1DST_XMM0_HI; + pThis->aOperands[2].idxFieldBase = BS3CG1DST_INVALID; + break; + + case BS3CG1ENC_VEX_MODRM_Vq_WO_Wq: + BS3_ASSERT(pThis->fFlags & BS3CG1INSTR_F_VEX_L_ZERO); + pThis->pfnEncoder = Bs3Cg1EncodeNext_VEX_MODRM_WsomethingWO_Vsomething_Wip_Lmbz_OR_ViceVersa; + pThis->iRegOp = 0; + pThis->iRmOp = 1; + pThis->aOperands[0].cbOp = 8; + pThis->aOperands[1].cbOp = 8; + pThis->aOperands[0].enmLocation = BS3CG1OPLOC_CTX_ZX_VLMAX; + pThis->aOperands[1].enmLocation = BS3CG1OPLOC_CTX; + pThis->aOperands[1].enmLocationReg = BS3CG1OPLOC_CTX; + pThis->aOperands[1].enmLocationMem = BS3CG1OPLOC_MEM; + pThis->aOperands[0].idxFieldBase = BS3CG1DST_XMM0_LO; + pThis->aOperands[1].idxFieldBase = BS3CG1DST_XMM0_LO; + break; + + case BS3CG1ENC_VEX_MODRM_Vx_WO_Wx: + pThis->pfnEncoder = Bs3Cg1EncodeNext_VEX_MODRM_WsomethingWO_Vsomething_Wip_OR_ViceVersa; + pThis->iRegOp = 0; + pThis->iRmOp = 1; + pThis->aOperands[0].cbOp = 16; + pThis->aOperands[1].cbOp = 16; + pThis->aOperands[0].enmLocation = BS3CG1OPLOC_CTX_ZX_VLMAX; + pThis->aOperands[1].enmLocation = BS3CG1OPLOC_CTX; + pThis->aOperands[1].enmLocationReg = BS3CG1OPLOC_CTX; + pThis->aOperands[1].enmLocationMem = BS3CG1OPLOC_MEM; + pThis->aOperands[0].idxFieldBase = BS3CG1DST_XMM0; + pThis->aOperands[1].idxFieldBase = BS3CG1DST_XMM0; + break; + + case BS3CG1ENC_VEX_MODRM_Ed_WO_Vd_WZ: + pThis->pfnEncoder = Bs3Cg1EncodeNext_VEX_MODRM_Vd_WO_Ed_WZ; + pThis->iRmOp = 0; + pThis->iRegOp = 1; + pThis->aOperands[0].cbOp = 4; + pThis->aOperands[1].cbOp = 4; + pThis->aOperands[0].idxFieldBase = BS3CG1DST_EAX; + pThis->aOperands[1].idxFieldBase = BS3CG1DST_XMM0_DW0_ZX; + pThis->aOperands[0].enmLocation = BS3CG1OPLOC_CTX; + pThis->aOperands[0].enmLocationReg = BS3CG1OPLOC_CTX; + pThis->aOperands[0].enmLocationMem = BS3CG1OPLOC_MEM_WO; + pThis->aOperands[1].enmLocation = BS3CG1OPLOC_CTX; + break; + + case BS3CG1ENC_VEX_MODRM_Eq_WO_Vq_WNZ: + pThis->pfnEncoder = Bs3Cg1EncodeNext_VEX_MODRM_Vq_WO_Eq_WNZ; + pThis->iRmOp = 0; + pThis->iRegOp = 1; + pThis->aOperands[0].cbOp = 8; + pThis->aOperands[1].cbOp = 8; + pThis->aOperands[0].idxFieldBase = BS3CG1DST_RAX; + pThis->aOperands[1].idxFieldBase = BS3CG1DST_XMM0_LO_ZX; + pThis->aOperands[0].enmLocation = BS3CG1OPLOC_CTX; + pThis->aOperands[0].enmLocationReg = BS3CG1OPLOC_CTX; + pThis->aOperands[0].enmLocationMem = BS3CG1OPLOC_MEM_WO; + pThis->aOperands[1].enmLocation = BS3CG1OPLOC_CTX; + break; + + case BS3CG1ENC_VEX_MODRM_Md_WO: + pThis->pfnEncoder = Bs3Cg1EncodeNext_VEX_MODRM_Md_WO; + pThis->iRmOp = 0; + pThis->aOperands[0].cbOp = 4; + pThis->aOperands[0].enmLocation = BS3CG1OPLOC_MEM_WO; + pThis->aOperands[0].enmLocationMem = BS3CG1OPLOC_MEM_WO; + break; + + case BS3CG1ENC_VEX_MODRM_Md_WO_Vss: + pThis->pfnEncoder = Bs3Cg1EncodeNext_VEX_MODRM_VsomethingWO_Msomething_Wip_Lig_OR_ViceVersa; + pThis->iRmOp = 0; + pThis->iRegOp = 1; + pThis->aOperands[0].cbOp = 4; + pThis->aOperands[1].cbOp = 4; + pThis->aOperands[0].enmLocation = BS3CG1OPLOC_MEM_WO; + pThis->aOperands[1].enmLocation = BS3CG1OPLOC_CTX; + pThis->aOperands[0].idxFieldBase = BS3CG1DST_INVALID; + pThis->aOperands[1].idxFieldBase = BS3CG1DST_XMM0_DW0; + break; + + case BS3CG1ENC_VEX_MODRM_Mq_WO_Vq: + BS3_ASSERT(pThis->fFlags & (BS3CG1INSTR_F_VEX_L_ZERO | BS3CG1INSTR_F_VEX_L_IGNORED)); + pThis->pfnEncoder = pThis->fFlags & BS3CG1INSTR_F_VEX_L_ZERO + ? Bs3Cg1EncodeNext_VEX_MODRM_VsomethingWO_Msomething_Wip_Lmbz_OR_ViceVersa + : Bs3Cg1EncodeNext_VEX_MODRM_VsomethingWO_Msomething_Wip_Lig_OR_ViceVersa; + pThis->iRmOp = 0; + pThis->iRegOp = 1; + pThis->aOperands[0].cbOp = 8; + pThis->aOperands[1].cbOp = 8; + pThis->aOperands[0].enmLocation = BS3CG1OPLOC_MEM_WO; + pThis->aOperands[1].enmLocation = BS3CG1OPLOC_CTX; + pThis->aOperands[1].idxFieldBase = BS3CG1DST_XMM0_LO; + break; + + case BS3CG1ENC_VEX_MODRM_Mq_WO_Vsd: + pThis->pfnEncoder = Bs3Cg1EncodeNext_VEX_MODRM_VsomethingWO_Msomething_Wip_Lig_OR_ViceVersa; + pThis->iRmOp = 0; + pThis->iRegOp = 1; + pThis->aOperands[0].cbOp = 8; + pThis->aOperands[1].cbOp = 8; + pThis->aOperands[0].enmLocation = BS3CG1OPLOC_MEM_WO; + pThis->aOperands[1].enmLocation = BS3CG1OPLOC_CTX; + pThis->aOperands[0].idxFieldBase = BS3CG1DST_INVALID; + pThis->aOperands[1].idxFieldBase = BS3CG1DST_XMM0_LO; + break; + + case BS3CG1ENC_VEX_MODRM_Mps_WO_Vps: + case BS3CG1ENC_VEX_MODRM_Mpd_WO_Vpd: + case BS3CG1ENC_VEX_MODRM_Mx_WO_Vx: + pThis->pfnEncoder = Bs3Cg1EncodeNext_VEX_MODRM_VsomethingWO_Msomething_Wip_OR_ViceVersa; + pThis->iRmOp = 0; + pThis->iRegOp = 1; + pThis->aOperands[0].cbOp = 16; + pThis->aOperands[1].cbOp = 16; + pThis->aOperands[0].enmLocation = BS3CG1OPLOC_MEM_WO; + pThis->aOperands[1].enmLocation = BS3CG1OPLOC_CTX; + pThis->aOperands[1].idxFieldBase = BS3CG1DST_XMM0; + break; + + case BS3CG1ENC_VEX_MODRM_Uss_WO_HssHi_Vss: + pThis->pfnEncoder = Bs3Cg1EncodeNext_VEX_MODRM_VsomethingWO_Hsomething_Usomething_Lip_Wip_OR_ViceVersa; + pThis->iRegOp = 2; + pThis->iRmOp = 0; + pThis->aOperands[0].cbOp = 16; + pThis->aOperands[1].cbOp = 96; + pThis->aOperands[2].cbOp = 4; + pThis->aOperands[0].enmLocation = BS3CG1OPLOC_CTX_ZX_VLMAX; + pThis->aOperands[1].enmLocation = BS3CG1OPLOC_CTX; + pThis->aOperands[2].enmLocation = BS3CG1OPLOC_CTX; + pThis->aOperands[0].idxFieldBase = BS3CG1DST_XMM0; + pThis->aOperands[1].idxFieldBase = BS3CG1DST_XMM0_HI96; + pThis->aOperands[2].idxFieldBase = BS3CG1DST_XMM0_DW0; + break; + + case BS3CG1ENC_VEX_MODRM_Usd_WO_HsdHi_Vsd: + pThis->pfnEncoder = Bs3Cg1EncodeNext_VEX_MODRM_VsomethingWO_Hsomething_Usomething_Lip_Wip_OR_ViceVersa; + pThis->iRegOp = 2; + pThis->iRmOp = 0; + pThis->aOperands[0].cbOp = 16; + pThis->aOperands[1].cbOp = 8; + pThis->aOperands[2].cbOp = 8; + pThis->aOperands[0].enmLocation = BS3CG1OPLOC_CTX_ZX_VLMAX; + pThis->aOperands[1].enmLocation = BS3CG1OPLOC_CTX; + pThis->aOperands[2].enmLocation = BS3CG1OPLOC_CTX; + pThis->aOperands[0].idxFieldBase = BS3CG1DST_XMM0; + pThis->aOperands[1].idxFieldBase = BS3CG1DST_XMM0_HI; + pThis->aOperands[2].idxFieldBase = BS3CG1DST_XMM0_LO; + break; + + case BS3CG1ENC_VEX_MODRM_Wps_WO_Vps: + case BS3CG1ENC_VEX_MODRM_Wpd_WO_Vpd: + pThis->pfnEncoder = Bs3Cg1EncodeNext_VEX_MODRM_WsomethingWO_Vsomething_Wip_OR_ViceVersa; + pThis->iRmOp = 0; + pThis->iRegOp = 1; + pThis->aOperands[0].cbOp = 16; + pThis->aOperands[1].cbOp = 16; + pThis->aOperands[0].enmLocation = BS3CG1OPLOC_CTX_ZX_VLMAX; + pThis->aOperands[0].enmLocationReg = BS3CG1OPLOC_CTX_ZX_VLMAX; + pThis->aOperands[0].enmLocationMem = BS3CG1OPLOC_MEM_WO; + pThis->aOperands[1].enmLocation = BS3CG1OPLOC_CTX; + pThis->aOperands[0].idxFieldBase = BS3CG1DST_XMM0; + pThis->aOperands[1].idxFieldBase = BS3CG1DST_XMM0; + break; + + case BS3CG1ENC_VEX_MODRM_Wq_WO_Vq: + BS3_ASSERT(pThis->fFlags & BS3CG1INSTR_F_VEX_L_ZERO); + pThis->pfnEncoder = Bs3Cg1EncodeNext_VEX_MODRM_WsomethingWO_Vsomething_Wip_Lmbz_OR_ViceVersa; + pThis->iRegOp = 1; + pThis->iRmOp = 0; + pThis->aOperands[0].cbOp = 8; + pThis->aOperands[1].cbOp = 8; + pThis->aOperands[0].enmLocation = BS3CG1OPLOC_CTX_ZX_VLMAX; + pThis->aOperands[0].enmLocationReg = BS3CG1OPLOC_CTX_ZX_VLMAX; + pThis->aOperands[0].enmLocationMem = BS3CG1OPLOC_MEM_WO; + pThis->aOperands[1].enmLocation = BS3CG1OPLOC_CTX; + pThis->aOperands[0].idxFieldBase = BS3CG1DST_XMM0_LO; + pThis->aOperands[1].idxFieldBase = BS3CG1DST_XMM0_LO; + break; + + case BS3CG1ENC_VEX_MODRM_Wx_WO_Vx: + pThis->pfnEncoder = Bs3Cg1EncodeNext_VEX_MODRM_WsomethingWO_Vsomething_Wip_OR_ViceVersa; + pThis->iRmOp = 0; + pThis->iRegOp = 1; + pThis->aOperands[0].cbOp = 16; + pThis->aOperands[1].cbOp = 16; + pThis->aOperands[0].enmLocation = BS3CG1OPLOC_CTX_ZX_VLMAX; + pThis->aOperands[0].enmLocationReg = BS3CG1OPLOC_CTX_ZX_VLMAX; + pThis->aOperands[0].enmLocationMem = BS3CG1OPLOC_MEM_WO; + pThis->aOperands[1].enmLocation = BS3CG1OPLOC_CTX; + pThis->aOperands[0].idxFieldBase = BS3CG1DST_XMM0; + pThis->aOperands[1].idxFieldBase = BS3CG1DST_XMM0; + break; + + + /* Unused or invalid instructions mostly. */ + //case BS3CG1ENC_VEX_FIXED: + // pThis->pfnEncoder = Bs3Cg1EncodeNext_VEX_FIXED; + // break; + case BS3CG1ENC_VEX_MODRM_MOD_EQ_3: + pThis->pfnEncoder = Bs3Cg1EncodeNext_VEX_MODRM_MOD_EQ_3; + break; + case BS3CG1ENC_VEX_MODRM_MOD_NE_3: + pThis->pfnEncoder = Bs3Cg1EncodeNext_VEX_MODRM_MOD_NE_3; + break; + case BS3CG1ENC_VEX_MODRM: + pThis->pfnEncoder = Bs3Cg1EncodeNext_VEX_MODRM; + break; + +#endif /* BS3CG1_WITH_VEX */ + + default: + Bs3TestFailedF("Invalid/unimplemented enmEncoding for instruction #%RU32 (%.*s): %d", + pThis->iInstr, pThis->cchMnemonic, pThis->pchMnemonic, pThis->enmEncoding); + return false; + } + return true; +} + + +/** + * Calculates the appropriate non-intel invalid instruction encoding. + * + * @returns the encoding to use instead. + * @param enmEncoding The intel invalid instruction encoding. + */ +static BS3CG1ENC Bs3Cg1CalcNoneIntelInvalidEncoding(BS3CG1ENC enmEncoding) +{ + switch (enmEncoding) + { + case BS3CG1ENC_MODRM_Gb_Eb: + case BS3CG1ENC_MODRM_Gv_RO_Ma: + case BS3CG1ENC_FIXED: + return BS3CG1ENC_FIXED; + default: + Bs3TestFailedF("Bs3Cg1CalcNoneIntelInvalidEncoding: Unsupported encoding: %d\n", enmEncoding); + return BS3CG1ENC_FIXED; + } +} + + +/** + * Sets cbOpDefault, cbOpOvrd66 and cbOpOvrdRexW. + * + * @param pThis The state. + * @param bMode The mode (only code part is used). + */ +static void Bs3Cg1SetOpSizes(PBS3CG1STATE pThis, uint8_t bMode) +{ + if (BS3_MODE_IS_16BIT_CODE(bMode)) + { + pThis->cbOpDefault = 2; + pThis->cbOpOvrd66 = 4; + pThis->cbOpOvrdRexW = 0; + } + else if (BS3_MODE_IS_32BIT_CODE(bMode)) + { + pThis->cbOpDefault = 4; + pThis->cbOpOvrd66 = 2; + pThis->cbOpOvrdRexW = 0; + } + else + { + pThis->cbOpDefault = 4; + pThis->cbOpOvrd66 = 2; + pThis->cbOpOvrdRexW = 8; + } +} + + +/** + * Sets up SSE and maybe AVX. + * + * @returns true (if successful, false if not and the SSE instructions ends up + * being invalid). + * @param pThis The state. + */ +static bool BS3_NEAR_CODE Bs3Cg3SetupSseAndAvx(PBS3CG1STATE pThis) +{ + if (!pThis->fWorkExtCtx) + { + unsigned i; + uint32_t cr0 = ASMGetCR0(); + uint32_t cr4 = ASMGetCR4(); + + cr0 &= ~(X86_CR0_TS | X86_CR0_MP | X86_CR0_EM); + cr0 |= X86_CR0_NE; + ASMSetCR0(cr0); + if (pThis->pExtCtx->enmMethod == BS3EXTCTXMETHOD_XSAVE) + { + cr4 |= X86_CR4_OSFXSR | X86_CR4_OSXMMEEXCPT | X86_CR4_OSXSAVE; + ASMSetCR4(cr4); + ASMSetXcr0(pThis->pExtCtx->fXcr0Nominal); + } + else + { + cr4 |= X86_CR4_OSFXSR | X86_CR4_OSXMMEEXCPT; + ASMSetCR4(cr4); + } + + for (i = 0; i < RT_ELEMENTS(pThis->aInitialCtxs); i++) + { + pThis->aInitialCtxs[i].cr0.u32 = cr0; + pThis->aInitialCtxs[i].cr4.u32 = cr4; + } + pThis->fWorkExtCtx = true; + } + + return true; +} + + +/** + * Next CPU configuration to test the current instruction in. + * + * This is for testing FPU, SSE and AVX instructions with the various lazy state + * load and enable bits in different configurations to ensure we're getting the + * right response. + * + * This also cleans up the CPU and test driver state. + * + * @returns true if we're to do another round, false if we're done. + * @param pThis The state. + * @param iCpuSetup The current CPU setup number. + * @param pfInvalidInstr Where to indicate whether the setup causes an + * invalid instruction or not. This is also used as + * input to avoid unnecessary CPUID work. + */ +static bool BS3_NEAR_CODE Bs3Cg1CpuSetupNext(PBS3CG1STATE pThis, unsigned iCpuSetup, bool BS3_FAR *pfInvalidInstr) +{ + if ( (pThis->fFlags & BS3CG1INSTR_F_INVALID_64BIT) + && BS3CG1_IS_64BIT_TARGET(pThis)) + return false; + + switch (pThis->enmCpuTest) + { + case BS3CG1CPU_ANY: + case BS3CG1CPU_GE_80186: + case BS3CG1CPU_GE_80286: + case BS3CG1CPU_GE_80386: + case BS3CG1CPU_GE_80486: + case BS3CG1CPU_GE_Pentium: + case BS3CG1CPU_CLFSH: + case BS3CG1CPU_CLFLUSHOPT: + return false; + + case BS3CG1CPU_MMX: + return false; + + case BS3CG1CPU_SSE: + case BS3CG1CPU_SSE2: + case BS3CG1CPU_SSE3: + case BS3CG1CPU_SSE4_1: + case BS3CG1CPU_AVX: + case BS3CG1CPU_AVX2: + if (iCpuSetup > 0 || *pfInvalidInstr) + { + /** @todo do more configs here. */ + pThis->fWorkExtCtx = false; + ASMSetCR0(ASMGetCR0() | X86_CR0_EM | X86_CR0_MP); + ASMSetCR4(ASMGetCR4() & ~(X86_CR4_OSFXSR | X86_CR4_OSXMMEEXCPT | X86_CR4_OSXSAVE)); + return false; + } + return false; + + default: + Bs3TestFailedF("Invalid enmCpuTest value: %d", pThis->enmCpuTest); + return false; + } +} + + +/** + * Check if the instruction is supported by the CPU, possibly making state + * adjustments to enable support for it. + * + * @returns true if supported, false if not. + * @param pThis The state. + */ +static bool BS3_NEAR_CODE Bs3Cg1CpuSetupFirst(PBS3CG1STATE pThis) +{ + uint32_t fEax; + uint32_t fEbx; + uint32_t fEcx; + uint32_t fEdx; + + if ( (pThis->fFlags & BS3CG1INSTR_F_INVALID_64BIT) + && BS3CG1_IS_64BIT_TARGET(pThis)) + return false; + + switch (pThis->enmCpuTest) + { + case BS3CG1CPU_ANY: + return true; + + case BS3CG1CPU_GE_80186: + if ((g_uBs3CpuDetected & BS3CPU_TYPE_MASK) >= BS3CPU_80186) + return true; + return false; + + case BS3CG1CPU_GE_80286: + if ((g_uBs3CpuDetected & BS3CPU_TYPE_MASK) >= BS3CPU_80286) + return true; + return false; + + case BS3CG1CPU_GE_80386: + if ((g_uBs3CpuDetected & BS3CPU_TYPE_MASK) >= BS3CPU_80386) + return true; + return false; + + case BS3CG1CPU_GE_80486: + if ((g_uBs3CpuDetected & BS3CPU_TYPE_MASK) >= BS3CPU_80486) + return true; + return false; + + case BS3CG1CPU_GE_Pentium: + if ((g_uBs3CpuDetected & BS3CPU_TYPE_MASK) >= BS3CPU_Pentium) + return true; + return false; + + case BS3CG1CPU_MMX: + if (g_uBs3CpuDetected & BS3CPU_F_CPUID) + { + ASMCpuIdExSlow(1, 0, 0, 0, NULL, NULL, NULL, &fEdx); + if (fEdx & X86_CPUID_FEATURE_EDX_MMX) + return Bs3Cg3SetupSseAndAvx(pThis); /** @todo only do FNSAVE/FXSAVE here? */ + } + return false; + + case BS3CG1CPU_SSE: + case BS3CG1CPU_SSE2: + case BS3CG1CPU_SSE3: + case BS3CG1CPU_SSE4_1: + case BS3CG1CPU_AVX: + if (g_uBs3CpuDetected & BS3CPU_F_CPUID) + { + ASMCpuIdExSlow(1, 0, 0, 0, NULL, NULL, &fEcx, &fEdx); + switch (pThis->enmCpuTest) + { + case BS3CG1CPU_SSE: + if (fEdx & X86_CPUID_FEATURE_EDX_SSE) + return Bs3Cg3SetupSseAndAvx(pThis); + return false; + case BS3CG1CPU_SSE2: + if (fEdx & X86_CPUID_FEATURE_EDX_SSE2) + return Bs3Cg3SetupSseAndAvx(pThis); + return false; + case BS3CG1CPU_SSE3: + if (fEcx & X86_CPUID_FEATURE_ECX_SSE3) + return Bs3Cg3SetupSseAndAvx(pThis); + return false; + case BS3CG1CPU_SSE4_1: + if (fEcx & X86_CPUID_FEATURE_ECX_SSE4_1) + return Bs3Cg3SetupSseAndAvx(pThis); + return false; + case BS3CG1CPU_AVX: + if (fEcx & X86_CPUID_FEATURE_ECX_AVX) + return Bs3Cg3SetupSseAndAvx(pThis) && !BS3_MODE_IS_RM_OR_V86(pThis->bMode); + return false; + default: BS3_ASSERT(0); /* impossible */ + } + } + return false; + + case BS3CG1CPU_AVX2: + if (g_uBs3CpuDetected & BS3CPU_F_CPUID) + { + ASMCpuIdExSlow(7, 0, 0/*leaf*/, 0, &fEax, &fEbx, &fEcx, &fEdx); + switch (pThis->enmCpuTest) + { + case BS3CG1CPU_AVX2: + if (fEbx & X86_CPUID_STEXT_FEATURE_EBX_AVX2) + return Bs3Cg3SetupSseAndAvx(pThis) && !BS3_MODE_IS_RM_OR_V86(pThis->bMode); + return false; + default: BS3_ASSERT(0); return false; /* impossible */ + } + } + return false; + + case BS3CG1CPU_CLFSH: + if (g_uBs3CpuDetected & BS3CPU_F_CPUID) + { + ASMCpuIdExSlow(1, 0, 0, 0, NULL, NULL, NULL, &fEdx); + if (fEdx & X86_CPUID_FEATURE_EDX_CLFSH) + return true; + } + return false; + + case BS3CG1CPU_CLFLUSHOPT: + if (g_uBs3CpuDetected & BS3CPU_F_CPUID) + { + ASMCpuIdExSlow(7, 0, 0/*leaf*/, 0, NULL, &fEbx, NULL, NULL); + if (fEbx & X86_CPUID_STEXT_FEATURE_EBX_CLFLUSHOPT) + return true; + } + return false; + + default: + Bs3TestFailedF("Invalid enmCpuTest value: %d", pThis->enmCpuTest); + return false; + } +} + + + +/** + * Checks the preconditions for a test. + * + * @returns true if the test be executed, false if not. + * @param pThis The state. + * @param pHdr The test header. + */ +static bool BS3_NEAR_CODE Bs3Cg1RunSelector(PBS3CG1STATE pThis, PCBS3CG1TESTHDR pHdr) +{ + + uint8_t const BS3_FAR *pbCode = (uint8_t const BS3_FAR *)(pHdr + 1); + unsigned cbLeft = pHdr->cbSelector; + while (cbLeft-- > 0) + { + switch (*pbCode++) + { +#define CASE_PRED(a_Pred, a_Expr) \ + case ((a_Pred) << BS3CG1SEL_OP_KIND_MASK) | BS3CG1SEL_OP_IS_TRUE: \ + if (!(a_Expr)) return false; \ + break; \ + case ((a_Pred) << BS3CG1SEL_OP_KIND_MASK) | BS3CG1SEL_OP_IS_FALSE: \ + if (a_Expr) return false; \ + break + CASE_PRED(BS3CG1PRED_SIZE_O16, pThis->cbOperand == 2); + CASE_PRED(BS3CG1PRED_SIZE_O32, pThis->cbOperand == 4); + CASE_PRED(BS3CG1PRED_SIZE_O64, pThis->cbOperand == 8); + CASE_PRED(BS3CG1PRED_VEXL_0, pThis->uVexL == 0); + CASE_PRED(BS3CG1PRED_VEXL_1, pThis->uVexL == 1); + CASE_PRED(BS3CG1PRED_RING_0, pThis->uCpl == 0); + CASE_PRED(BS3CG1PRED_RING_1, pThis->uCpl == 1); + CASE_PRED(BS3CG1PRED_RING_2, pThis->uCpl == 2); + CASE_PRED(BS3CG1PRED_RING_3, pThis->uCpl == 3); + CASE_PRED(BS3CG1PRED_RING_0_THRU_2, pThis->uCpl <= 2); + CASE_PRED(BS3CG1PRED_RING_1_THRU_3, pThis->uCpl >= 1); + CASE_PRED(BS3CG1PRED_CODE_64BIT, BS3CG1_IS_64BIT_TARGET(pThis)); + CASE_PRED(BS3CG1PRED_CODE_32BIT, BS3_MODE_IS_32BIT_CODE(pThis->bMode)); + CASE_PRED(BS3CG1PRED_CODE_16BIT, BS3_MODE_IS_16BIT_CODE(pThis->bMode)); + CASE_PRED(BS3CG1PRED_MODE_REAL, BS3_MODE_IS_RM_SYS(pThis->bMode)); + CASE_PRED(BS3CG1PRED_MODE_PROT, BS3_MODE_IS_PM_SYS(pThis->bMode)); + CASE_PRED(BS3CG1PRED_MODE_LONG, BS3_MODE_IS_64BIT_SYS(pThis->bMode)); + CASE_PRED(BS3CG1PRED_MODE_SMM, false); + CASE_PRED(BS3CG1PRED_MODE_VMX, false); + CASE_PRED(BS3CG1PRED_MODE_SVM, false); + CASE_PRED(BS3CG1PRED_PAGING_ON, BS3_MODE_IS_PAGED(pThis->bMode)); + CASE_PRED(BS3CG1PRED_PAGING_OFF, !BS3_MODE_IS_PAGED(pThis->bMode)); + CASE_PRED(BS3CG1PRED_VENDOR_AMD, pThis->bCpuVendor == BS3CPUVENDOR_AMD); + CASE_PRED(BS3CG1PRED_VENDOR_INTEL, pThis->bCpuVendor == BS3CPUVENDOR_INTEL); + CASE_PRED(BS3CG1PRED_VENDOR_VIA, pThis->bCpuVendor == BS3CPUVENDOR_VIA); + CASE_PRED(BS3CG1PRED_VENDOR_SHANGHAI, pThis->bCpuVendor == BS3CPUVENDOR_SHANGHAI); + +#undef CASE_PRED + default: + return Bs3TestFailedF("Invalid selector opcode %#x!", pbCode[-1]); + } + } + + return true; +} + + +#ifdef BS3CG1_DEBUG_CTX_MOD +/** + * Translates the operator into a string. + * + * @returns Read-only string pointer. + * @param bOpcode The context modifier program opcode. + */ +static const char BS3_FAR * BS3_NEAR_CODE Bs3Cg1CtxOpToString(uint8_t bOpcode) +{ + switch (bOpcode & BS3CG1_CTXOP_OPERATOR_MASK) + { + case BS3CG1_CTXOP_ASSIGN: return "="; + case BS3CG1_CTXOP_OR: return "|="; + case BS3CG1_CTXOP_AND: return "&="; + case BS3CG1_CTXOP_AND_INV: return "&~="; + default: return "?WTF?"; + } +} +#endif + + +/** + * Runs a context modifier program. + * + * @returns Success indicator (true/false). + * @param pThis The state. + * @param pCtx The context. + * @param pHdr The program header. + * @param off The program offset relative to the end of the header. + * @param cb The program size. + * @param pEflCtx The context to take undefined EFLAGS from. (This is NULL + * if we're processing a input context modifier program.) + * @param pbInstr Points to the first instruction byte. For storing + * immediate operands during input context modification. + * NULL for output contexts. + */ +static bool BS3_NEAR_CODE Bs3Cg1RunContextModifier(PBS3CG1STATE pThis, PBS3REGCTX pCtx, PCBS3CG1TESTHDR pHdr, + unsigned off, unsigned cb, + PCBS3REGCTX pEflCtx, uint8_t BS3_FAR *pbInstr) +{ + uint8_t const BS3_FAR *pbCode = (uint8_t const BS3_FAR *)(pHdr + 1) + off; + int cbLeft = cb; + while (cbLeft-- > 0) + { + /* + * Decode the instruction. + */ + uint8_t const bOpcode = *pbCode++; + unsigned cbValue; + unsigned cbDst; + BS3CG1DST idxField; + BS3PTRUNION PtrField; + uint8_t BS3_FAR *pbMemCopy = NULL; + bool fZxVlMax; + + /* Expand the destiation field (can be escaped). Set fZxVlMax. */ + switch (bOpcode & BS3CG1_CTXOP_DST_MASK) + { + case BS3CG1_CTXOP_OP1: + idxField = pThis->aOperands[0].idxField; + if (idxField == BS3CG1DST_INVALID) + idxField = BS3CG1DST_OP1; + fZxVlMax = pEflCtx != NULL && pThis->aOperands[0].enmLocation == BS3CG1OPLOC_CTX_ZX_VLMAX; + break; + + case BS3CG1_CTXOP_OP2: + idxField = pThis->aOperands[1].idxField; + if (idxField == BS3CG1DST_INVALID) + idxField = BS3CG1DST_OP2; + fZxVlMax = pEflCtx != NULL && pThis->aOperands[1].enmLocation == BS3CG1OPLOC_CTX_ZX_VLMAX; + break; + + case BS3CG1_CTXOP_EFL: + idxField = BS3CG1DST_EFL; + fZxVlMax = false; + break; + + case BS3CG1_CTXOP_DST_ESC: + if (cbLeft-- > 0) + { + idxField = (BS3CG1DST)*pbCode++; + if (idxField <= BS3CG1DST_OP4) + { + if (idxField > BS3CG1DST_INVALID) + { + unsigned idxOp = idxField - BS3CG1DST_OP1; + uint8_t idxField2 = pThis->aOperands[idxOp].idxField; + if (idxField2 != BS3CG1DST_INVALID) + idxField = idxField2; + fZxVlMax = pEflCtx != NULL && pThis->aOperands[idxOp].enmLocation == BS3CG1OPLOC_CTX_ZX_VLMAX; + break; + } + } + else if (idxField < BS3CG1DST_END) + { + fZxVlMax = false; + break; + } + return Bs3TestFailedF("Malformed context instruction: idxField=%d", idxField); + } + RT_FALL_THRU(); + default: + return Bs3TestFailed("Malformed context instruction: Destination"); + } + + /* Expand value size (can be escaped). */ + switch (bOpcode & BS3CG1_CTXOP_SIZE_MASK) + { + case BS3CG1_CTXOP_1_BYTE: cbValue = 1; break; + case BS3CG1_CTXOP_2_BYTES: cbValue = 2; break; + case BS3CG1_CTXOP_4_BYTES: cbValue = 4; break; + case BS3CG1_CTXOP_8_BYTES: cbValue = 8; break; + case BS3CG1_CTXOP_16_BYTES: cbValue = 16; break; + case BS3CG1_CTXOP_32_BYTES: cbValue = 32; break; + case BS3CG1_CTXOP_12_BYTES: cbValue = 12; break; + case BS3CG1_CTXOP_SIZE_ESC: + if (cbLeft-- > 0) + { + cbValue = *pbCode++; + if (cbValue) + break; + } + RT_FALL_THRU(); + default: + return Bs3TestFailed("Malformed context instruction: size"); + } + + /* Make sure there is enough instruction bytes for the value. */ + if (cbValue <= cbLeft) + { /* likely */ } + else + return Bs3TestFailedF("Malformed context instruction: %u bytes value, %u bytes left", cbValue, cbLeft); + + /* + * Do value processing specific to the target field size. + */ + cbDst = g_acbBs3Cg1DstFields[idxField]; + if (cbDst == BS3CG1DSTSIZE_OPERAND) + cbDst = pThis->aOperands[idxField - BS3CG1DST_OP1].cbOp; + else if (cbDst == BS3CG1DSTSIZE_OPERAND_SIZE_GRP) + cbDst = pThis->cbOperand; + if (cbDst <= 8) + { + unsigned const offField = g_aoffBs3Cg1DstFields[idxField]; + + /* + * Deal with fields up to 8-byte wide. + */ + + /* Get the value. */ + uint64_t uValue; + if ((bOpcode & BS3CG1_CTXOP_SIGN_EXT)) + switch (cbValue) + { + case 1: uValue = *(int8_t const BS3_FAR *)pbCode; break; + case 2: uValue = *(int16_t const BS3_FAR *)pbCode; break; + case 4: uValue = *(int32_t const BS3_FAR *)pbCode; break; + default: + if (cbValue >= 8) + { + uValue = *(uint64_t const BS3_FAR *)pbCode; + break; + } + return Bs3TestFailedF("Malformed context instruction: %u bytes value (%u dst)", cbValue, cbDst); + } + else + switch (cbValue) + { + case 1: uValue = *(uint8_t const BS3_FAR *)pbCode; break; + case 2: uValue = *(uint16_t const BS3_FAR *)pbCode; break; + case 4: uValue = *(uint32_t const BS3_FAR *)pbCode; break; + default: + if (cbValue >= 8) + { + uValue = *(uint64_t const BS3_FAR *)pbCode; + break; + } + return Bs3TestFailedF("Malformed context instruction: %u bytes value (%u dst)", cbValue, cbDst); + } + + /* Find the field. */ + if (offField < sizeof(BS3REGCTX)) + PtrField.pu8 = (uint8_t BS3_FAR *)pCtx + offField; + /* Non-register operands: */ + else if ((unsigned)(idxField - BS3CG1DST_OP1) < 4U) + { + unsigned const idxOp = idxField - BS3CG1DST_OP1; + + switch (pThis->aOperands[idxOp].enmLocation) + { + case BS3CG1OPLOC_IMM: + if (pbInstr) + PtrField.pu8 = &pbInstr[pThis->aOperands[idxOp].off]; + else + return Bs3TestFailedF("Immediate operand referenced in output context!"); + break; + + case BS3CG1OPLOC_MEM: + if (!pbInstr) + return Bs3TestFailedF("Read only operand specified in output!"); + PtrField.pu8 = &pThis->pbDataPg[X86_PAGE_SIZE - pThis->aOperands[idxOp].off]; + break; + + case BS3CG1OPLOC_MEM_RW: + case BS3CG1OPLOC_MEM_WO: + if (pbInstr) + { + PtrField.pu8 = &pThis->pbDataPg[X86_PAGE_SIZE - pThis->aOperands[idxOp].off]; + pbMemCopy = pThis->MemOp.ab; + } + else + PtrField.pu8 = pThis->MemOp.ab; + break; + + default: + if (pThis->enmEncoding != pThis->enmEncodingNonInvalid) + goto l_advance_to_next; + return Bs3TestFailedF("Internal error: cbDst=%u idxField=%d (%d) offField=%#x: enmLocation=%u off=%#x idxField=%u", + cbDst, idxField, idxOp, offField, pThis->aOperands[idxOp].enmLocation, + pThis->aOperands[idxOp].off, pThis->aOperands[idxOp].idxField); + } + } + /* Special field: Copying in undefined EFLAGS from the result context. */ + else if (idxField == BS3CG1DST_EFL_UNDEF) + { + if (!pEflCtx || (bOpcode & BS3CG1_CTXOP_OPERATOR_MASK) != BS3CG1_CTXOP_ASSIGN) + return Bs3TestFailed("Invalid BS3CG1DST_EFL_UNDEF usage"); + PtrField.pu32 = &pCtx->rflags.u32; + uValue = (*PtrField.pu32 & ~(uint32_t)uValue) | (pEflCtx->rflags.u32 & (uint32_t)uValue); + } + /* Special field: Expected value (in/result) exception. */ + else if (idxField == BS3CG1DST_VALUE_XCPT) + { + if (!pEflCtx || (bOpcode & BS3CG1_CTXOP_OPERATOR_MASK) != BS3CG1_CTXOP_ASSIGN || cbDst != 1) + return Bs3TestFailed("Invalid BS3CG1DST_VALUE_XCPT usage"); + PtrField.pu8 = &pThis->bValueXcpt; + } + /* FPU and FXSAVE format. */ + else if ( pThis->pExtCtx->enmMethod != BS3EXTCTXMETHOD_ANCIENT + && offField - sizeof(BS3REGCTX) < RT_UOFFSET_AFTER(BS3EXTCTX, Ctx.x87.aXMM[15])) + { + if (pThis->fWorkExtCtx) + PtrField.pb = (uint8_t *)pThis->pExtCtx + offField - sizeof(BS3REGCTX); + else if (!pThis->fCpuSetupFirstResult) + { + BS3CG1_DPRINTF(("dbg: Extended context disabled: skipping modification (<=8)\n")); + goto l_advance_to_next; + } + else + return Bs3TestFailedF("Extended context disabled: Field %d (%s) @ %#x LB %u\n", + idxField, g_aszBs3Cg1DstFields[idxField].sz, offField, cbDst); + } + /** @todo other FPU fields and FPU state formats. */ + else + return Bs3TestFailedF("Todo implement me: cbDst=%u idxField=%d %s offField=%#x (<= 8)", + cbDst, idxField, g_aszBs3Cg1DstFields[idxField].sz, offField); + +#ifdef BS3CG1_DEBUG_CTX_MOD + switch (cbDst) + { + case 1: + BS3CG1_DPRINTF(("dbg: modify %s: %#04RX8 (LB %u) %s %#RX64 (LB %u)\n", g_aszBs3Cg1DstFields[idxField].sz, + *PtrField.pu8, cbDst, Bs3Cg1CtxOpToString(bOpcode), uValue, cbValue)); + break; + case 2: + BS3CG1_DPRINTF(("dbg: modify %s: %#06RX16 (LB %u) %s %#RX64 (LB %u)\n", g_aszBs3Cg1DstFields[idxField].sz, + *PtrField.pu16, cbDst, Bs3Cg1CtxOpToString(bOpcode), uValue, cbValue)); + break; + case 4: + BS3CG1_DPRINTF(("dbg: modify %s: %#010RX32 (LB %u) %s %#RX64 (LB %u)\n", g_aszBs3Cg1DstFields[idxField].sz, + *PtrField.pu32, cbDst, Bs3Cg1CtxOpToString(bOpcode), uValue, cbValue)); + break; + default: + BS3CG1_DPRINTF(("dbg: modify %s: %#018RX64 (LB %u) %s %#RX64 (LB %u)\n", g_aszBs3Cg1DstFields[idxField].sz, + *PtrField.pu64, cbDst, Bs3Cg1CtxOpToString(bOpcode), uValue, cbValue)); + break; + } +#endif + + /* Modify the field. */ + switch (cbDst) + { + case 1: + switch (bOpcode & BS3CG1_CTXOP_OPERATOR_MASK) + { + case BS3CG1_CTXOP_ASSIGN: *PtrField.pu8 = (uint8_t)uValue; break; + case BS3CG1_CTXOP_OR: *PtrField.pu8 |= (uint8_t)uValue; break; + case BS3CG1_CTXOP_AND: *PtrField.pu8 &= (uint8_t)uValue; break; + case BS3CG1_CTXOP_AND_INV: *PtrField.pu8 &= ~(uint8_t)uValue; break; + } + break; + + case 2: + switch (bOpcode & BS3CG1_CTXOP_OPERATOR_MASK) + { + case BS3CG1_CTXOP_ASSIGN: *PtrField.pu16 = (uint16_t)uValue; break; + case BS3CG1_CTXOP_OR: *PtrField.pu16 |= (uint16_t)uValue; break; + case BS3CG1_CTXOP_AND: *PtrField.pu16 &= (uint16_t)uValue; break; + case BS3CG1_CTXOP_AND_INV: *PtrField.pu16 &= ~(uint16_t)uValue; break; + } + break; + + case 4: + if ( (unsigned)(idxField - BS3CG1DST_XMM0_DW0_ZX) <= (unsigned)(BS3CG1DST_XMM15_DW0_ZX - BS3CG1DST_XMM0_DW0_ZX) + || fZxVlMax) + { + PtrField.pu32[1] = 0; + PtrField.pu64[1] = 0; + } + else if (offField <= RT_UOFFSETOF(BS3REGCTX, r15) /* Clear the top dword. */) + PtrField.pu32[1] = 0; + else if ((unsigned)(idxField - BS3CG1DST_MM0_LO_ZX) <= (unsigned)(BS3CG1DST_MM7_LO_ZX - BS3CG1DST_MM0_LO_ZX)) + { + PtrField.pu32[1] = 0; + PtrField.pu32[2] = 0xffff; /* observed on skylake */ + } + switch (bOpcode & BS3CG1_CTXOP_OPERATOR_MASK) + { + case BS3CG1_CTXOP_ASSIGN: *PtrField.pu32 = (uint32_t)uValue; break; + case BS3CG1_CTXOP_OR: *PtrField.pu32 |= (uint32_t)uValue; break; + case BS3CG1_CTXOP_AND: *PtrField.pu32 &= (uint32_t)uValue; break; + case BS3CG1_CTXOP_AND_INV: *PtrField.pu32 &= ~(uint32_t)uValue; break; + } + break; + + case 8: + if ( (unsigned)(idxField - BS3CG1DST_XMM0_LO_ZX) <= (unsigned)(BS3CG1DST_XMM15_LO_ZX - BS3CG1DST_XMM0_LO_ZX) + || fZxVlMax) + PtrField.pu64[1] = 0; + else if ((unsigned)(idxField - BS3CG1DST_MM0) <= (unsigned)(BS3CG1DST_MM7 - BS3CG1DST_MM0)) + PtrField.pu32[2] = 0xffff; /* observed on skylake */ + + switch (bOpcode & BS3CG1_CTXOP_OPERATOR_MASK) + { + case BS3CG1_CTXOP_ASSIGN: *PtrField.pu64 = (uint64_t)uValue; break; + case BS3CG1_CTXOP_OR: *PtrField.pu64 |= (uint64_t)uValue; break; + case BS3CG1_CTXOP_AND: *PtrField.pu64 &= (uint64_t)uValue; break; + case BS3CG1_CTXOP_AND_INV: *PtrField.pu64 &= ~(uint64_t)uValue; break; + } + break; + + default: + return Bs3TestFailedF("Malformed context instruction: cbDst=%u, expected 1, 2, 4, or 8", cbDst); + } + +#ifdef BS3CG1_DEBUG_CTX_MOD + switch (cbDst) + { + case 1: BS3CG1_DPRINTF(("dbg: --> %s: %#04RX8\n", g_aszBs3Cg1DstFields[idxField].sz, *PtrField.pu8)); break; + case 2: BS3CG1_DPRINTF(("dbg: --> %s: %#06RX16\n", g_aszBs3Cg1DstFields[idxField].sz, *PtrField.pu16)); break; + case 4: BS3CG1_DPRINTF(("dbg: --> %s: %#010RX32\n", g_aszBs3Cg1DstFields[idxField].sz, *PtrField.pu32)); break; + default: BS3CG1_DPRINTF(("dbg: --> %s: %#018RX64\n", g_aszBs3Cg1DstFields[idxField].sz, *PtrField.pu64)); break; + } +#endif + if (fZxVlMax) + { + uintptr_t iReg = ((uintptr_t)PtrField.pu8 - (uintptr_t)&pThis->pExtCtx->Ctx.x87.aXMM[0]) + / sizeof(pThis->pExtCtx->Ctx.x87.aXMM[0]); + pThis->pExtCtx->Ctx.x.u.YmmHi.aYmmHi[iReg].au64[0] = 0; + pThis->pExtCtx->Ctx.x.u.YmmHi.aYmmHi[iReg].au64[1] = 0; +#ifdef BS3CG1_DEBUG_CTX_MOD + BS3CG1_DPRINTF(("dbg: --> cleared YMM%u_HI\n", iReg)); +#endif + } + } + /* + * Deal with larger field (FPU, SSE, AVX, ...). + */ + else if (pThis->fWorkExtCtx) + { + union + { + X86FPUREG FpuReg; + X86XMMREG XmmReg; + X86YMMREG YmmReg; + X86ZMMREG ZmmReg; + uint8_t ab[sizeof(X86ZMMREG)]; + uint32_t au32[sizeof(X86ZMMREG) / sizeof(uint32_t)]; + uint64_t au64[sizeof(X86ZMMREG) / sizeof(uint64_t)]; + } Value; + unsigned const offField = g_aoffBs3Cg1DstFields[idxField]; + unsigned iReg; + + /* Copy the value into the union, doing the zero padding / extending. */ + Bs3MemCpy(&Value, pbCode, cbValue); + if (cbValue < sizeof(Value)) + { + if ((bOpcode & BS3CG1_CTXOP_SIGN_EXT) && (Value.ab[cbValue - 1] & 0x80)) + Bs3MemSet(&Value.ab[cbValue], 0xff, sizeof(Value) - cbValue); + else + Bs3MemSet(&Value.ab[cbValue], 0x00, sizeof(Value) - cbValue); + } + + /* Optimized access to XMM and STx registers. */ + if ( pThis->pExtCtx->enmMethod != BS3EXTCTXMETHOD_ANCIENT + && offField - sizeof(BS3REGCTX) < RT_UOFFSET_AFTER(BS3EXTCTX, Ctx.x87.aXMM[15]) ) + PtrField.pb = (uint8_t *)pThis->pExtCtx + offField - sizeof(BS3REGCTX); + /* Non-register operands: */ + else if ((unsigned)(idxField - BS3CG1DST_OP1) < 4U) + { + unsigned const idxOp = idxField - BS3CG1DST_OP1; + switch (pThis->aOperands[idxOp].enmLocation) + { + case BS3CG1OPLOC_MEM: + if (!pbInstr) + return Bs3TestFailedF("Read only operand specified in output!"); + PtrField.pu8 = &pThis->pbDataPg[X86_PAGE_SIZE - pThis->aOperands[idxOp].off]; + break; + + case BS3CG1OPLOC_MEM_RW: + case BS3CG1OPLOC_MEM_WO: + if (pbInstr) + { + PtrField.pu8 = &pThis->pbDataPg[X86_PAGE_SIZE - pThis->aOperands[idxOp].off]; + pbMemCopy = pThis->MemOp.ab; + } + else + PtrField.pu8 = pThis->MemOp.ab; + break; + + default: + return Bs3TestFailedF("Internal error: Field %d (%d) @ %#x LB %u: enmLocation=%u off=%#x idxField=%u", + idxField, idxOp, offField, cbDst, pThis->aOperands[idxOp].enmLocation, + pThis->aOperands[idxOp].off, pThis->aOperands[idxOp].idxField); + } + } + /* The YMM (AVX) registers have split storage in the state, so they need special handling. */ + else if ((iReg = idxField - BS3CG1DST_YMM0) < 16U) + { + /* The first 128-bits in XMM land. */ + PtrField.pu64 = &pThis->pExtCtx->Ctx.x87.aXMM[iReg].au64[0]; + switch (bOpcode & BS3CG1_CTXOP_OPERATOR_MASK) + { + case BS3CG1_CTXOP_ASSIGN: + PtrField.pu64[0] = Value.au64[0]; + PtrField.pu64[1] = Value.au64[1]; + break; + case BS3CG1_CTXOP_OR: + PtrField.pu64[0] |= Value.au64[0]; + PtrField.pu64[1] |= Value.au64[1]; + break; + case BS3CG1_CTXOP_AND: + PtrField.pu64[0] &= Value.au64[0]; + PtrField.pu64[1] &= Value.au64[1]; + break; + case BS3CG1_CTXOP_AND_INV: + PtrField.pu64[0] &= ~Value.au64[0]; + PtrField.pu64[1] &= ~Value.au64[1]; + break; + } + + /* The second 128-bit in YMM_HI land. */ + PtrField.pu64 = &pThis->pExtCtx->Ctx.x.u.YmmHi.aYmmHi[iReg].au64[0]; + switch (bOpcode & BS3CG1_CTXOP_OPERATOR_MASK) + { + case BS3CG1_CTXOP_ASSIGN: + PtrField.pu64[0] = Value.au64[2]; + PtrField.pu64[1] = Value.au64[3]; + break; + case BS3CG1_CTXOP_OR: + PtrField.pu64[0] |= Value.au64[2]; + PtrField.pu64[1] |= Value.au64[3]; + break; + case BS3CG1_CTXOP_AND: + PtrField.pu64[0] &= Value.au64[2]; + PtrField.pu64[1] &= Value.au64[3]; + break; + case BS3CG1_CTXOP_AND_INV: + PtrField.pu64[0] &= ~Value.au64[2]; + PtrField.pu64[1] &= ~Value.au64[3]; + break; + } + PtrField.pb = NULL; + } + /* AVX512 needs handling like above, but more complicated. */ + else + return Bs3TestFailedF("TODO: implement me: cbDst=%d idxField=%d (AVX and other weird state)", cbDst, idxField); + + if (PtrField.pb) + { + /* Modify the field / memory. */ + unsigned i; + if (cbDst & 3) + return Bs3TestFailedF("Malformed context instruction: cbDst=%u, multiple of 4", cbDst); + +#ifdef BS3CG1_DEBUG_CTX_MOD + BS3CG1_DPRINTF(("dbg: modify %s: %.*Rhxs (LB %u) %s %.*Rhxs (LB %u)\n", g_aszBs3Cg1DstFields[idxField].sz, + cbDst, PtrField.pb, cbDst, Bs3Cg1CtxOpToString(bOpcode), cbValue, Value.ab, cbValue)); +#endif + + i = cbDst / 4; + while (i-- > 0) + { + switch (bOpcode & BS3CG1_CTXOP_OPERATOR_MASK) + { + case BS3CG1_CTXOP_ASSIGN: PtrField.pu32[i] = Value.au32[i]; break; + case BS3CG1_CTXOP_OR: PtrField.pu32[i] |= Value.au32[i]; break; + case BS3CG1_CTXOP_AND: PtrField.pu32[i] &= Value.au32[i]; break; + case BS3CG1_CTXOP_AND_INV: PtrField.pu32[i] &= ~Value.au32[i]; break; + } + } + +#ifdef BS3CG1_DEBUG_CTX_MOD + BS3CG1_DPRINTF(("dbg: --> %s: %.*Rhxs\n", g_aszBs3Cg1DstFields[idxField].sz, cbDst, PtrField.pb)); +#endif + + if (fZxVlMax) + { + uintptr_t iReg = ((uintptr_t)PtrField.pu8 - (uintptr_t)&pThis->pExtCtx->Ctx.x87.aXMM[0]) + / sizeof(pThis->pExtCtx->Ctx.x87.aXMM[0]); + if (cbDst < 16) + { + for (i = cbDst / 4; i < 4; i++) + PtrField.pu32[i++] = 0; +#ifdef BS3CG1_DEBUG_CTX_MOD + BS3CG1_DPRINTF(("dbg: --> cleared high %u bytes of XMM%u\n", 16 - cbDst, iReg)); +#endif + } + pThis->pExtCtx->Ctx.x.u.YmmHi.aYmmHi[iReg].au64[0] = 0; + pThis->pExtCtx->Ctx.x.u.YmmHi.aYmmHi[iReg].au64[1] = 0; +#ifdef BS3CG1_DEBUG_CTX_MOD + BS3CG1_DPRINTF(("dbg: --> cleared YMM%u_HI\n", iReg)); +#endif + } + } + + /* + * Hack! Update pThis->MemOp when setting up the inputs so we can + * correctly validate value and alignment exceptions. + */ + if (pbMemCopy && PtrField.pv) + Bs3MemCpy(pbMemCopy, PtrField.pv, cbDst); + } + /* !pThis->fWorkExtCtx: */ + else if (pThis->fCpuSetupFirstResult) + return Bs3TestFailedF("Extended context disabled: Field %d (%s) @ %#x LB %u\n", + idxField, g_aszBs3Cg1DstFields[idxField].sz, g_aoffBs3Cg1DstFields[idxField], cbDst); + else + BS3CG1_DPRINTF(("dbg: Extended context disabled: skipping modification [> 8]\n")); + + /* + * Advance to the next instruction. + */ +l_advance_to_next: + pbCode += cbValue; + cbLeft -= cbValue; + } + + return true; +} + + +/** + * Checks the result of a run. + * + * @returns true if successful, false if not. + * @param pThis The state. + * @param bTestXcptExpected The exception causing the test code to stop + * executing. + * @param fInvalidEncodingPgFault Set if we've cut the instruction a byte + * short and is expecting a \#PF on the page + * boundrary rather than a \#UD. Only set if + * fInvalidEncoding is also set. + * @param iEncoding For error reporting. + */ +static bool BS3_NEAR_CODE Bs3Cg1CheckResult(PBS3CG1STATE pThis, uint8_t bTestXcptExpected, + bool fInvalidEncodingPgFault, unsigned iEncoding) +{ + unsigned iOperand; + + /* + * Check the exception state first. + */ + uint8_t bExpectedXcpt; + uint8_t cbAdjustPc; + if (!pThis->fInvalidEncoding) + { + bExpectedXcpt = pThis->bAlignmentXcpt; + if (bExpectedXcpt == UINT8_MAX) + bExpectedXcpt = pThis->bValueXcpt; + if (bExpectedXcpt == UINT8_MAX) + { + cbAdjustPc = pThis->cbCurInstr; + bExpectedXcpt = bTestXcptExpected; + if (bTestXcptExpected == X86_XCPT_PF) + pThis->Ctx.cr2.u = pThis->uCodePgFlat + X86_PAGE_SIZE; + } + else + cbAdjustPc = 0; + } + else + { + cbAdjustPc = 0; + if (!fInvalidEncodingPgFault) + bExpectedXcpt = X86_XCPT_UD; + else + { + bExpectedXcpt = X86_XCPT_PF; + pThis->Ctx.cr2.u = pThis->uCodePgFlat + X86_PAGE_SIZE; + } + } + if (RT_LIKELY( pThis->TrapFrame.bXcpt == bExpectedXcpt + && pThis->TrapFrame.Ctx.rip.u == pThis->Ctx.rip.u + cbAdjustPc)) + { + /* + * Check the register content. + */ + bool fOkay = Bs3TestCheckRegCtxEx(&pThis->TrapFrame.Ctx, &pThis->Ctx, + cbAdjustPc, 0 /*cbSpAdjust*/, 0 /*fExtraEfl*/, + pThis->pszMode, iEncoding); + + /* + * Check memory output operands. + */ + if (!pThis->fInvalidEncoding) + { + iOperand = pThis->cOperands; + while (iOperand-- > 0) + if ( pThis->aOperands[iOperand].enmLocation == BS3CG1OPLOC_MEM_RW + || pThis->aOperands[iOperand].enmLocation == BS3CG1OPLOC_MEM_WO) + { + if (pThis->aOperands[iOperand].off) + { + BS3PTRUNION PtrUnion; + PtrUnion.pb = &pThis->pbDataPg[X86_PAGE_SIZE - pThis->aOperands[iOperand].off]; + switch (pThis->aOperands[iOperand].cbOp) + { + case 1: + if (*PtrUnion.pu8 == pThis->MemOp.ab[0]) + continue; + Bs3TestFailedF("op%u: Wrote %#04RX8, expected %#04RX8", + iOperand, *PtrUnion.pu8, pThis->MemOp.ab[0]); + break; + case 2: + if (*PtrUnion.pu16 == pThis->MemOp.au16[0]) + continue; + Bs3TestFailedF("op%u: Wrote %#06RX16, expected %#06RX16", + iOperand, *PtrUnion.pu16, pThis->MemOp.au16[0]); + break; + case 4: + if (*PtrUnion.pu32 == pThis->MemOp.au32[0]) + continue; + Bs3TestFailedF("op%u: Wrote %#010RX32, expected %#010RX32", + iOperand, *PtrUnion.pu32, pThis->MemOp.au32[0]); + break; + case 8: + if (*PtrUnion.pu64 == pThis->MemOp.au64[0]) + continue; + Bs3TestFailedF("op%u: Wrote %#018RX64, expected %#018RX64", + iOperand, *PtrUnion.pu64, pThis->MemOp.au64[0]); + break; + default: + if (Bs3MemCmp(PtrUnion.pb, pThis->MemOp.ab, pThis->aOperands[iOperand].cbOp) == 0) + continue; + Bs3TestFailedF("op%u: Wrote %.*Rhxs, expected %.*Rhxs", + iOperand, + pThis->aOperands[iOperand].cbOp, PtrUnion.pb, + pThis->aOperands[iOperand].cbOp, pThis->MemOp.ab); + break; + } + } + else + Bs3TestFailedF("op%u: off is zero\n", iOperand); + fOkay = false; + } + } + + /* + * Check extended context if enabled. + */ + if (pThis->fWorkExtCtx) + { + PBS3EXTCTX pExpect = pThis->pExtCtx; + PBS3EXTCTX pResult = pThis->pResultExtCtx; + unsigned i; + if ( pExpect->enmMethod == BS3EXTCTXMETHOD_XSAVE + || pExpect->enmMethod == BS3EXTCTXMETHOD_FXSAVE) + { + /* Compare the x87 state, ASSUMING XCR0 bit 1 is set. */ +#define CHECK_FIELD(a_Field, a_szFmt) \ + if (pResult->Ctx.a_Field != pExpect->Ctx.a_Field) fOkay = Bs3TestFailedF(a_szFmt, pResult->Ctx.a_Field, pExpect->Ctx.a_Field) + CHECK_FIELD(x87.FCW, "FCW: %#06x, expected %#06x"); + CHECK_FIELD(x87.FSW, "FSW: %#06x, expected %#06x"); + CHECK_FIELD(x87.FTW, "FTW: %#06x, expected %#06x"); + //CHECK_FIELD(x87.FOP, "FOP: %#06x, expected %#06x"); + //CHECK_FIELD(x87.FPUIP, "FPUIP: %#010RX32, expected %#010RX32"); + //CHECK_FIELD(x87.CS, "FPUCS: %#06x, expected %#06x"); + //CHECK_FIELD(x87.Rsrvd1, "Rsrvd1: %#06x, expected %#06x"); + //CHECK_FIELD(x87.DP, "FPUDP: %#010RX32, expected %#010RX32"); + //CHECK_FIELD(x87.DS, "FPUDS: %#06x, expected %#06x"); + //CHECK_FIELD(x87.Rsrvd2, "Rsrvd2: %#06x, expected %#06x"); + CHECK_FIELD(x87.MXCSR, "MXCSR: %#010RX32, expected %#010RX32"); +#undef CHECK_FIELD + for (i = 0; i < RT_ELEMENTS(pExpect->Ctx.x87.aRegs); i++) + if ( pResult->Ctx.x87.aRegs[i].au64[0] != pExpect->Ctx.x87.aRegs[i].au64[0] + || pResult->Ctx.x87.aRegs[i].au16[4] != pExpect->Ctx.x87.aRegs[i].au16[4]) + fOkay = Bs3TestFailedF("ST[%u]: %c m=%#RX64 e=%d, expected %c m=%#RX64 e=%d", i, + pResult->Ctx.x87.aRegs[i].r80Ex.s.fSign ? '-' : '+', + pResult->Ctx.x87.aRegs[i].r80Ex.s.u64Mantissa, + pResult->Ctx.x87.aRegs[i].r80Ex.s.uExponent, + pExpect->Ctx.x87.aRegs[i].r80Ex.s.fSign ? '-' : '+', + pExpect->Ctx.x87.aRegs[i].r80Ex.s.u64Mantissa, + pExpect->Ctx.x87.aRegs[i].r80Ex.s.uExponent); + for (i = 0; i < (ARCH_BITS == 64 ? 16 : 8); i++) + if ( pResult->Ctx.x87.aXMM[i].au64[0] != pExpect->Ctx.x87.aXMM[i].au64[0] + || pResult->Ctx.x87.aXMM[i].au64[1] != pExpect->Ctx.x87.aXMM[i].au64[1]) + fOkay = Bs3TestFailedF("XMM%u: %#010RX64'%016RX64, expected %#010RX64'%08RX64", i, + pResult->Ctx.x87.aXMM[i].au64[1], + pResult->Ctx.x87.aXMM[i].au64[0], + pExpect->Ctx.x87.aXMM[i].au64[1], + pExpect->Ctx.x87.aXMM[i].au64[0]); + if (pExpect->fXcr0Saved & XSAVE_C_YMM) + for (i = 0; i < (ARCH_BITS == 64 ? 16 : 8); i++) + if ( pResult->Ctx.x.u.YmmHi.aYmmHi[i].au64[0] != pExpect->Ctx.x.u.YmmHi.aYmmHi[i].au64[0] + || pResult->Ctx.x.u.YmmHi.aYmmHi[i].au64[1] != pExpect->Ctx.x.u.YmmHi.aYmmHi[i].au64[1]) + fOkay = Bs3TestFailedF("YMM%u_HI: %#010RX64'%016RX64, expected %#010RX64'%08RX64", i, + pResult->Ctx.x.u.YmmHi.aYmmHi[i].au64[1], + pResult->Ctx.x.u.YmmHi.aYmmHi[i].au64[0], + pExpect->Ctx.x.u.YmmHi.aYmmHi[i].au64[1], + pExpect->Ctx.x.u.YmmHi.aYmmHi[i].au64[0]); + } + else + fOkay = Bs3TestFailedF("Unsupported extended CPU context method: %d", pExpect->enmMethod); + } + + /* + * Done. + */ + if (fOkay) + return true; + + /* + * Report failure. + */ + Bs3TestFailedF("ins#%RU32/test#%u: encoding #%u: %.*Rhxs%s", + pThis->iInstr, pThis->iTest, iEncoding, pThis->cbCurInstr, pThis->abCurInstr, + fInvalidEncodingPgFault ? " (cut short)" : ""); + } + else + Bs3TestFailedF("ins#%RU32/test#%u: bXcpt=%#x expected %#x; rip=%RX64 expected %RX64; encoding#%u: %.*Rhxs%s", + pThis->iInstr, pThis->iTest, + pThis->TrapFrame.bXcpt, bExpectedXcpt, + pThis->TrapFrame.Ctx.rip.u, pThis->Ctx.rip.u + cbAdjustPc, + iEncoding, pThis->cbCurInstr, pThis->abCurInstr, fInvalidEncodingPgFault ? " (cut short)" : ""); + Bs3TestPrintf("cpl=%u cbOperands=%u\n", pThis->uCpl, pThis->cbOperand); + + /* + * Display memory operands. + */ + for (iOperand = 0; iOperand < pThis->cOperands; iOperand++) + { + BS3PTRUNION PtrUnion; + switch (pThis->aOperands[iOperand].enmLocation) + { + case BS3CG1OPLOC_CTX: + { + uint8_t idxField = pThis->aOperands[iOperand].idxField; + unsigned offField = g_aoffBs3Cg1DstFields[idxField]; + if (offField <= sizeof(BS3REGCTX)) + PtrUnion.pb = (uint8_t BS3_FAR *)&pThis->Ctx + offField; + else + { + Bs3TestPrintf("op%u: ctx%u: xxxx\n", iOperand, pThis->aOperands[iOperand].cbOp * 8); + break; + } + switch (pThis->aOperands[iOperand].cbOp) + { + case 1: Bs3TestPrintf("op%u: ctx08: %#04RX8\n", iOperand, *PtrUnion.pu8); break; + case 2: Bs3TestPrintf("op%u: ctx16: %#06RX16\n", iOperand, *PtrUnion.pu16); break; + case 4: Bs3TestPrintf("op%u: ctx32: %#010RX32\n", iOperand, *PtrUnion.pu32); break; + case 8: Bs3TestPrintf("op%u: ctx64: %#018RX64\n", iOperand, *PtrUnion.pu64); break; + default: + Bs3TestPrintf("op%u: ctx%u: %.*Rhxs\n", iOperand, pThis->aOperands[iOperand].cbOp * 8, + pThis->aOperands[iOperand].cbOp, PtrUnion.pb); + break; + } + break; + } + + case BS3CG1OPLOC_IMM: + PtrUnion.pb = &pThis->pbCodePg[pThis->aOperands[iOperand].off]; + switch (pThis->aOperands[iOperand].cbOp) + { + case 1: Bs3TestPrintf("op%u: imm08: %#04RX8\n", iOperand, *PtrUnion.pu8); break; + case 2: Bs3TestPrintf("op%u: imm16: %#06RX16\n", iOperand, *PtrUnion.pu16); break; + case 4: Bs3TestPrintf("op%u: imm32: %#010RX32\n", iOperand, *PtrUnion.pu32); break; + case 8: Bs3TestPrintf("op%u: imm64: %#018RX64\n", iOperand, *PtrUnion.pu64); break; + default: + Bs3TestPrintf("op%u: imm%u: %.*Rhxs\n", iOperand, pThis->aOperands[iOperand].cbOp * 8, + pThis->aOperands[iOperand].cbOp, PtrUnion.pb); + break; + } + break; + + case BS3CG1OPLOC_MEM: + case BS3CG1OPLOC_MEM_RW: + case BS3CG1OPLOC_MEM_WO: + if (pThis->aOperands[iOperand].off) + { + PtrUnion.pb = &pThis->pbDataPg[X86_PAGE_SIZE - pThis->aOperands[iOperand].off]; + switch (pThis->aOperands[iOperand].cbOp) + { + case 1: Bs3TestPrintf("op%u: result mem08: %#04RX8\n", iOperand, *PtrUnion.pu8); break; + case 2: Bs3TestPrintf("op%u: result mem16: %#06RX16\n", iOperand, *PtrUnion.pu16); break; + case 4: Bs3TestPrintf("op%u: result mem32: %#010RX32\n", iOperand, *PtrUnion.pu32); break; + case 8: Bs3TestPrintf("op%u: result mem64: %#018RX64\n", iOperand, *PtrUnion.pu64); break; + default: + Bs3TestPrintf("op%u: result mem%u: %.*Rhxs\n", iOperand, pThis->aOperands[iOperand].cbOp * 8, + pThis->aOperands[iOperand].cbOp, PtrUnion.pb); + break; + } + if ( pThis->aOperands[iOperand].enmLocation == BS3CG1OPLOC_MEM_WO + || pThis->aOperands[iOperand].enmLocation == BS3CG1OPLOC_MEM_RW) + { + PtrUnion.pb = pThis->MemOp.ab; + switch (pThis->aOperands[iOperand].cbOp) + { + case 1: Bs3TestPrintf("op%u: expect mem08: %#04RX8\n", iOperand, *PtrUnion.pu8); break; + case 2: Bs3TestPrintf("op%u: expect mem16: %#06RX16\n", iOperand, *PtrUnion.pu16); break; + case 4: Bs3TestPrintf("op%u: expect mem32: %#010RX32\n", iOperand, *PtrUnion.pu32); break; + case 8: Bs3TestPrintf("op%u: expect mem64: %#018RX64\n", iOperand, *PtrUnion.pu64); break; + default: + Bs3TestPrintf("op%u: expect mem%u: %.*Rhxs\n", iOperand, pThis->aOperands[iOperand].cbOp * 8, + pThis->aOperands[iOperand].cbOp, PtrUnion.pb); + break; + } + } + } + else + Bs3TestPrintf("op%u: mem%u: zero off value!!\n", iOperand, pThis->aOperands[iOperand].cbOp * 8); + break; + } + } + + /* + * Display contexts. + */ + Bs3TestPrintf("-- Expected context:\n"); + Bs3RegCtxPrint(&pThis->Ctx); + if (pThis->fWorkExtCtx) + Bs3TestPrintf("xcr0=%RX64\n", pThis->pExtCtx->fXcr0Saved); + Bs3TestPrintf("-- Actual context:\n"); + Bs3TrapPrintFrame(&pThis->TrapFrame); + if (pThis->fWorkExtCtx) + Bs3TestPrintf("xcr0=%RX64\n", pThis->pResultExtCtx->fXcr0Saved); + Bs3TestPrintf("\n"); +ASMHalt(); + return false; +} + + +/** + * Destroys the state, freeing all allocations and such. + * + * @param pThis The state. + */ +static void BS3_NEAR_CODE Bs3Cg1Destroy(PBS3CG1STATE pThis) +{ + if (BS3_MODE_IS_PAGED(pThis->bMode)) + { +#if ARCH_BITS != 16 + Bs3MemGuardedTestPageFree(pThis->pbCodePg); + Bs3MemGuardedTestPageFree(pThis->pbDataPg); +#endif + } + else + { + Bs3MemFree(pThis->pbCodePg, X86_PAGE_SIZE); + Bs3MemFree(pThis->pbDataPg, X86_PAGE_SIZE); + } + + if (pThis->pExtCtx) + Bs3MemFree(pThis->pExtCtx, pThis->pExtCtx->cb * 3); + + pThis->pbCodePg = NULL; + pThis->pbDataPg = NULL; + pThis->pExtCtx = NULL; + pThis->pResultExtCtx = NULL; + pThis->pInitialExtCtx = NULL; +} + + +/** + * Initializes the state. + * + * @returns Success indicator (true/false) + * @param pThis The state. + * @param bMode The mode being tested. + */ +bool BS3_NEAR_CODE BS3_CMN_NM(Bs3Cg1Init)(PBS3CG1STATE pThis, uint8_t bMode) +{ + BS3MEMKIND const enmMemKind = BS3_MODE_IS_RM_OR_V86(bMode) ? BS3MEMKIND_REAL + : !BS3_MODE_IS_64BIT_CODE(bMode) ? BS3MEMKIND_TILED : BS3MEMKIND_FLAT32; + unsigned iRing; + unsigned cb; + unsigned i; + uint64_t fFlags; + PBS3EXTCTX pExtCtx; + + Bs3MemSet(pThis, 0, sizeof(*pThis)); + + pThis->iFirstRing = BS3_MODE_IS_V86(bMode) ? 3 : 0; + pThis->iEndRing = BS3_MODE_IS_RM_SYS(bMode) ? 1 : 4; + pThis->bMode = bMode; + pThis->pszMode = Bs3GetModeName(bMode); + pThis->pszModeShort = Bs3GetModeNameShortLower(bMode); + pThis->bCpuVendor = Bs3GetCpuVendor(); + pThis->pchMnemonic = g_achBs3Cg1Mnemonics; + pThis->pabOperands = g_abBs3Cg1Operands; + pThis->pabOpcodes = g_abBs3Cg1Opcodes; + pThis->fAdvanceMnemonic = 1; + + /* Allocate extended context structures. */ + cb = Bs3ExtCtxGetSize(&fFlags); + pExtCtx = Bs3MemAlloc(BS3MEMKIND_TILED, cb * 3); + if (!pExtCtx) + return Bs3TestFailedF("Bs3MemAlloc(tiled,%#x)", cb * 3); + pThis->pExtCtx = pExtCtx; + pThis->pResultExtCtx = (PBS3EXTCTX)((uint8_t BS3_FAR *)pExtCtx + cb); + pThis->pInitialExtCtx = (PBS3EXTCTX)((uint8_t BS3_FAR *)pExtCtx + cb + cb); + + Bs3ExtCtxInit(pThis->pExtCtx, cb, fFlags); + Bs3ExtCtxInit(pThis->pResultExtCtx, cb, fFlags); + Bs3ExtCtxInit(pThis->pInitialExtCtx, cb, fFlags); + //Bs3TestPrintf("fCR0=%RX64 cbExtCtx=%#x method=%d\n", fFlags, cb, pExtCtx->enmMethod); + + /* Allocate guarded exectuable and data memory. */ + if (BS3_MODE_IS_PAGED(bMode)) + { +#if ARCH_BITS != 16 + pThis->pbCodePg = Bs3MemGuardedTestPageAlloc(enmMemKind); + pThis->pbDataPg = Bs3MemGuardedTestPageAlloc(enmMemKind); + if (!pThis->pbCodePg || !pThis->pbDataPg) + { + Bs3TestFailedF("Bs3MemGuardedTestPageAlloc(%d) failed", enmMemKind); + Bs3MemPrintInfo(); + Bs3Shutdown(); + return Bs3TestFailedF("Bs3MemGuardedTestPageAlloc(%d) failed", enmMemKind); + } + if ( BS3_MODE_IS_64BIT_CODE(bMode) + && (uintptr_t)pThis->pbDataPg >= _2G) + return Bs3TestFailedF("pbDataPg=%p is above 2GB and not simple to address from 64-bit code", pThis->pbDataPg); +#else + return Bs3TestFailed("WTF?! #1"); +#endif + } + else + { + pThis->pbCodePg = Bs3MemAlloc(enmMemKind, X86_PAGE_SIZE); + pThis->pbDataPg = Bs3MemAlloc(enmMemKind, X86_PAGE_SIZE); + if (!pThis->pbCodePg || !pThis->pbDataPg) + { + Bs3MemPrintInfo(); + return Bs3TestFailedF("Bs3MemAlloc(%d,Pg) failed", enmMemKind); + } + } + pThis->uCodePgFlat = Bs3SelPtrToFlat(pThis->pbCodePg); + pThis->uDataPgFlat = Bs3SelPtrToFlat(pThis->pbDataPg); +#if ARCH_BITS == 16 + pThis->CodePgFar.sel = BS3_FP_SEG(pThis->pbCodePg); + pThis->CodePgFar.off = BS3_FP_OFF(pThis->pbCodePg); + pThis->CodePgRip = BS3_FP_OFF(pThis->pbCodePg); + pThis->DataPgFar.sel = BS3_FP_SEG(pThis->pbDataPg); + pThis->DataPgFar.off = BS3_FP_OFF(pThis->pbDataPg); +#else + if (BS3_MODE_IS_RM_OR_V86(bMode)) + { + *(uint32_t *)&pThis->DataPgFar = Bs3SelFlatDataToRealMode(pThis->uDataPgFlat); + ASMCompilerBarrier(); + pThis->CodePgFar.off = 0; + pThis->CodePgFar.sel = pThis->uCodePgFlat >> 4; + pThis->CodePgRip = pThis->CodePgFar.off; + } + else if (BS3_MODE_IS_16BIT_CODE(bMode)) + { + *(uint32_t *)&pThis->DataPgFar = Bs3SelFlatDataToProtFar16(pThis->uDataPgFlat); + ASMCompilerBarrier(); + pThis->CodePgFar.sel = BS3_SEL_SPARE_00; + pThis->CodePgFar.off = 0; + pThis->CodePgRip = 0; + } + else if (BS3_MODE_IS_32BIT_CODE(bMode)) + { + *(uint32_t *)&pThis->DataPgFar = Bs3SelFlatDataToProtFar16(pThis->uDataPgFlat); + ASMCompilerBarrier(); + pThis->CodePgFar.sel = 0; + pThis->CodePgFar.off = 0; + pThis->CodePgRip = (uintptr_t)pThis->pbCodePg; + } + else + { + pThis->DataPgFar.off = 0; + pThis->DataPgFar.sel = 0; + pThis->CodePgFar.off = 0; + pThis->CodePgFar.sel = 0; + pThis->CodePgRip = (uintptr_t)pThis->pbCodePg; + } +#endif + BS3CG1_DPRINTF(("pbDataPg=%p %04x:%04x pbCodePg=%p %04x:%04x\n", + pThis->pbDataPg, pThis->DataPgFar.sel, pThis->DataPgFar.off, + pThis->pbCodePg, pThis->CodePgFar.sel, pThis->CodePgFar.off)); + + /* + * Create basic context for each target ring. + * + * In protected 16-bit code we need set up code selectors that can access + * pbCodePg. + * + * In long mode we make sure the high 32-bits of GPRs (sans RSP) have some + * bits set so we can check that the implicit clearing is tested. + */ + Bs3RegCtxSaveEx(&pThis->aInitialCtxs[pThis->iFirstRing], bMode, 1024 * 3); +#if ARCH_BITS == 64 + pThis->aInitialCtxs[pThis->iFirstRing].rax.u |= UINT64_C(0x0101010100000000); + pThis->aInitialCtxs[pThis->iFirstRing].rbx.u |= UINT64_C(0x0202020200000000); + pThis->aInitialCtxs[pThis->iFirstRing].rcx.u |= UINT64_C(0x0303030300000000); + pThis->aInitialCtxs[pThis->iFirstRing].rdx.u |= UINT64_C(0x0404040400000000); + pThis->aInitialCtxs[pThis->iFirstRing].rbp.u |= UINT64_C(0x0505050500000000); + pThis->aInitialCtxs[pThis->iFirstRing].rdi.u |= UINT64_C(0x0606060600000000); + pThis->aInitialCtxs[pThis->iFirstRing].rsi.u |= UINT64_C(0x0707070700000000); + pThis->aInitialCtxs[pThis->iFirstRing].r8.u |= UINT64_C(0x0808080800000000); + pThis->aInitialCtxs[pThis->iFirstRing].r9.u |= UINT64_C(0x0909090900000000); + pThis->aInitialCtxs[pThis->iFirstRing].r10.u |= UINT64_C(0x1010101000000000); + pThis->aInitialCtxs[pThis->iFirstRing].r11.u |= UINT64_C(0x1111111100000000); + pThis->aInitialCtxs[pThis->iFirstRing].r12.u |= UINT64_C(0x1212121200000000); + pThis->aInitialCtxs[pThis->iFirstRing].r13.u |= UINT64_C(0x1313131300000000); + pThis->aInitialCtxs[pThis->iFirstRing].r14.u |= UINT64_C(0x1414141400000000); + pThis->aInitialCtxs[pThis->iFirstRing].r15.u |= UINT64_C(0x1515151500000000); +#endif + + if (BS3_MODE_IS_RM_OR_V86(bMode)) + { + pThis->aInitialCtxs[pThis->iFirstRing].cs = pThis->CodePgFar.sel; + BS3_ASSERT(pThis->iFirstRing + 1 == pThis->iEndRing); + } + else if (BS3_MODE_IS_16BIT_CODE(bMode)) + { +#if ARCH_BITS == 16 + uintptr_t const uFlatCodePgSeg = Bs3SelPtrToFlat(BS3_FP_MAKE(BS3_FP_SEG(pThis->pbCodePg), 0)); +#else + uintptr_t const uFlatCodePgSeg = (uintptr_t)pThis->pbCodePg; +#endif + for (iRing = pThis->iFirstRing + 1; iRing < pThis->iEndRing; iRing++) + { + Bs3MemCpy(&pThis->aInitialCtxs[iRing], &pThis->aInitialCtxs[pThis->iFirstRing], sizeof(pThis->aInitialCtxs[iRing])); + Bs3RegCtxConvertToRingX(&pThis->aInitialCtxs[iRing], iRing); + } + for (iRing = pThis->iFirstRing; iRing < pThis->iEndRing; iRing++) + { + pThis->aInitialCtxs[iRing].cs = BS3_SEL_SPARE_00 + iRing * 8 + iRing; + Bs3SelSetup16BitCode(&Bs3GdteSpare00 + iRing, uFlatCodePgSeg, iRing); + } + } + else + { + Bs3RegCtxSetRipCsFromCurPtr(&pThis->aInitialCtxs[pThis->iFirstRing], (FPFNBS3FAR)pThis->pbCodePg); + for (iRing = pThis->iFirstRing + 1; iRing < pThis->iEndRing; iRing++) + { + Bs3MemCpy(&pThis->aInitialCtxs[iRing], &pThis->aInitialCtxs[pThis->iFirstRing], sizeof(pThis->aInitialCtxs[iRing])); + Bs3RegCtxConvertToRingX(&pThis->aInitialCtxs[iRing], iRing); + } + } + + /* + * Create an initial extended CPU context. + */ + pExtCtx = pThis->pInitialExtCtx; + if ( pExtCtx->enmMethod == BS3EXTCTXMETHOD_FXSAVE + || pExtCtx->enmMethod == BS3EXTCTXMETHOD_XSAVE) + { + pExtCtx->Ctx.x87.FCW = X86_FCW_MASK_ALL | X86_FCW_PC_64 | X86_FCW_RC_NEAREST; + pExtCtx->Ctx.x87.FSW = 0; + pExtCtx->Ctx.x87.MXCSR = X86_MXCSR_IM | X86_MXCSR_DM | X86_MXCSR_RC_NEAREST; + pExtCtx->Ctx.x87.MXCSR_MASK = 0; + for (i = 0; i < RT_ELEMENTS(pExtCtx->Ctx.x87.aRegs); i++) + { + pExtCtx->Ctx.x87.aRegs[i].au16[0] = i << 4; + pExtCtx->Ctx.x87.aRegs[i].au16[1] = i << 4; + pExtCtx->Ctx.x87.aRegs[i].au16[2] = i << 4; + pExtCtx->Ctx.x87.aRegs[i].au16[3] = i << 4; + } + for (i = 0; i < RT_ELEMENTS(pExtCtx->Ctx.x87.aXMM); i++) + { + pExtCtx->Ctx.x87.aXMM[i].au16[0] = i | UINT16_C(0x8f00); + pExtCtx->Ctx.x87.aXMM[i].au16[1] = i | UINT16_C(0x8e00); + pExtCtx->Ctx.x87.aXMM[i].au16[2] = i | UINT16_C(0x8d00); + pExtCtx->Ctx.x87.aXMM[i].au16[3] = i | UINT16_C(0x8c00); + pExtCtx->Ctx.x87.aXMM[i].au16[4] = i | UINT16_C(0x8b00); + pExtCtx->Ctx.x87.aXMM[i].au16[5] = i | UINT16_C(0x8a00); + pExtCtx->Ctx.x87.aXMM[i].au16[6] = i | UINT16_C(0x8900); + pExtCtx->Ctx.x87.aXMM[i].au16[7] = i | UINT16_C(0x8800); + } + if (pExtCtx->fXcr0Nominal & XSAVE_C_YMM) + for (i = 0; i < RT_ELEMENTS(pExtCtx->Ctx.x.u.YmmHi.aYmmHi); i++) + { + pExtCtx->Ctx.x.u.YmmHi.aYmmHi[i].au16[0] = (i << 8) | (i << 12) | 0xff; + pExtCtx->Ctx.x.u.YmmHi.aYmmHi[i].au16[1] = (i << 8) | (i << 12) | 0xfe; + pExtCtx->Ctx.x.u.YmmHi.aYmmHi[i].au16[2] = (i << 8) | (i << 12) | 0xfd; + pExtCtx->Ctx.x.u.YmmHi.aYmmHi[i].au16[3] = (i << 8) | (i << 12) | 0xfc; + pExtCtx->Ctx.x.u.YmmHi.aYmmHi[i].au16[4] = (i << 8) | (i << 12) | 0xfb; + pExtCtx->Ctx.x.u.YmmHi.aYmmHi[i].au16[5] = (i << 8) | (i << 12) | 0xfa; + pExtCtx->Ctx.x.u.YmmHi.aYmmHi[i].au16[6] = (i << 8) | (i << 12) | 0xf9; + pExtCtx->Ctx.x.u.YmmHi.aYmmHi[i].au16[7] = (i << 8) | (i << 12) | 0xf8; + } + + } + //else if (pExtCtx->enmMethod == BS3EXTCTXMETHOD_ANCIENT) + else + return Bs3TestFailedF("Unsupported extended CPU context method: %d", pExtCtx->enmMethod); + + return true; +} + + +static uint8_t BS3_NEAR_CODE BS3_CMN_NM(Bs3Cg1WorkerInner)(PBS3CG1STATE pThis) +{ + uint8_t iRing; + unsigned iInstr; + + /* + * Test the instructions. + */ + for (iInstr = 0; iInstr < g_cBs3Cg1Instructions; + iInstr++, + pThis->pchMnemonic += pThis->fAdvanceMnemonic * pThis->cchMnemonic, + pThis->pabOperands += pThis->cOperands, + pThis->pabOpcodes += pThis->cbOpcodes) + { + uint8_t const bTestXcptExpected = BS3_MODE_IS_PAGED(pThis->bMode) ? X86_XCPT_PF : X86_XCPT_UD; + bool fOuterInvalidInstr = false; + unsigned iCpuSetup; + + /* + * Expand the instruction information into the state. + * Note! 16-bit will switch to a two level test header lookup once we exceed 64KB. + */ + PCBS3CG1INSTR pInstr = &g_aBs3Cg1Instructions[iInstr]; + pThis->iInstr = iInstr; + pThis->pTestHdr = (PCBS3CG1TESTHDR)&g_abBs3Cg1Tests[pInstr->offTests]; + pThis->fFlags = pInstr->fFlags; + pThis->enmEncoding = (BS3CG1ENC)pInstr->enmEncoding; + pThis->enmEncodingNonInvalid = (BS3CG1ENC)pInstr->enmEncoding; + pThis->enmCpuTest = (BS3CG1CPU)pInstr->enmCpuTest; + pThis->enmPrefixKind = (BS3CG1PFXKIND)pInstr->enmPrefixKind; + pThis->enmXcptType = (BS3CG1XCPTTYPE)pInstr->enmXcptType; + pThis->cchMnemonic = pInstr->cchMnemonic; + if (pThis->fAdvanceMnemonic) + Bs3TestSubF("%s / %.*s", pThis->pszModeShort, pThis->cchMnemonic, pThis->pchMnemonic); + pThis->fAdvanceMnemonic = pInstr->fAdvanceMnemonic; + pThis->uOpcodeMap = pInstr->uOpcodeMap; + pThis->cOperands = pInstr->cOperands; + pThis->cbOpcodes = pInstr->cbOpcodes; + switch (pThis->cOperands) + { + case 4: pThis->aenmOperands[3] = (BS3CG1OP)pThis->pabOperands[3]; + case 3: pThis->aenmOperands[2] = (BS3CG1OP)pThis->pabOperands[2]; + case 2: pThis->aenmOperands[1] = (BS3CG1OP)pThis->pabOperands[1]; + case 1: pThis->aenmOperands[0] = (BS3CG1OP)pThis->pabOperands[0]; + } + switch (pThis->cbOpcodes) + { + case 4: pThis->abOpcodes[3] = pThis->pabOpcodes[3]; + case 3: pThis->abOpcodes[2] = pThis->pabOpcodes[2]; + case 2: pThis->abOpcodes[1] = pThis->pabOpcodes[1]; + case 1: pThis->abOpcodes[0] = pThis->pabOpcodes[0]; + } + + /* + * Check if the CPU supports the instruction. + */ + pThis->fCpuSetupFirstResult = Bs3Cg1CpuSetupFirst(pThis); + if ( !pThis->fCpuSetupFirstResult + || (pThis->fFlags & (BS3CG1INSTR_F_UNUSED | BS3CG1INSTR_F_INVALID))) + fOuterInvalidInstr = true; + + /* Switch the encoder for some of the invalid instructions on non-intel CPUs. */ + if ( (pThis->fFlags & BS3CG1INSTR_F_INTEL_DECODES_INVALID) + && pThis->bCpuVendor != BS3CPUVENDOR_INTEL + && ( (pThis->fFlags & (BS3CG1INSTR_F_UNUSED | BS3CG1INSTR_F_INVALID)) + || (BS3CG1_IS_64BIT_TARGET(pThis) && (pThis->fFlags & BS3CG1INSTR_F_INVALID_64BIT)) + || fOuterInvalidInstr ) ) + pThis->enmEncoding = Bs3Cg1CalcNoneIntelInvalidEncoding(pThis->enmEncoding); + + for (iCpuSetup = 0;; iCpuSetup++) + { + unsigned iEncoding; + unsigned iEncodingNext; + + /* + * Prep the operands and encoding handling. + */ + Bs3Cg1SetOpSizes(pThis, pThis->bMode); + if (!Bs3Cg1EncodePrep(pThis)) + break; + + /* + * Encode the instruction in various ways and check out the test values. + */ + for (iEncoding = 0;; iEncoding = iEncodingNext) + { + /* + * Encode the next instruction variation. + */ + pThis->fInvalidEncoding = fOuterInvalidInstr; + iEncodingNext = Bs3Cg1EncodeNext(pThis, iEncoding); + if (iEncodingNext <= iEncoding) + break; + BS3CG1_DPRINTF(("\ndbg: Encoding #%u: cbCurInst=%u: %.*Rhxs fInvalidEncoding=%d\n", + iEncoding, pThis->cbCurInstr, pThis->cbCurInstr, pThis->abCurInstr, pThis->fInvalidEncoding)); + + /* + * Do the rings. + */ + for (iRing = pThis->iFirstRing + pThis->fSameRingNotOkay; iRing < pThis->iEndRing; iRing++) + { + PCBS3CG1TESTHDR pHdr; + + pThis->uCpl = iRing; + BS3CG1_DPRINTF(("dbg: Ring %u\n", iRing)); + + /* + * Do the tests one by one. + */ + pHdr = pThis->pTestHdr; + for (pThis->iTest = 0;; pThis->iTest++) + { + if (Bs3Cg1RunSelector(pThis, pHdr)) + { + /* Okay, set up the execution context. */ + unsigned offCode; + uint8_t BS3_FAR *pbCode; + + Bs3MemCpy(&pThis->Ctx, &pThis->aInitialCtxs[iRing], sizeof(pThis->Ctx)); + if (pThis->fWorkExtCtx) + Bs3ExtCtxCopy(pThis->pExtCtx, pThis->pInitialExtCtx); + if (BS3_MODE_IS_PAGED(pThis->bMode)) + { + offCode = X86_PAGE_SIZE - pThis->cbCurInstr; + pbCode = &pThis->pbCodePg[offCode]; + //if (iEncoding > 0) { pbCode[-1] = 0xf4; offCode--; } + } + else + { + pbCode = pThis->pbCodePg; + pbCode[pThis->cbCurInstr] = 0x0f; /* UD2 */ + pbCode[pThis->cbCurInstr + 1] = 0x0b; + offCode = 0; + } + pThis->Ctx.rip.u = pThis->CodePgRip + offCode; + Bs3MemCpy(pbCode, pThis->abCurInstr, pThis->cbCurInstr); + + if (Bs3Cg1RunContextModifier(pThis, &pThis->Ctx, pHdr, pHdr->cbSelector, pHdr->cbInput, NULL, pbCode)) + { + /* Run the instruction. */ + BS3CG1_DPRINTF(("dbg: Running test #%u\n", pThis->iTest)); + //Bs3RegCtxPrint(&pThis->Ctx); + if (pThis->fWorkExtCtx) + Bs3ExtCtxRestore(pThis->pExtCtx); + Bs3TrapSetJmpAndRestore(&pThis->Ctx, &pThis->TrapFrame); + if (pThis->fWorkExtCtx) + Bs3ExtCtxSave(pThis->pResultExtCtx); + BS3CG1_DPRINTF(("dbg: bXcpt=%#x rip=%RX64 -> %RX64\n", + pThis->TrapFrame.bXcpt, pThis->Ctx.rip.u, pThis->TrapFrame.Ctx.rip.u)); + + /* + * Apply the output modification program to the context. + */ + pThis->Ctx.rflags.u32 &= ~X86_EFL_RF; + pThis->Ctx.rflags.u32 |= pThis->TrapFrame.Ctx.rflags.u32 & X86_EFL_RF; + pThis->bValueXcpt = UINT8_MAX; //??? + if ( pThis->fInvalidEncoding + || pThis->bAlignmentXcpt != UINT8_MAX + || pThis->bValueXcpt != UINT8_MAX + || Bs3Cg1RunContextModifier(pThis, &pThis->Ctx, pHdr, + pHdr->cbSelector + pHdr->cbInput, pHdr->cbOutput, + &pThis->TrapFrame.Ctx, NULL /*pbCode*/)) + Bs3Cg1CheckResult(pThis, bTestXcptExpected, false /*fInvalidEncodingPgFault*/, iEncoding); + else + { + Bs3TestPrintf("Bs3Cg1RunContextModifier(out): iEncoding=%u iTest=%RU32 iInstr=%u %.*s\n", + iEncoding, pThis->iTest, pThis->iInstr, pThis->cchMnemonic, pThis->pchMnemonic); + ASMHalt(); + } + + /* + * If this is an invalid encoding or instruction, check that we + * get a page fault when shortening it by one byte. + * (Since we didn't execute the output context modifier, we don't + * need to re-initialize the start context.) + */ + if ( pThis->fInvalidEncoding + && BS3_MODE_IS_PAGED(pThis->bMode) + && pThis->cbCurInstr) + { + pbCode += 1; + offCode += 1; + pThis->Ctx.rip.u = pThis->CodePgRip + offCode; + Bs3MemCpy(pbCode, pThis->abCurInstr, pThis->cbCurInstr - 1); + + /* Run the instruction. */ + BS3CG1_DPRINTF(("dbg: Running test #%u (cut short #PF)\n", pThis->iTest)); + //Bs3RegCtxPrint(&pThis->Ctx); + if (pThis->fWorkExtCtx) + Bs3ExtCtxRestore(pThis->pExtCtx); + Bs3TrapSetJmpAndRestore(&pThis->Ctx, &pThis->TrapFrame); + if (pThis->fWorkExtCtx) + Bs3ExtCtxSave(pThis->pResultExtCtx); + BS3CG1_DPRINTF(("dbg: bXcpt=%#x rip=%RX64 -> %RX64 (cut short #PF)\n", + pThis->TrapFrame.bXcpt, pThis->Ctx.rip.u, pThis->TrapFrame.Ctx.rip.u)); + + /* Check it */ + pThis->Ctx.rflags.u32 &= ~X86_EFL_RF; + pThis->Ctx.rflags.u32 |= pThis->TrapFrame.Ctx.rflags.u32 & X86_EFL_RF; + Bs3Cg1CheckResult(pThis, X86_XCPT_PF, true /*fInvalidEncodingPgFault*/, iEncoding); + } + } + else + { + Bs3TestPrintf("Bs3Cg1RunContextModifier(in): iEncoding=%u iTest=%u iInstr=%RU32 %.*s\n", + iEncoding, pThis->iTest, pThis->iInstr, pThis->cchMnemonic, pThis->pchMnemonic); + ASMHalt(); + } + } + else + BS3CG1_DPRINTF(("dbg: Skipping #%u\n", pThis->iTest)); + + /* advance */ + if (pHdr->fLast) + { + BS3CG1_DPRINTF(("dbg: Last\n\n")); + break; + } + pHdr = (PCBS3CG1TESTHDR)((uint8_t BS3_FAR *)(pHdr + 1) + pHdr->cbInput + pHdr->cbOutput + pHdr->cbSelector); + } + } + } + + /* + * Clean up (segment registers, etc) and get the next CPU config. + */ + Bs3Cg1EncodeCleanup(pThis); + if (!Bs3Cg1CpuSetupNext(pThis, iCpuSetup, &fOuterInvalidInstr)) + break; + if (pThis->fFlags & (BS3CG1INSTR_F_UNUSED | BS3CG1INSTR_F_INVALID)) + fOuterInvalidInstr = true; + } + } + + return 0; +} + + +BS3_DECL_FAR(uint8_t) BS3_CMN_NM(Bs3Cg1Worker)(uint8_t bMode) +{ + uint8_t bRet = 1; + BS3CG1STATE This; + +#if 0 + /* (for debugging) */ + if (bMode != BS3_MODE_LM64) + return BS3TESTDOMODE_SKIPPED; +#endif + + if (BS3_CMN_NM(Bs3Cg1Init)(&This, bMode)) + { + bRet = BS3_CMN_NM(Bs3Cg1WorkerInner)(&This); + Bs3TestSubDone(); + } + Bs3Cg1Destroy(&This); + +#if 0 + /* (for debugging) */ + if (bMode == BS3_MODE_PPV86) + { + Bs3TestTerm(); + Bs3Shutdown(); + } +#endif + return bRet; +} + diff --git a/src/VBox/ValidationKit/bootsectors/bs3-cpu-generated-1.c b/src/VBox/ValidationKit/bootsectors/bs3-cpu-generated-1.c new file mode 100644 index 00000000..1cd65270 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3-cpu-generated-1.c @@ -0,0 +1,59 @@ +/* $Id: bs3-cpu-generated-1.c $ */ +/** @file + * BS3Kit - bs3-cpu-generated-1, 16-bit C code. + */ + +/* + * Copyright (C) 2007-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include <bs3kit.h> +#include "bs3-cpu-generated-1.h" + + +/********************************************************************************************************************************* +* Internal Functions * +*********************************************************************************************************************************/ +BS3TESTMODEBYMAX_PROTOTYPES_CMN(Bs3Cg1Worker); + + +/********************************************************************************************************************************* +* Global Variables * +*********************************************************************************************************************************/ +static const BS3TESTMODEBYMAXENTRY g_aModeTest[] = +{ + BS3TESTMODEBYMAXENTRY_CMN(NULL, Bs3Cg1Worker), +}; + + +BS3_DECL(void) Main_rm() +{ + Bs3InitAll_rm(); + Bs3TestInit("bs3-cpu-generated-1"); + + Bs3TestDoModesByMax_rm(g_aModeTest, RT_ELEMENTS(g_aModeTest)); + + Bs3TestTerm(); +} + diff --git a/src/VBox/ValidationKit/bootsectors/bs3-cpu-generated-1.h b/src/VBox/ValidationKit/bootsectors/bs3-cpu-generated-1.h new file mode 100644 index 00000000..db986ac3 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3-cpu-generated-1.h @@ -0,0 +1,805 @@ +/* $Id: bs3-cpu-generated-1.h $ */ +/** @file + * BS3Kit - bs3-cpu-generated-1, common header file. + */ + +/* + * Copyright (C) 2007-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + +#ifndef VBOX_INCLUDED_SRC_bootsectors_bs3_cpu_generated_1_h +#define VBOX_INCLUDED_SRC_bootsectors_bs3_cpu_generated_1_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <bs3kit.h> +#include <iprt/assert.h> + + +/** + * Operand details. + * + * Currently simply using the encoding from the reference manuals. + */ +typedef enum BS3CG1OP +{ + BS3CG1OP_INVALID = 0, + + BS3CG1OP_Eb, + BS3CG1OP_Ed, + BS3CG1OP_Ed_WO, + BS3CG1OP_Eq, + BS3CG1OP_Eq_WO, + BS3CG1OP_Ev, + BS3CG1OP_Qq, + BS3CG1OP_Qq_WO, + BS3CG1OP_Wss, + BS3CG1OP_Wss_WO, + BS3CG1OP_Wsd, + BS3CG1OP_Wsd_WO, + BS3CG1OP_Wps, + BS3CG1OP_Wps_WO, + BS3CG1OP_Wpd, + BS3CG1OP_Wpd_WO, + BS3CG1OP_Wdq, + BS3CG1OP_Wdq_WO, + BS3CG1OP_Wq, + BS3CG1OP_Wq_WO, + BS3CG1OP_WqZxReg_WO, + BS3CG1OP_Wx, + BS3CG1OP_Wx_WO, + + BS3CG1OP_Gb, + BS3CG1OP_Gv, + BS3CG1OP_Gv_RO, + BS3CG1OP_HssHi, + BS3CG1OP_HsdHi, + BS3CG1OP_HqHi, + BS3CG1OP_Nq, + BS3CG1OP_Pd, + BS3CG1OP_PdZx_WO, + BS3CG1OP_Pq, + BS3CG1OP_Pq_WO, + BS3CG1OP_Uq, + BS3CG1OP_UqHi, + BS3CG1OP_Uss, + BS3CG1OP_Uss_WO, + BS3CG1OP_Usd, + BS3CG1OP_Usd_WO, + BS3CG1OP_Vd, + BS3CG1OP_Vd_WO, + BS3CG1OP_VdZx_WO, + BS3CG1OP_Vss, + BS3CG1OP_Vss_WO, + BS3CG1OP_VssZx_WO, + BS3CG1OP_Vsd, + BS3CG1OP_Vsd_WO, + BS3CG1OP_VsdZx_WO, + BS3CG1OP_Vps, + BS3CG1OP_Vps_WO, + BS3CG1OP_Vpd, + BS3CG1OP_Vpd_WO, + BS3CG1OP_Vq, + BS3CG1OP_Vq_WO, + BS3CG1OP_Vdq, + BS3CG1OP_Vdq_WO, + BS3CG1OP_VqHi, + BS3CG1OP_VqHi_WO, + BS3CG1OP_VqZx_WO, + BS3CG1OP_Vx, + BS3CG1OP_Vx_WO, + + BS3CG1OP_Ib, + BS3CG1OP_Iz, + + BS3CG1OP_AL, + BS3CG1OP_rAX, + + BS3CG1OP_Ma, + BS3CG1OP_Mb_RO, + BS3CG1OP_Md, + BS3CG1OP_Md_RO, + BS3CG1OP_Md_WO, + BS3CG1OP_Mdq, + BS3CG1OP_Mdq_WO, + BS3CG1OP_Mq, + BS3CG1OP_Mq_WO, + BS3CG1OP_Mps_WO, + BS3CG1OP_Mpd_WO, + BS3CG1OP_Mx, + BS3CG1OP_Mx_WO, + + BS3CG1OP_END +} BS3CG1OP; +/** Pointer to a const operand enum. */ +typedef const BS3CG1OP BS3_FAR *PCBS3CG1OP; + + +/** + * Instruction encoding format. + * + * This duplicates some of the info in the operand array, however it makes it + * easier to figure out encoding variations. + */ +typedef enum BS3CG1ENC +{ + BS3CG1ENC_INVALID = 0, + + BS3CG1ENC_MODRM_Eb_Gb, + BS3CG1ENC_MODRM_Ev_Gv, + BS3CG1ENC_MODRM_Ed_WO_Pd_WZ, + BS3CG1ENC_MODRM_Eq_WO_Pq_WNZ, + BS3CG1ENC_MODRM_Ed_WO_Vd_WZ, + BS3CG1ENC_MODRM_Eq_WO_Vq_WNZ, + BS3CG1ENC_MODRM_Pq_WO_Qq, + BS3CG1ENC_MODRM_Wss_WO_Vss, + BS3CG1ENC_MODRM_Wsd_WO_Vsd, + BS3CG1ENC_MODRM_Wps_WO_Vps, + BS3CG1ENC_MODRM_Wpd_WO_Vpd, + BS3CG1ENC_MODRM_WqZxReg_WO_Vq, + + BS3CG1ENC_MODRM_Gb_Eb, + BS3CG1ENC_MODRM_Gv_Ev, + BS3CG1ENC_MODRM_Gv_RO_Ma, /**< bound instruction */ + BS3CG1ENC_MODRM_Pq_WO_Uq, + BS3CG1ENC_MODRM_PdZx_WO_Ed_WZ, + BS3CG1ENC_MODRM_Pq_WO_Eq_WNZ, + BS3CG1ENC_MODRM_VdZx_WO_Ed_WZ, + BS3CG1ENC_MODRM_Vq_WO_UqHi, + BS3CG1ENC_MODRM_Vq_WO_Mq, + BS3CG1ENC_MODRM_VqHi_WO_Uq, + BS3CG1ENC_MODRM_VqHi_WO_Mq, + BS3CG1ENC_MODRM_VqZx_WO_Eq_WNZ, + BS3CG1ENC_MODRM_Vdq_WO_Mdq, + BS3CG1ENC_MODRM_Vdq_WO_Wdq, + BS3CG1ENC_MODRM_Vpd_WO_Wpd, + BS3CG1ENC_MODRM_Vps_WO_Wps, + BS3CG1ENC_MODRM_VssZx_WO_Wss, + BS3CG1ENC_MODRM_VsdZx_WO_Wsd, + BS3CG1ENC_MODRM_VqZx_WO_Wq, + BS3CG1ENC_MODRM_VqZx_WO_Nq, + BS3CG1ENC_MODRM_Mb_RO, + BS3CG1ENC_MODRM_Md_RO, + BS3CG1ENC_MODRM_Md_WO, + BS3CG1ENC_MODRM_Mdq_WO_Vdq, + BS3CG1ENC_MODRM_Mq_WO_Pq, + BS3CG1ENC_MODRM_Mq_WO_Vq, + BS3CG1ENC_MODRM_Mq_WO_VqHi, + BS3CG1ENC_MODRM_Mps_WO_Vps, + BS3CG1ENC_MODRM_Mpd_WO_Vpd, + + BS3CG1ENC_VEX_MODRM_Vd_WO_Ed_WZ, + BS3CG1ENC_VEX_MODRM_Vps_WO_Wps, + BS3CG1ENC_VEX_MODRM_Vpd_WO_Wpd, + BS3CG1ENC_VEX_MODRM_Vss_WO_HssHi_Uss, + BS3CG1ENC_VEX_MODRM_Vsd_WO_HsdHi_Usd, + BS3CG1ENC_VEX_MODRM_Vq_WO_Eq_WNZ, + BS3CG1ENC_VEX_MODRM_Vq_WO_HqHi_UqHi, + BS3CG1ENC_VEX_MODRM_Vq_WO_HqHi_Mq, + BS3CG1ENC_VEX_MODRM_Vq_WO_Wq, + BS3CG1ENC_VEX_MODRM_VssZx_WO_Md, + BS3CG1ENC_VEX_MODRM_VsdZx_WO_Mq, + BS3CG1ENC_VEX_MODRM_Vx_WO_Mx_L0, + BS3CG1ENC_VEX_MODRM_Vx_WO_Mx_L1, + BS3CG1ENC_VEX_MODRM_Vx_WO_Wx, + BS3CG1ENC_VEX_MODRM_Ed_WO_Vd_WZ, + BS3CG1ENC_VEX_MODRM_Eq_WO_Vq_WNZ, + BS3CG1ENC_VEX_MODRM_Md_WO, + BS3CG1ENC_VEX_MODRM_Mq_WO_Vq, + BS3CG1ENC_VEX_MODRM_Md_WO_Vss, + BS3CG1ENC_VEX_MODRM_Mq_WO_Vsd, + BS3CG1ENC_VEX_MODRM_Mps_WO_Vps, + BS3CG1ENC_VEX_MODRM_Mpd_WO_Vpd, + BS3CG1ENC_VEX_MODRM_Mx_WO_Vx, + BS3CG1ENC_VEX_MODRM_Uss_WO_HssHi_Vss, + BS3CG1ENC_VEX_MODRM_Usd_WO_HsdHi_Vsd, + BS3CG1ENC_VEX_MODRM_Wps_WO_Vps, + BS3CG1ENC_VEX_MODRM_Wpd_WO_Vpd, + BS3CG1ENC_VEX_MODRM_Wq_WO_Vq, + BS3CG1ENC_VEX_MODRM_Wx_WO_Vx, + + BS3CG1ENC_FIXED, + BS3CG1ENC_FIXED_AL_Ib, + BS3CG1ENC_FIXED_rAX_Iz, + + + BS3CG1ENC_MODRM_MOD_EQ_3, /**< Unused or invalid instruction. */ + BS3CG1ENC_MODRM_MOD_NE_3, /**< Unused or invalid instruction. */ + //BS3CG1ENC_VEX_FIXED, /**< Unused or invalid instruction. */ + BS3CG1ENC_VEX_MODRM_MOD_EQ_3, /**< Unused or invalid instruction. */ + BS3CG1ENC_VEX_MODRM_MOD_NE_3, /**< Unused or invalid instruction. */ + BS3CG1ENC_VEX_MODRM, /**< Unused or invalid instruction. */ + + BS3CG1ENC_END +} BS3CG1ENC; + + +/** + * Prefix sensitivitiy kind. + */ +typedef enum BS3CG1PFXKIND +{ + BS3CG1PFXKIND_INVALID = 0, + + BS3CG1PFXKIND_NO_F2_F3_66, /**< No 66, F2 or F3 prefixes allowed as that would alter the meaning. */ + BS3CG1PFXKIND_REQ_F2, /**< Requires F2 (REPNE) prefix as part of the instr encoding. */ + BS3CG1PFXKIND_REQ_F3, /**< Requires F3 (REPE) prefix as part of the instr encoding. */ + BS3CG1PFXKIND_REQ_66, /**< Requires 66 (OP SIZE) prefix as part of the instr encoding. */ + + /** @todo more work to be done here... */ + BS3CG1PFXKIND_MODRM, + BS3CG1PFXKIND_MODRM_NO_OP_SIZES, + + BS3CG1PFXKIND_END +} BS3CG1PFXKIND; + +/** + * CPU selection or CPU ID. + */ +typedef enum BS3CG1CPU +{ + /** Works with an CPU. */ + BS3CG1CPU_ANY = 0, + BS3CG1CPU_GE_80186, + BS3CG1CPU_GE_80286, + BS3CG1CPU_GE_80386, + BS3CG1CPU_GE_80486, + BS3CG1CPU_GE_Pentium, + + BS3CG1CPU_MMX, + BS3CG1CPU_SSE, + BS3CG1CPU_SSE2, + BS3CG1CPU_SSE3, + BS3CG1CPU_SSE4_1, + BS3CG1CPU_AVX, + BS3CG1CPU_AVX2, + BS3CG1CPU_CLFSH, + BS3CG1CPU_CLFLUSHOPT, + + BS3CG1CPU_END +} BS3CG1CPU; + + +/** + * SSE & AVX exception types. + */ +typedef enum BS3CG1XCPTTYPE +{ + BS3CG1XCPTTYPE_NONE = 0, + /* SSE: */ + BS3CG1XCPTTYPE_1, + BS3CG1XCPTTYPE_2, + BS3CG1XCPTTYPE_3, + BS3CG1XCPTTYPE_4, + BS3CG1XCPTTYPE_4UA, + BS3CG1XCPTTYPE_5, + BS3CG1XCPTTYPE_5LZ, + BS3CG1XCPTTYPE_6, + BS3CG1XCPTTYPE_7, + BS3CG1XCPTTYPE_7LZ, + BS3CG1XCPTTYPE_8, + BS3CG1XCPTTYPE_11, + BS3CG1XCPTTYPE_12, + /* EVEX: */ + BS3CG1XCPTTYPE_E1, + BS3CG1XCPTTYPE_E1NF, + BS3CG1XCPTTYPE_E2, + BS3CG1XCPTTYPE_E3, + BS3CG1XCPTTYPE_E3NF, + BS3CG1XCPTTYPE_E4, + BS3CG1XCPTTYPE_E4NF, + BS3CG1XCPTTYPE_E5, + BS3CG1XCPTTYPE_E5NF, + BS3CG1XCPTTYPE_E6, + BS3CG1XCPTTYPE_E6NF, + BS3CG1XCPTTYPE_E7NF, + BS3CG1XCPTTYPE_E9, + BS3CG1XCPTTYPE_E9NF, + BS3CG1XCPTTYPE_E10, + BS3CG1XCPTTYPE_E11, + BS3CG1XCPTTYPE_E12, + BS3CG1XCPTTYPE_E12NF, + BS3CG1XCPTTYPE_END +} BS3CG1XCPTTYPE; +AssertCompile(BS3CG1XCPTTYPE_END <= 32); + + +/** + * Generated instruction info. + */ +typedef struct BS3CG1INSTR +{ + /** The opcode size. */ + uint32_t cbOpcodes : 2; + /** The number of operands. */ + uint32_t cOperands : 2; + /** The length of the mnemonic. */ + uint32_t cchMnemonic : 4; + /** Whether to advance the mnemonic array pointer. */ + uint32_t fAdvanceMnemonic : 1; + /** Offset into g_abBs3Cg1Tests of the first test. */ + uint32_t offTests : 23; + /** BS3CG1ENC values. */ + uint32_t enmEncoding : 10; + /** The VEX, EVEX or XOP opcode map number (VEX.mmmm). */ + uint32_t uOpcodeMap : 4; + /** BS3CG1PFXKIND values. */ + uint32_t enmPrefixKind : 4; + /** CPU test / CPU ID bit test (BS3CG1CPU). */ + uint32_t enmCpuTest : 6; + /** Exception type (BS3CG1XCPTTYPE) */ + uint32_t enmXcptType : 5; + /** Currently unused bits. */ + uint32_t uUnused : 3; + /** BS3CG1INSTR_F_XXX. */ + uint32_t fFlags; +} BS3CG1INSTR; +AssertCompileSize(BS3CG1INSTR, 12); +/** Pointer to a const instruction. */ +typedef BS3CG1INSTR const BS3_FAR *PCBS3CG1INSTR; + + +/** @name BS3CG1INSTR_F_XXX + * @{ */ +/** Defaults to SS rather than DS. */ +#define BS3CG1INSTR_F_DEF_SS UINT32_C(0x00000001) +/** Invalid instruction in 64-bit mode. */ +#define BS3CG1INSTR_F_INVALID_64BIT UINT32_C(0x00000002) +/** Unused instruction. */ +#define BS3CG1INSTR_F_UNUSED UINT32_C(0x00000004) +/** Invalid instruction. */ +#define BS3CG1INSTR_F_INVALID UINT32_C(0x00000008) +/** Only intel does full ModR/M(, ++) decoding for invalid instruction. + * Always used with BS3CG1INSTR_F_INVALID or BS3CG1INSTR_F_UNUSED. */ +#define BS3CG1INSTR_F_INTEL_DECODES_INVALID UINT32_C(0x00000010) +/** VEX.L must be zero (IEMOPHINT_VEX_L_ZERO). */ +#define BS3CG1INSTR_F_VEX_L_ZERO UINT32_C(0x00000020) +/** VEX.L is ignored (IEMOPHINT_VEX_L_IGNORED). */ +#define BS3CG1INSTR_F_VEX_L_IGNORED UINT32_C(0x00000040) +/** @} */ + + +/** + * Test header. + */ +typedef struct BS3CG1TESTHDR +{ + /** The size of the selector program in bytes. + * This is also the offset of the input context modification program. */ + uint32_t cbSelector : 8; + /** The size of the input context modification program in bytes. + * This immediately follows the selector program. */ + uint32_t cbInput : 12; + /** The size of the output context modification program in bytes. + * This immediately follows the input context modification program. The + * program takes the result of the input program as starting point. */ + uint32_t cbOutput : 11; + /** Indicates whether this is the last test or not. */ + uint32_t fLast : 1; +} BS3CG1TESTHDR; +AssertCompileSize(BS3CG1TESTHDR, 4); +/** Pointer to a const test header. */ +typedef BS3CG1TESTHDR const BS3_FAR *PCBS3CG1TESTHDR; + +/** @name Opcode format for the BS3CG1 context modifier. + * + * Used by both the input and output context programs. + * + * The most common operations are encoded as a single byte opcode followed by + * one or more immediate bytes with data. + * + * @{ */ +#define BS3CG1_CTXOP_SIZE_MASK UINT8_C(0x07) +#define BS3CG1_CTXOP_1_BYTE UINT8_C(0x00) +#define BS3CG1_CTXOP_2_BYTES UINT8_C(0x01) +#define BS3CG1_CTXOP_4_BYTES UINT8_C(0x02) +#define BS3CG1_CTXOP_8_BYTES UINT8_C(0x03) +#define BS3CG1_CTXOP_16_BYTES UINT8_C(0x04) +#define BS3CG1_CTXOP_32_BYTES UINT8_C(0x05) +#define BS3CG1_CTXOP_12_BYTES UINT8_C(0x06) +#define BS3CG1_CTXOP_SIZE_ESC UINT8_C(0x07) /**< Separate byte encoding the value size following any destination escape byte. */ + +#define BS3CG1_CTXOP_DST_MASK UINT8_C(0x18) +#define BS3CG1_CTXOP_OP1 UINT8_C(0x00) +#define BS3CG1_CTXOP_OP2 UINT8_C(0x08) +#define BS3CG1_CTXOP_EFL UINT8_C(0x10) +#define BS3CG1_CTXOP_DST_ESC UINT8_C(0x18) /**< Separate byte giving the destination follows immediately. */ + +#define BS3CG1_CTXOP_SIGN_EXT UINT8_C(0x20) /**< Whether to sign-extend (set) the immediate value. */ + +#define BS3CG1_CTXOP_OPERATOR_MASK UINT8_C(0xc0) +#define BS3CG1_CTXOP_ASSIGN UINT8_C(0x00) /**< Simple assignment operator (=) */ +#define BS3CG1_CTXOP_OR UINT8_C(0x40) /**< OR assignment operator (|=). */ +#define BS3CG1_CTXOP_AND UINT8_C(0x80) /**< AND assignment operator (&=). */ +#define BS3CG1_CTXOP_AND_INV UINT8_C(0xc0) /**< AND assignment operator of the inverted value (&~=). */ +/** @} */ + +/** + * Escaped destination values + * + * These are just uppercased versions of TestInOut.kdFields, where dots are + * replaced by underscores. + */ +typedef enum BS3CG1DST +{ + BS3CG1DST_INVALID = 0, + /* Operands. */ + BS3CG1DST_OP1, + BS3CG1DST_OP2, + BS3CG1DST_OP3, + BS3CG1DST_OP4, + /* Flags. */ + BS3CG1DST_EFL, + BS3CG1DST_EFL_UNDEF, /**< Special field only valid in output context modifiers: EFLAGS |= Value & Ouput.EFLAGS; */ + /* 8-bit GPRs. */ + BS3CG1DST_AL, + BS3CG1DST_CL, + BS3CG1DST_DL, + BS3CG1DST_BL, + BS3CG1DST_AH, + BS3CG1DST_CH, + BS3CG1DST_DH, + BS3CG1DST_BH, + BS3CG1DST_SPL, + BS3CG1DST_BPL, + BS3CG1DST_SIL, + BS3CG1DST_DIL, + BS3CG1DST_R8L, + BS3CG1DST_R9L, + BS3CG1DST_R10L, + BS3CG1DST_R11L, + BS3CG1DST_R12L, + BS3CG1DST_R13L, + BS3CG1DST_R14L, + BS3CG1DST_R15L, + /* 16-bit GPRs. */ + BS3CG1DST_AX, + BS3CG1DST_CX, + BS3CG1DST_DX, + BS3CG1DST_BX, + BS3CG1DST_SP, + BS3CG1DST_BP, + BS3CG1DST_SI, + BS3CG1DST_DI, + BS3CG1DST_R8W, + BS3CG1DST_R9W, + BS3CG1DST_R10W, + BS3CG1DST_R11W, + BS3CG1DST_R12W, + BS3CG1DST_R13W, + BS3CG1DST_R14W, + BS3CG1DST_R15W, + /* 32-bit GPRs. */ + BS3CG1DST_EAX, + BS3CG1DST_ECX, + BS3CG1DST_EDX, + BS3CG1DST_EBX, + BS3CG1DST_ESP, + BS3CG1DST_EBP, + BS3CG1DST_ESI, + BS3CG1DST_EDI, + BS3CG1DST_R8D, + BS3CG1DST_R9D, + BS3CG1DST_R10D, + BS3CG1DST_R11D, + BS3CG1DST_R12D, + BS3CG1DST_R13D, + BS3CG1DST_R14D, + BS3CG1DST_R15D, + /* 64-bit GPRs. */ + BS3CG1DST_RAX, + BS3CG1DST_RCX, + BS3CG1DST_RDX, + BS3CG1DST_RBX, + BS3CG1DST_RSP, + BS3CG1DST_RBP, + BS3CG1DST_RSI, + BS3CG1DST_RDI, + BS3CG1DST_R8, + BS3CG1DST_R9, + BS3CG1DST_R10, + BS3CG1DST_R11, + BS3CG1DST_R12, + BS3CG1DST_R13, + BS3CG1DST_R14, + BS3CG1DST_R15, + /* 16-bit, 32-bit or 64-bit registers according to operand size. */ + BS3CG1DST_OZ_RAX, + BS3CG1DST_OZ_RCX, + BS3CG1DST_OZ_RDX, + BS3CG1DST_OZ_RBX, + BS3CG1DST_OZ_RSP, + BS3CG1DST_OZ_RBP, + BS3CG1DST_OZ_RSI, + BS3CG1DST_OZ_RDI, + BS3CG1DST_OZ_R8, + BS3CG1DST_OZ_R9, + BS3CG1DST_OZ_R10, + BS3CG1DST_OZ_R11, + BS3CG1DST_OZ_R12, + BS3CG1DST_OZ_R13, + BS3CG1DST_OZ_R14, + BS3CG1DST_OZ_R15, + + /* Control registers.*/ + BS3CG1DST_CR0, + BS3CG1DST_CR4, + BS3CG1DST_XCR0, + + /* FPU registers. */ + BS3CG1DST_FPU_FIRST, + BS3CG1DST_FCW = BS3CG1DST_FPU_FIRST, + BS3CG1DST_FSW, + BS3CG1DST_FTW, + BS3CG1DST_FOP, + BS3CG1DST_FPUIP, + BS3CG1DST_FPUCS, + BS3CG1DST_FPUDP, + BS3CG1DST_FPUDS, + BS3CG1DST_MXCSR, + BS3CG1DST_ST0, + BS3CG1DST_ST1, + BS3CG1DST_ST2, + BS3CG1DST_ST3, + BS3CG1DST_ST4, + BS3CG1DST_ST5, + BS3CG1DST_ST6, + BS3CG1DST_ST7, + /* MMX registers. */ + BS3CG1DST_MM0, + BS3CG1DST_MM1, + BS3CG1DST_MM2, + BS3CG1DST_MM3, + BS3CG1DST_MM4, + BS3CG1DST_MM5, + BS3CG1DST_MM6, + BS3CG1DST_MM7, + BS3CG1DST_MM0_LO_ZX, + BS3CG1DST_MM1_LO_ZX, + BS3CG1DST_MM2_LO_ZX, + BS3CG1DST_MM3_LO_ZX, + BS3CG1DST_MM4_LO_ZX, + BS3CG1DST_MM5_LO_ZX, + BS3CG1DST_MM6_LO_ZX, + BS3CG1DST_MM7_LO_ZX, + /* SSE registers. */ + BS3CG1DST_XMM0, + BS3CG1DST_XMM1, + BS3CG1DST_XMM2, + BS3CG1DST_XMM3, + BS3CG1DST_XMM4, + BS3CG1DST_XMM5, + BS3CG1DST_XMM6, + BS3CG1DST_XMM7, + BS3CG1DST_XMM8, + BS3CG1DST_XMM9, + BS3CG1DST_XMM10, + BS3CG1DST_XMM11, + BS3CG1DST_XMM12, + BS3CG1DST_XMM13, + BS3CG1DST_XMM14, + BS3CG1DST_XMM15, + BS3CG1DST_XMM0_LO, + BS3CG1DST_XMM1_LO, + BS3CG1DST_XMM2_LO, + BS3CG1DST_XMM3_LO, + BS3CG1DST_XMM4_LO, + BS3CG1DST_XMM5_LO, + BS3CG1DST_XMM6_LO, + BS3CG1DST_XMM7_LO, + BS3CG1DST_XMM8_LO, + BS3CG1DST_XMM9_LO, + BS3CG1DST_XMM10_LO, + BS3CG1DST_XMM11_LO, + BS3CG1DST_XMM12_LO, + BS3CG1DST_XMM13_LO, + BS3CG1DST_XMM14_LO, + BS3CG1DST_XMM15_LO, + BS3CG1DST_XMM0_HI, + BS3CG1DST_XMM1_HI, + BS3CG1DST_XMM2_HI, + BS3CG1DST_XMM3_HI, + BS3CG1DST_XMM4_HI, + BS3CG1DST_XMM5_HI, + BS3CG1DST_XMM6_HI, + BS3CG1DST_XMM7_HI, + BS3CG1DST_XMM8_HI, + BS3CG1DST_XMM9_HI, + BS3CG1DST_XMM10_HI, + BS3CG1DST_XMM11_HI, + BS3CG1DST_XMM12_HI, + BS3CG1DST_XMM13_HI, + BS3CG1DST_XMM14_HI, + BS3CG1DST_XMM15_HI, + BS3CG1DST_XMM0_LO_ZX, + BS3CG1DST_XMM1_LO_ZX, + BS3CG1DST_XMM2_LO_ZX, + BS3CG1DST_XMM3_LO_ZX, + BS3CG1DST_XMM4_LO_ZX, + BS3CG1DST_XMM5_LO_ZX, + BS3CG1DST_XMM6_LO_ZX, + BS3CG1DST_XMM7_LO_ZX, + BS3CG1DST_XMM8_LO_ZX, + BS3CG1DST_XMM9_LO_ZX, + BS3CG1DST_XMM10_LO_ZX, + BS3CG1DST_XMM11_LO_ZX, + BS3CG1DST_XMM12_LO_ZX, + BS3CG1DST_XMM13_LO_ZX, + BS3CG1DST_XMM14_LO_ZX, + BS3CG1DST_XMM15_LO_ZX, + BS3CG1DST_XMM0_DW0, + BS3CG1DST_XMM1_DW0, + BS3CG1DST_XMM2_DW0, + BS3CG1DST_XMM3_DW0, + BS3CG1DST_XMM4_DW0, + BS3CG1DST_XMM5_DW0, + BS3CG1DST_XMM6_DW0, + BS3CG1DST_XMM7_DW0, + BS3CG1DST_XMM8_DW0, + BS3CG1DST_XMM9_DW0, + BS3CG1DST_XMM10_DW0, + BS3CG1DST_XMM11_DW0, + BS3CG1DST_XMM12_DW0, + BS3CG1DST_XMM13_DW0, + BS3CG1DST_XMM14_DW0, + BS3CG1DST_XMM15_DW0, + BS3CG1DST_XMM0_DW0_ZX, + BS3CG1DST_XMM1_DW0_ZX, + BS3CG1DST_XMM2_DW0_ZX, + BS3CG1DST_XMM3_DW0_ZX, + BS3CG1DST_XMM4_DW0_ZX, + BS3CG1DST_XMM5_DW0_ZX, + BS3CG1DST_XMM6_DW0_ZX, + BS3CG1DST_XMM7_DW0_ZX, + BS3CG1DST_XMM8_DW0_ZX, + BS3CG1DST_XMM9_DW0_ZX, + BS3CG1DST_XMM10_DW0_ZX, + BS3CG1DST_XMM11_DW0_ZX, + BS3CG1DST_XMM12_DW0_ZX, + BS3CG1DST_XMM13_DW0_ZX, + BS3CG1DST_XMM14_DW0_ZX, + BS3CG1DST_XMM15_DW0_ZX, + BS3CG1DST_XMM0_HI96, + BS3CG1DST_XMM1_HI96, + BS3CG1DST_XMM2_HI96, + BS3CG1DST_XMM3_HI96, + BS3CG1DST_XMM4_HI96, + BS3CG1DST_XMM5_HI96, + BS3CG1DST_XMM6_HI96, + BS3CG1DST_XMM7_HI96, + BS3CG1DST_XMM8_HI96, + BS3CG1DST_XMM9_HI96, + BS3CG1DST_XMM10_HI96, + BS3CG1DST_XMM11_HI96, + BS3CG1DST_XMM12_HI96, + BS3CG1DST_XMM13_HI96, + BS3CG1DST_XMM14_HI96, + BS3CG1DST_XMM15_HI96, + /* AVX registers. */ + BS3CG1DST_YMM0, + BS3CG1DST_YMM1, + BS3CG1DST_YMM2, + BS3CG1DST_YMM3, + BS3CG1DST_YMM4, + BS3CG1DST_YMM5, + BS3CG1DST_YMM6, + BS3CG1DST_YMM7, + BS3CG1DST_YMM8, + BS3CG1DST_YMM9, + BS3CG1DST_YMM10, + BS3CG1DST_YMM11, + BS3CG1DST_YMM12, + BS3CG1DST_YMM13, + BS3CG1DST_YMM14, + BS3CG1DST_YMM15, + + /* Special fields: */ + BS3CG1DST_SPECIAL_START, + BS3CG1DST_VALUE_XCPT = BS3CG1DST_SPECIAL_START, /**< Expected exception based on input or result. */ + + BS3CG1DST_END +} BS3CG1DST; +AssertCompile(BS3CG1DST_END <= 256); + +/** @name Selector opcode definitions. + * + * Selector programs are very simple, they are zero or more predicate tests + * that are ANDed together. If a predicate test fails, the test is skipped. + * + * One instruction is encoded as byte, where the first bit indicates what kind + * of test and the 7 remaining bits indicates which predicate to check. + * + * @{ */ +#define BS3CG1SEL_OP_KIND_MASK UINT8_C(0x01) /**< The operator part (put in lower bit to reduce switch value range). */ +#define BS3CG1SEL_OP_IS_TRUE UINT8_C(0x00) /**< Check that the predicate is true. */ +#define BS3CG1SEL_OP_IS_FALSE UINT8_C(0x01) /**< Check that the predicate is false. */ +#define BS3CG1SEL_OP_PRED_SHIFT 1 /**< Shift factor for getting/putting a BS3CG1PRED value into/from a byte. */ +/** @} */ + +/** + * Test selector predicates (values are shifted by BS3CG1SEL_OP_PRED_SHIFT). + */ +typedef enum BS3CG1PRED +{ + BS3CG1PRED_INVALID = 0, + + /* Operand size. */ + BS3CG1PRED_SIZE_O16, + BS3CG1PRED_SIZE_O32, + BS3CG1PRED_SIZE_O64, + /* VEX.L values. */ + BS3CG1PRED_VEXL_0, + BS3CG1PRED_VEXL_1, + /* Execution ring. */ + BS3CG1PRED_RING_0, + BS3CG1PRED_RING_1, + BS3CG1PRED_RING_2, + BS3CG1PRED_RING_3, + BS3CG1PRED_RING_0_THRU_2, + BS3CG1PRED_RING_1_THRU_3, + /* Basic code mode. */ + BS3CG1PRED_CODE_64BIT, + BS3CG1PRED_CODE_32BIT, + BS3CG1PRED_CODE_16BIT, + /* CPU modes. */ + BS3CG1PRED_MODE_REAL, + BS3CG1PRED_MODE_PROT, + BS3CG1PRED_MODE_LONG, + BS3CG1PRED_MODE_V86, + BS3CG1PRED_MODE_SMM, + BS3CG1PRED_MODE_VMX, + BS3CG1PRED_MODE_SVM, + /* Paging on/off */ + BS3CG1PRED_PAGING_ON, + BS3CG1PRED_PAGING_OFF, + /* CPU Vendors. */ + BS3CG1PRED_VENDOR_AMD, + BS3CG1PRED_VENDOR_INTEL, + BS3CG1PRED_VENDOR_VIA, + BS3CG1PRED_VENDOR_SHANGHAI, + + BS3CG1PRED_END +} BS3CG1PRED; + + +/** The test instructions (generated). */ +extern const BS3CG1INSTR BS3_FAR_DATA g_aBs3Cg1Instructions[]; +/** The number of test instructions (generated). */ +extern const uint16_t BS3_FAR_DATA g_cBs3Cg1Instructions; +/** The mnemonics (generated). + * Variable length sequence of mnemonics that runs in parallel to + * g_aBs3Cg1Instructions. */ +extern const char BS3_FAR_DATA g_achBs3Cg1Mnemonics[]; +/** The opcodes (generated). + * Variable length sequence of opcode bytes that runs in parallel to + * g_aBs3Cg1Instructions, advancing by BS3CG1INSTR::cbOpcodes each time. */ +extern const uint8_t BS3_FAR_DATA g_abBs3Cg1Opcodes[]; +/** The operands (generated). + * Variable length sequence of opcode values (BS3CG1OP) that runs in + * parallel to g_aBs3Cg1Instructions, advancing by BS3CG1INSTR::cOperands. */ +extern const uint8_t BS3_FAR_DATA g_abBs3Cg1Operands[]; +/** The test data that BS3CG1INSTR. + * In order to simplify generating these, we use a byte array. */ +extern const uint8_t BS3_FAR_DATA g_abBs3Cg1Tests[]; + + +#endif /* !VBOX_INCLUDED_SRC_bootsectors_bs3_cpu_generated_1_h */ + diff --git a/src/VBox/ValidationKit/bootsectors/bs3-cpu-instr-2-asm.asm b/src/VBox/ValidationKit/bootsectors/bs3-cpu-instr-2-asm.asm new file mode 100644 index 00000000..8b54d62c --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3-cpu-instr-2-asm.asm @@ -0,0 +1,62 @@ +; $Id: bs3-cpu-instr-2-asm.asm $ +;; @file +; BS3Kit - bs3-cpu-instr-2 +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + + +;********************************************************************************************************************************* +;* Header Files * +;********************************************************************************************************************************* +%include "bs3kit.mac" + + +;********************************************************************************************************************************* +;* Global Variables * +;********************************************************************************************************************************* +;BS3_BEGIN_DATA16 +;BS3_GLOBAL_DATA g_bs3CpuBasic2_ud2_FlatAddr, 4 +; dd _bs3CpuBasic2_ud2 wrt FLAT + + + +; +; CPU mode agnostic test code snippets. +; +BS3_BEGIN_TEXT16 + +BS3_PROC_BEGIN _bs3CpuInstr2_imul_bl_ud2 + imul bl +.again: + ud2 + jmp .again +BS3_PROC_END _bs3CpuInstr2_imul_bl_ud2 + + + +; +; Instantiate code templates. +; +BS3_INSTANTIATE_COMMON_TEMPLATE "bs3-cpu-instr-2-template.mac" +BS3_INSTANTIATE_TEMPLATE_WITH_WEIRD_ONES "bs3-cpu-instr-2-template.mac" + diff --git a/src/VBox/ValidationKit/bootsectors/bs3-cpu-instr-2-template.c b/src/VBox/ValidationKit/bootsectors/bs3-cpu-instr-2-template.c new file mode 100644 index 00000000..4b4b2913 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3-cpu-instr-2-template.c @@ -0,0 +1,1038 @@ +/* $Id: bs3-cpu-instr-2-template.c $ */ +/** @file + * BS3Kit - bs3-cpu-instr-2, C code template. + */ + +/* + * Copyright (C) 2007-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include <iprt/asm.h> +#include <iprt/asm-amd64-x86.h> + + + + +/********************************************************************************************************************************* +* Structures and Typedefs * +*********************************************************************************************************************************/ +#ifdef BS3_INSTANTIATING_CMN +# if ARCH_BITS == 64 +typedef struct BS3CI2FSGSBASE +{ + const char *pszDesc; + bool f64BitOperand; + FPFNBS3FAR pfnWorker; + uint8_t offWorkerUd2; + FPFNBS3FAR pfnVerifyWorker; + uint8_t offVerifyWorkerUd2; +} BS3CI2FSGSBASE; +# endif +#endif + + +/********************************************************************************************************************************* +* External Symbols * +*********************************************************************************************************************************/ +#ifdef BS3_INSTANTIATING_CMN +extern FNBS3FAR BS3_CMN_NM(bs3CpuInstr2_mul_xBX_ud2); +extern FNBS3FAR BS3_CMN_NM(bs3CpuInstr2_imul_xBX_ud2); +extern FNBS3FAR BS3_CMN_NM(bs3CpuInstr2_imul_xCX_xBX_ud2); +extern FNBS3FAR BS3_CMN_NM(bs3CpuInstr2_div_xBX_ud2); +extern FNBS3FAR BS3_CMN_NM(bs3CpuInstr2_idiv_xBX_ud2); +# if ARCH_BITS == 64 +extern FNBS3FAR BS3_CMN_NM(bs3CpuInstr2_cmpxchg16b_rdi_ud2); +extern FNBS3FAR BS3_CMN_NM(bs3CpuInstr2_lock_cmpxchg16b_rdi_ud2); +extern FNBS3FAR BS3_CMN_NM(bs3CpuInstr2_o16_cmpxchg16b_rdi_ud2); +extern FNBS3FAR BS3_CMN_NM(bs3CpuInstr2_lock_o16_cmpxchg16b_rdi_ud2); +extern FNBS3FAR BS3_CMN_NM(bs3CpuInstr2_repz_cmpxchg16b_rdi_ud2); +extern FNBS3FAR BS3_CMN_NM(bs3CpuInstr2_lock_repz_cmpxchg16b_rdi_ud2); +extern FNBS3FAR BS3_CMN_NM(bs3CpuInstr2_repnz_cmpxchg16b_rdi_ud2); +extern FNBS3FAR BS3_CMN_NM(bs3CpuInstr2_lock_repnz_cmpxchg16b_rdi_ud2); + +extern FNBS3FAR BS3_CMN_NM(bs3CpuInstr2_wrfsbase_rbx_ud2); +extern FNBS3FAR BS3_CMN_NM(bs3CpuInstr2_wrfsbase_ebx_ud2); +extern FNBS3FAR BS3_CMN_NM(bs3CpuInstr2_wrfsbase_rbx_rdfsbase_rcx_ud2); +extern FNBS3FAR BS3_CMN_NM(bs3CpuInstr2_wrfsbase_ebx_rdfsbase_ecx_ud2); + +extern FNBS3FAR BS3_CMN_NM(bs3CpuInstr2_wrgsbase_rbx_ud2); +extern FNBS3FAR BS3_CMN_NM(bs3CpuInstr2_wrgsbase_ebx_ud2); +extern FNBS3FAR BS3_CMN_NM(bs3CpuInstr2_wrgsbase_rbx_rdgsbase_rcx_ud2); +extern FNBS3FAR BS3_CMN_NM(bs3CpuInstr2_wrgsbase_ebx_rdgsbase_ecx_ud2); + +extern FNBS3FAR BS3_CMN_NM(bs3CpuInstr2_rdfsbase_rbx_ud2); +extern FNBS3FAR BS3_CMN_NM(bs3CpuInstr2_rdfsbase_ebx_ud2); +extern FNBS3FAR BS3_CMN_NM(bs3CpuInstr2_rdgsbase_rbx_ud2); +extern FNBS3FAR BS3_CMN_NM(bs3CpuInstr2_rdgsbase_ebx_ud2); +# endif +#endif + + +/********************************************************************************************************************************* +* Global Variables * +*********************************************************************************************************************************/ +#ifdef BS3_INSTANTIATING_CMN +# if ARCH_BITS == 64 +static BS3CI2FSGSBASE const s_aWrFsBaseWorkers[] = +{ + { "wrfsbase rbx", true, BS3_CMN_NM(bs3CpuInstr2_wrfsbase_rbx_ud2), 5, BS3_CMN_NM(bs3CpuInstr2_wrfsbase_rbx_rdfsbase_rcx_ud2), 13 }, + { "wrfsbase ebx", false, BS3_CMN_NM(bs3CpuInstr2_wrfsbase_ebx_ud2), 4, BS3_CMN_NM(bs3CpuInstr2_wrfsbase_ebx_rdfsbase_ecx_ud2), 10 }, +}; + +static BS3CI2FSGSBASE const s_aWrGsBaseWorkers[] = +{ + { "wrgsbase rbx", true, BS3_CMN_NM(bs3CpuInstr2_wrgsbase_rbx_ud2), 5, BS3_CMN_NM(bs3CpuInstr2_wrgsbase_rbx_rdgsbase_rcx_ud2), 13 }, + { "wrgsbase ebx", false, BS3_CMN_NM(bs3CpuInstr2_wrgsbase_ebx_ud2), 4, BS3_CMN_NM(bs3CpuInstr2_wrgsbase_ebx_rdgsbase_ecx_ud2), 10 }, +}; + +static BS3CI2FSGSBASE const s_aRdFsBaseWorkers[] = +{ + { "rdfsbase rbx", true, BS3_CMN_NM(bs3CpuInstr2_rdfsbase_rbx_ud2), 5, BS3_CMN_NM(bs3CpuInstr2_wrfsbase_rbx_rdfsbase_rcx_ud2), 13 }, + { "rdfsbase ebx", false, BS3_CMN_NM(bs3CpuInstr2_rdfsbase_ebx_ud2), 4, BS3_CMN_NM(bs3CpuInstr2_wrfsbase_ebx_rdfsbase_ecx_ud2), 10 }, +}; + +static BS3CI2FSGSBASE const s_aRdGsBaseWorkers[] = +{ + { "rdgsbase rbx", true, BS3_CMN_NM(bs3CpuInstr2_rdgsbase_rbx_ud2), 5, BS3_CMN_NM(bs3CpuInstr2_wrgsbase_rbx_rdgsbase_rcx_ud2), 13 }, + { "rdgsbase ebx", false, BS3_CMN_NM(bs3CpuInstr2_rdgsbase_ebx_ud2), 4, BS3_CMN_NM(bs3CpuInstr2_wrgsbase_ebx_rdgsbase_ecx_ud2), 10 }, +}; +# endif +#endif /* BS3_INSTANTIATING_CMN - global */ + + +/* + * Common code. + * Common code. + * Common code. + */ +#ifdef BS3_INSTANTIATING_CMN + +BS3_DECL_FAR(uint8_t) BS3_CMN_NM(bs3CpuInstr2_mul)(uint8_t bMode) +{ +#define MUL_CHECK_EFLAGS_ZERO (uint16_t)(X86_EFL_AF | X86_EFL_ZF) +#define MUL_CHECK_EFLAGS (uint16_t)(X86_EFL_CF | X86_EFL_OF | X86_EFL_SF | X86_EFL_PF) + + static const struct + { + RTCCUINTREG uInAX; + RTCCUINTREG uInBX; + RTCCUINTREG uOutDX; + RTCCUINTREG uOutAX; + uint16_t fFlags; + } s_aTests[] = + { + { 1, 1, + 0, 1, 0 }, + { 2, 2, + 0, 4, 0 }, + { RTCCUINTREG_MAX, RTCCUINTREG_MAX, + RTCCUINTREG_MAX-1, 1, X86_EFL_CF | X86_EFL_OF }, + { RTCCINTREG_MAX, RTCCINTREG_MAX, + RTCCINTREG_MAX / 2, 1, X86_EFL_CF | X86_EFL_OF }, + { 1, RTCCUINTREG_MAX, + 0, RTCCUINTREG_MAX, X86_EFL_PF | X86_EFL_SF }, + { 1, RTCCINTREG_MAX, + 0, RTCCINTREG_MAX, X86_EFL_PF }, + { 2, RTCCINTREG_MAX, + 0, RTCCUINTREG_MAX - 1, X86_EFL_SF }, + { (RTCCUINTREG)RTCCINTREG_MAX + 1, 2, + 1, 0, X86_EFL_PF | X86_EFL_CF | X86_EFL_OF }, + { (RTCCUINTREG)RTCCINTREG_MAX / 2 + 1, 3, + 0, ((RTCCUINTREG)RTCCINTREG_MAX / 2 + 1) * 3, X86_EFL_PF | X86_EFL_SF }, + }; + + BS3REGCTX Ctx; + BS3TRAPFRAME TrapFrame; + unsigned i, j, k; + + /* Ensure the structures are allocated before we sample the stack pointer. */ + Bs3MemSet(&Ctx, 0, sizeof(Ctx)); + Bs3MemSet(&TrapFrame, 0, sizeof(TrapFrame)); + + /* + * Create test context. + */ + Bs3RegCtxSaveEx(&Ctx, bMode, 512); + Bs3RegCtxSetRipCsFromCurPtr(&Ctx, BS3_CMN_NM(bs3CpuInstr2_mul_xBX_ud2)); + for (k = 0; k < 2; k++) + { + Ctx.rflags.u16 |= MUL_CHECK_EFLAGS | MUL_CHECK_EFLAGS_ZERO; + for (j = 0; j < 2; j++) + { + for (i = 0; i < RT_ELEMENTS(s_aTests); i++) + { + if (k == 0) + { + Ctx.rax.RT_CONCAT(u,ARCH_BITS) = s_aTests[i].uInAX; + Ctx.rbx.RT_CONCAT(u,ARCH_BITS) = s_aTests[i].uInBX; + } + else + { + Ctx.rax.RT_CONCAT(u,ARCH_BITS) = s_aTests[i].uInBX; + Ctx.rbx.RT_CONCAT(u,ARCH_BITS) = s_aTests[i].uInAX; + } + Bs3TrapSetJmpAndRestore(&Ctx, &TrapFrame); + if (TrapFrame.bXcpt != X86_XCPT_UD) + Bs3TestFailedF("Expected #UD got %#x", TrapFrame.bXcpt); + else if ( TrapFrame.Ctx.rax.RT_CONCAT(u,ARCH_BITS) != s_aTests[i].uOutAX + || TrapFrame.Ctx.rdx.RT_CONCAT(u,ARCH_BITS) != s_aTests[i].uOutDX + || (TrapFrame.Ctx.rflags.u16 & (MUL_CHECK_EFLAGS | MUL_CHECK_EFLAGS_ZERO)) + != (s_aTests[i].fFlags & MUL_CHECK_EFLAGS) ) + { + Bs3TestFailedF("test #%i failed: input %#" RTCCUINTREG_XFMT " * %#" RTCCUINTREG_XFMT, + i, s_aTests[i].uInAX, s_aTests[i].uInBX); + + if (TrapFrame.Ctx.rax.RT_CONCAT(u,ARCH_BITS) != s_aTests[i].uOutAX) + Bs3TestFailedF("Expected xAX = %#RX" RT_XSTR(ARCH_BITS) " got %#RX" RT_XSTR(ARCH_BITS), + s_aTests[i].uOutAX, TrapFrame.Ctx.rax.RT_CONCAT(u,ARCH_BITS)); + if (TrapFrame.Ctx.rdx.RT_CONCAT(u,ARCH_BITS) != s_aTests[i].uOutDX) + Bs3TestFailedF("Expected xDX = %#RX" RT_XSTR(ARCH_BITS) " got %#RX" RT_XSTR(ARCH_BITS), + s_aTests[i].uOutDX, TrapFrame.Ctx.rdx.RT_CONCAT(u,ARCH_BITS)); + if ( (TrapFrame.Ctx.rflags.u16 & (MUL_CHECK_EFLAGS | MUL_CHECK_EFLAGS_ZERO)) + != (s_aTests[i].fFlags & MUL_CHECK_EFLAGS) ) + Bs3TestFailedF("Expected EFLAGS = %#06RX16, got %#06RX16", s_aTests[i].fFlags & MUL_CHECK_EFLAGS, + TrapFrame.Ctx.rflags.u16 & (MUL_CHECK_EFLAGS | MUL_CHECK_EFLAGS_ZERO)); + } + } + Ctx.rflags.u16 &= ~(MUL_CHECK_EFLAGS | MUL_CHECK_EFLAGS_ZERO); + } + } + + return 0; +} + + +BS3_DECL_FAR(uint8_t) BS3_CMN_NM(bs3CpuInstr2_imul)(uint8_t bMode) +{ +#define IMUL_CHECK_EFLAGS_ZERO (uint16_t)(X86_EFL_AF | X86_EFL_ZF) +#define IMUL_CHECK_EFLAGS (uint16_t)(X86_EFL_CF | X86_EFL_OF | X86_EFL_SF | X86_EFL_PF) + static const struct + { + RTCCUINTREG uInAX; + RTCCUINTREG uInBX; + RTCCUINTREG uOutDX; + RTCCUINTREG uOutAX; + uint16_t fFlags; + } s_aTests[] = + { + /* two positive values. */ + { 1, 1, + 0, 1, 0 }, + { 2, 2, + 0, 4, 0 }, + { RTCCINTREG_MAX, RTCCINTREG_MAX, + RTCCINTREG_MAX/2, 1, X86_EFL_CF | X86_EFL_OF }, + { 1, RTCCINTREG_MAX, + 0, RTCCINTREG_MAX, X86_EFL_PF }, + { 2, RTCCINTREG_MAX, + 0, RTCCUINTREG_MAX - 1U, X86_EFL_CF | X86_EFL_OF | X86_EFL_SF }, + { 2, RTCCINTREG_MAX / 2, + 0, RTCCINTREG_MAX - 1U, 0 }, + { 2, (RTCCINTREG_MAX / 2 + 1), + 0, (RTCCUINTREG)RTCCINTREG_MAX + 1U, X86_EFL_CF | X86_EFL_OF | X86_EFL_SF | X86_EFL_PF }, + { 4, (RTCCINTREG_MAX / 2 + 1), + 1, 0, X86_EFL_CF | X86_EFL_OF | X86_EFL_PF }, + + /* negative and positive */ + { -4, 3, + -1, -12, X86_EFL_SF }, + { 32, -127, + -1, -4064, X86_EFL_SF }, + { RTCCINTREG_MIN, 1, + -1, RTCCINTREG_MIN, X86_EFL_SF | X86_EFL_PF }, + { RTCCINTREG_MIN, 2, + -1, 0, X86_EFL_CF | X86_EFL_OF | X86_EFL_PF }, + { RTCCINTREG_MIN, 3, + -2, RTCCINTREG_MIN, X86_EFL_CF | X86_EFL_OF | X86_EFL_SF | X86_EFL_PF }, + { RTCCINTREG_MIN, 4, + -2, 0, X86_EFL_CF | X86_EFL_OF | X86_EFL_PF }, + { RTCCINTREG_MIN, RTCCINTREG_MAX, + RTCCINTREG_MIN / 2, RTCCINTREG_MIN, X86_EFL_CF | X86_EFL_OF | X86_EFL_SF | X86_EFL_PF }, + { RTCCINTREG_MIN, RTCCINTREG_MAX - 1, + RTCCINTREG_MIN / 2 + 1, 0, X86_EFL_CF | X86_EFL_OF | X86_EFL_PF }, + + /* two negative values. */ + { -4, -63, + 0, 252, X86_EFL_PF }, + { RTCCINTREG_MIN, RTCCINTREG_MIN, + RTCCUINTREG_MAX / 4 + 1, 0, X86_EFL_CF | X86_EFL_OF | X86_EFL_PF }, + { RTCCINTREG_MIN, RTCCINTREG_MIN + 1, + RTCCUINTREG_MAX / 4, RTCCINTREG_MIN, X86_EFL_CF | X86_EFL_OF | X86_EFL_SF | X86_EFL_PF}, + { RTCCINTREG_MIN + 1, RTCCINTREG_MIN + 1, + RTCCUINTREG_MAX / 4, 1, X86_EFL_CF | X86_EFL_OF }, + + }; + + BS3REGCTX Ctx; + BS3TRAPFRAME TrapFrame; + unsigned i, j, k; + + /* Ensure the structures are allocated before we sample the stack pointer. */ + Bs3MemSet(&Ctx, 0, sizeof(Ctx)); + Bs3MemSet(&TrapFrame, 0, sizeof(TrapFrame)); + + /* + * Create test context. + */ + Bs3RegCtxSaveEx(&Ctx, bMode, 512); + Bs3RegCtxSetRipCsFromCurPtr(&Ctx, BS3_CMN_NM(bs3CpuInstr2_imul_xBX_ud2)); + + for (k = 0; k < 2; k++) + { + Ctx.rflags.u16 |= MUL_CHECK_EFLAGS | MUL_CHECK_EFLAGS_ZERO; + for (j = 0; j < 2; j++) + { + for (i = 0; i < RT_ELEMENTS(s_aTests); i++) + { + if (k == 0) + { + Ctx.rax.RT_CONCAT(u,ARCH_BITS) = s_aTests[i].uInAX; + Ctx.rbx.RT_CONCAT(u,ARCH_BITS) = s_aTests[i].uInBX; + } + else + { + Ctx.rax.RT_CONCAT(u,ARCH_BITS) = s_aTests[i].uInBX; + Ctx.rbx.RT_CONCAT(u,ARCH_BITS) = s_aTests[i].uInAX; + } + Bs3TrapSetJmpAndRestore(&Ctx, &TrapFrame); + if (TrapFrame.bXcpt != X86_XCPT_UD) + Bs3TestFailedF("Expected #UD got %#x", TrapFrame.bXcpt); + else if ( TrapFrame.Ctx.rax.RT_CONCAT(u,ARCH_BITS) != s_aTests[i].uOutAX + || TrapFrame.Ctx.rdx.RT_CONCAT(u,ARCH_BITS) != s_aTests[i].uOutDX + || (TrapFrame.Ctx.rflags.u16 & (IMUL_CHECK_EFLAGS | IMUL_CHECK_EFLAGS_ZERO)) + != (s_aTests[i].fFlags & IMUL_CHECK_EFLAGS) ) + { + Bs3TestFailedF("test #%i failed: input %#" RTCCUINTREG_XFMT " * %#" RTCCUINTREG_XFMT, + i, s_aTests[i].uInAX, s_aTests[i].uInBX); + + if (TrapFrame.Ctx.rax.RT_CONCAT(u,ARCH_BITS) != s_aTests[i].uOutAX) + Bs3TestFailedF("Expected xAX = %#RX" RT_XSTR(ARCH_BITS) " got %#RX" RT_XSTR(ARCH_BITS), + s_aTests[i].uOutAX, TrapFrame.Ctx.rax.RT_CONCAT(u,ARCH_BITS)); + if (TrapFrame.Ctx.rdx.RT_CONCAT(u,ARCH_BITS) != s_aTests[i].uOutDX) + Bs3TestFailedF("Expected xDX = %#RX" RT_XSTR(ARCH_BITS) " got %#RX" RT_XSTR(ARCH_BITS), + s_aTests[i].uOutDX, TrapFrame.Ctx.rdx.RT_CONCAT(u,ARCH_BITS)); + if ( (TrapFrame.Ctx.rflags.u16 & (IMUL_CHECK_EFLAGS | IMUL_CHECK_EFLAGS_ZERO)) + != (s_aTests[i].fFlags & IMUL_CHECK_EFLAGS) ) + Bs3TestFailedF("Expected EFLAGS = %#06RX16, got %#06RX16", s_aTests[i].fFlags & IMUL_CHECK_EFLAGS, + TrapFrame.Ctx.rflags.u16 & (IMUL_CHECK_EFLAGS | IMUL_CHECK_EFLAGS_ZERO)); + } + } + } + } + + /* + * Repeat for the truncating two operand version. + */ + Bs3RegCtxSetRipCsFromCurPtr(&Ctx, BS3_CMN_NM(bs3CpuInstr2_imul_xCX_xBX_ud2)); + + for (k = 0; k < 2; k++) + { + Ctx.rflags.u16 |= MUL_CHECK_EFLAGS | MUL_CHECK_EFLAGS_ZERO; + for (j = 0; j < 2; j++) + { + for (i = 0; i < RT_ELEMENTS(s_aTests); i++) + { + if (k == 0) + { + Ctx.rcx.RT_CONCAT(u,ARCH_BITS) = s_aTests[i].uInAX; + Ctx.rbx.RT_CONCAT(u,ARCH_BITS) = s_aTests[i].uInBX; + } + else + { + Ctx.rcx.RT_CONCAT(u,ARCH_BITS) = s_aTests[i].uInBX; + Ctx.rbx.RT_CONCAT(u,ARCH_BITS) = s_aTests[i].uInAX; + } + Bs3TrapSetJmpAndRestore(&Ctx, &TrapFrame); + if (TrapFrame.bXcpt != X86_XCPT_UD) + Bs3TestFailedF("Expected #UD got %#x", TrapFrame.bXcpt); + else if ( TrapFrame.Ctx.rcx.RT_CONCAT(u,ARCH_BITS) != s_aTests[i].uOutAX + || TrapFrame.Ctx.rdx.u != Ctx.rdx.u + || TrapFrame.Ctx.rbx.u != Ctx.rbx.u + || (TrapFrame.Ctx.rflags.u16 & (IMUL_CHECK_EFLAGS | IMUL_CHECK_EFLAGS_ZERO)) + != (s_aTests[i].fFlags & IMUL_CHECK_EFLAGS) ) + { + Bs3TestFailedF("test #%i failed: input %#" RTCCUINTREG_XFMT " * %#" RTCCUINTREG_XFMT, + i, s_aTests[i].uInAX, s_aTests[i].uInBX); + + if (TrapFrame.Ctx.rcx.RT_CONCAT(u,ARCH_BITS) != s_aTests[i].uOutAX) + Bs3TestFailedF("Expected xAX = %#RX" RT_XSTR(ARCH_BITS) " got %#RX" RT_XSTR(ARCH_BITS), + s_aTests[i].uOutAX, TrapFrame.Ctx.rcx.RT_CONCAT(u,ARCH_BITS)); + if ( (TrapFrame.Ctx.rflags.u16 & (IMUL_CHECK_EFLAGS | IMUL_CHECK_EFLAGS_ZERO)) + != (s_aTests[i].fFlags & IMUL_CHECK_EFLAGS) ) + Bs3TestFailedF("Expected EFLAGS = %#06RX16, got %#06RX16", s_aTests[i].fFlags & IMUL_CHECK_EFLAGS, + TrapFrame.Ctx.rflags.u16 & (IMUL_CHECK_EFLAGS | IMUL_CHECK_EFLAGS_ZERO)); + } + } + } + } + + return 0; +} + + +BS3_DECL_FAR(uint8_t) BS3_CMN_NM(bs3CpuInstr2_div)(uint8_t bMode) +{ +#define DIV_CHECK_EFLAGS (uint16_t)(X86_EFL_CF | X86_EFL_OF | X86_EFL_SF | X86_EFL_ZF | X86_EFL_AF | X86_EFL_PF) + static const struct + { + RTCCUINTREG uInDX; + RTCCUINTREG uInAX; + RTCCUINTREG uInBX; + RTCCUINTREG uOutAX; + RTCCUINTREG uOutDX; + uint8_t bXcpt; + } s_aTests[] = + { + { 0, 1, 1, + 1, 0, X86_XCPT_UD }, + { 0, 5, 2, + 2, 1, X86_XCPT_UD }, + { 0, 0, 0, + 0, 0, X86_XCPT_DE }, + { RTCCUINTREG_MAX, RTCCUINTREG_MAX, 0, + 0, 0, X86_XCPT_DE }, + { RTCCUINTREG_MAX, RTCCUINTREG_MAX, 1, + 0, 0, X86_XCPT_DE }, + { RTCCUINTREG_MAX, RTCCUINTREG_MAX, RTCCUINTREG_MAX, + 0, 0, X86_XCPT_DE }, + { RTCCUINTREG_MAX - 1, RTCCUINTREG_MAX, RTCCUINTREG_MAX, + RTCCUINTREG_MAX, RTCCUINTREG_MAX - 1, X86_XCPT_UD }, + }; + + BS3REGCTX Ctx; + BS3TRAPFRAME TrapFrame; + unsigned i, j; + + /* Ensure the structures are allocated before we sample the stack pointer. */ + Bs3MemSet(&Ctx, 0, sizeof(Ctx)); + Bs3MemSet(&TrapFrame, 0, sizeof(TrapFrame)); + + /* + * Create test context. + */ + Bs3RegCtxSaveEx(&Ctx, bMode, 512); + Bs3RegCtxSetRipCsFromCurPtr(&Ctx, BS3_CMN_NM(bs3CpuInstr2_div_xBX_ud2)); + + /* + * Do the tests twice, first with all flags set, then once again with + * flags cleared. The flags are not touched by my intel skylake CPU. + */ + Ctx.rflags.u16 |= DIV_CHECK_EFLAGS; + for (j = 0; j < 2; j++) + { + for (i = 0; i < RT_ELEMENTS(s_aTests); i++) + { + Ctx.rax.RT_CONCAT(u,ARCH_BITS) = s_aTests[i].uInAX; + Ctx.rdx.RT_CONCAT(u,ARCH_BITS) = s_aTests[i].uInDX; + Ctx.rbx.RT_CONCAT(u,ARCH_BITS) = s_aTests[i].uInBX; + Bs3TrapSetJmpAndRestore(&Ctx, &TrapFrame); + + if ( TrapFrame.bXcpt != s_aTests[i].bXcpt + || ( s_aTests[i].bXcpt == X86_XCPT_UD + ? TrapFrame.Ctx.rax.RT_CONCAT(u,ARCH_BITS) != s_aTests[i].uOutAX + || TrapFrame.Ctx.rdx.RT_CONCAT(u,ARCH_BITS) != s_aTests[i].uOutDX + || (TrapFrame.Ctx.rflags.u16 & DIV_CHECK_EFLAGS) != (Ctx.rflags.u16 & DIV_CHECK_EFLAGS) + : TrapFrame.Ctx.rax.u != Ctx.rax.u + || TrapFrame.Ctx.rdx.u != Ctx.rdx.u + || (TrapFrame.Ctx.rflags.u16 & DIV_CHECK_EFLAGS) != (Ctx.rflags.u16 & DIV_CHECK_EFLAGS) ) ) + { + Bs3TestFailedF("test #%i failed: input %#" RTCCUINTREG_XFMT ":%" RTCCUINTREG_XFMT " / %#" RTCCUINTREG_XFMT, + i, s_aTests[i].uInDX, s_aTests[i].uInAX, s_aTests[i].uInBX); + if (TrapFrame.bXcpt != s_aTests[i].bXcpt) + Bs3TestFailedF("Expected bXcpt = %#x, got %#x", s_aTests[i].bXcpt, TrapFrame.bXcpt); + if (s_aTests[i].bXcpt == X86_XCPT_UD) + { + if (TrapFrame.Ctx.rax.RT_CONCAT(u, ARCH_BITS) != s_aTests[i].uOutAX) + Bs3TestFailedF("Expected xAX = %#" RTCCUINTREG_XFMT ", got %#" RTCCUINTREG_XFMT, + s_aTests[i].uOutAX, TrapFrame.Ctx.rax.RT_CONCAT(u,ARCH_BITS)); + if (TrapFrame.Ctx.rdx.RT_CONCAT(u,ARCH_BITS) != s_aTests[i].uOutDX) + Bs3TestFailedF("Expected xDX = %#" RTCCUINTREG_XFMT ", got %#" RTCCUINTREG_XFMT, + s_aTests[i].uOutDX, TrapFrame.Ctx.rdx.RT_CONCAT(u,ARCH_BITS)); + if ((TrapFrame.Ctx.rflags.u16 & DIV_CHECK_EFLAGS) != (Ctx.rflags.u16 & DIV_CHECK_EFLAGS)) + Bs3TestFailedF("Expected EFLAGS = %#06RX16, got %#06RX16", + Ctx.rflags.u16 & DIV_CHECK_EFLAGS, TrapFrame.Ctx.rflags.u16 & DIV_CHECK_EFLAGS); + } + } + } + Ctx.rflags.u16 &= ~DIV_CHECK_EFLAGS; + } + + return 0; +} + + + +BS3_DECL_FAR(uint8_t) BS3_CMN_NM(bs3CpuInstr2_idiv)(uint8_t bMode) +{ +#define IDIV_CHECK_EFLAGS (uint16_t)(X86_EFL_CF | X86_EFL_OF | X86_EFL_SF | X86_EFL_ZF | X86_EFL_AF | X86_EFL_PF) + static const struct + { + RTCCUINTREG uInDX; + RTCCUINTREG uInAX; + RTCCUINTREG uInBX; + RTCCUINTREG uOutAX; + RTCCUINTREG uOutDX; + uint8_t bXcpt; + } s_aTests[] = + { + { 0, 0, 0, + 0, 0, X86_XCPT_DE }, + { RTCCINTREG_MAX, RTCCINTREG_MAX, 0, + 0, 0, X86_XCPT_DE }, + /* two positive values. */ + { 0, 1, 1, + 1, 0, X86_XCPT_UD }, + { 0, 5, 2, + 2, 1, X86_XCPT_UD }, + { RTCCINTREG_MAX / 2, RTCCUINTREG_MAX / 2, RTCCINTREG_MAX, + RTCCINTREG_MAX, RTCCINTREG_MAX - 1, X86_XCPT_UD }, + { RTCCINTREG_MAX / 2, RTCCUINTREG_MAX / 2 + 1, RTCCINTREG_MAX, + RTCCINTREG_MAX, RTCCINTREG_MAX - 1, X86_XCPT_DE }, + /* negative dividend, positive divisor. */ + { -1, -7, 2, + -3, -1, X86_XCPT_UD }, + { RTCCINTREG_MIN / 2 + 1, 0, RTCCINTREG_MAX, + RTCCINTREG_MIN + 2, RTCCINTREG_MIN + 2, X86_XCPT_UD }, + { RTCCINTREG_MIN / 2, 0, RTCCINTREG_MAX, + 0, 0, X86_XCPT_DE }, + /* positive dividend, negative divisor. */ + { 0, 7, -2, + -3, 1, X86_XCPT_UD }, + { RTCCINTREG_MAX / 2 + 1, RTCCINTREG_MAX, RTCCINTREG_MIN, + RTCCINTREG_MIN, RTCCINTREG_MAX, X86_XCPT_UD }, + { RTCCINTREG_MAX / 2 + 1, (RTCCUINTREG)RTCCINTREG_MAX+1, RTCCINTREG_MIN, + 0, 0, X86_XCPT_DE }, + /* negative dividend, negative divisor. */ + { -1, -7, -2, + 3, -1, X86_XCPT_UD }, + { RTCCINTREG_MIN / 2, 1, RTCCINTREG_MIN, + RTCCINTREG_MAX, RTCCINTREG_MIN + 1, X86_XCPT_UD }, + { RTCCINTREG_MIN / 2, 2, RTCCINTREG_MIN, + RTCCINTREG_MAX, RTCCINTREG_MIN + 2, X86_XCPT_UD }, + { RTCCINTREG_MIN / 2, 0, RTCCINTREG_MIN, + 0, 0, X86_XCPT_DE }, + }; + + BS3REGCTX Ctx; + BS3TRAPFRAME TrapFrame; + unsigned i, j; + + /* Ensure the structures are allocated before we sample the stack pointer. */ + Bs3MemSet(&Ctx, 0, sizeof(Ctx)); + Bs3MemSet(&TrapFrame, 0, sizeof(TrapFrame)); + + /* + * Create test context. + */ + Bs3RegCtxSaveEx(&Ctx, bMode, 512); + Bs3RegCtxSetRipCsFromCurPtr(&Ctx, BS3_CMN_NM(bs3CpuInstr2_idiv_xBX_ud2)); + + /* + * Do the tests twice, first with all flags set, then once again with + * flags cleared. The flags are not touched by my intel skylake CPU. + */ + Ctx.rflags.u16 |= IDIV_CHECK_EFLAGS; + for (j = 0; j < 2; j++) + { + for (i = 0; i < RT_ELEMENTS(s_aTests); i++) + { + Ctx.rax.RT_CONCAT(u,ARCH_BITS) = s_aTests[i].uInAX; + Ctx.rdx.RT_CONCAT(u,ARCH_BITS) = s_aTests[i].uInDX; + Ctx.rbx.RT_CONCAT(u,ARCH_BITS) = s_aTests[i].uInBX; + Bs3TrapSetJmpAndRestore(&Ctx, &TrapFrame); + + if ( TrapFrame.bXcpt != s_aTests[i].bXcpt + || ( s_aTests[i].bXcpt == X86_XCPT_UD + ? TrapFrame.Ctx.rax.RT_CONCAT(u,ARCH_BITS) != s_aTests[i].uOutAX + || TrapFrame.Ctx.rdx.RT_CONCAT(u,ARCH_BITS) != s_aTests[i].uOutDX + || (TrapFrame.Ctx.rflags.u16 & IDIV_CHECK_EFLAGS) != (Ctx.rflags.u16 & IDIV_CHECK_EFLAGS) + : TrapFrame.Ctx.rax.u != Ctx.rax.u + || TrapFrame.Ctx.rdx.u != Ctx.rdx.u + || (TrapFrame.Ctx.rflags.u16 & IDIV_CHECK_EFLAGS) != (Ctx.rflags.u16 & IDIV_CHECK_EFLAGS) ) ) + { + Bs3TestFailedF("test #%i failed: input %#" RTCCUINTREG_XFMT ":%" RTCCUINTREG_XFMT " / %#" RTCCUINTREG_XFMT, + i, s_aTests[i].uInDX, s_aTests[i].uInAX, s_aTests[i].uInBX); + if (TrapFrame.bXcpt != s_aTests[i].bXcpt) + Bs3TestFailedF("Expected bXcpt = %#x, got %#x", s_aTests[i].bXcpt, TrapFrame.bXcpt); + if (s_aTests[i].bXcpt == X86_XCPT_UD) + { + if (TrapFrame.Ctx.rax.RT_CONCAT(u, ARCH_BITS) != s_aTests[i].uOutAX) + Bs3TestFailedF("Expected xAX = %#" RTCCUINTREG_XFMT ", got %#" RTCCUINTREG_XFMT, + s_aTests[i].uOutAX, TrapFrame.Ctx.rax.RT_CONCAT(u,ARCH_BITS)); + if (TrapFrame.Ctx.rdx.RT_CONCAT(u,ARCH_BITS) != s_aTests[i].uOutDX) + Bs3TestFailedF("Expected xDX = %#" RTCCUINTREG_XFMT ", got %#" RTCCUINTREG_XFMT, + s_aTests[i].uOutDX, TrapFrame.Ctx.rdx.RT_CONCAT(u,ARCH_BITS)); + if ((TrapFrame.Ctx.rflags.u16 & IDIV_CHECK_EFLAGS) != (Ctx.rflags.u16 & IDIV_CHECK_EFLAGS)) + Bs3TestFailedF("Expected EFLAGS = %#06RX16, got %#06RX16", + Ctx.rflags.u16 & IDIV_CHECK_EFLAGS, TrapFrame.Ctx.rflags.u16 & IDIV_CHECK_EFLAGS); + } + } + } + Ctx.rflags.u16 &= ~IDIV_CHECK_EFLAGS; + } + + return 0; +} + + +# if ARCH_BITS == 64 +BS3_DECL_FAR(uint8_t) BS3_CMN_NM(bs3CpuInstr2_cmpxchg16b)(uint8_t bMode) +{ + BS3REGCTX Ctx; + BS3REGCTX ExpectCtx; + BS3TRAPFRAME TrapFrame; + RTUINT128U au128[3]; + PRTUINT128U pau128 = RT_ALIGN_PT(&au128[0], sizeof(RTUINT128U), PRTUINT128U); + bool const fSupportCX16 = RT_BOOL(ASMCpuId_ECX(1) & X86_CPUID_FEATURE_ECX_CX16); + unsigned iFlags; + unsigned offBuf; + unsigned iMatch; + unsigned iWorker; + static struct + { + bool fLocked; + uint8_t offUd2; + FNBS3FAR *pfnWorker; + } const s_aWorkers[] = + { + { false, 4, BS3_CMN_NM(bs3CpuInstr2_cmpxchg16b_rdi_ud2) }, + { false, 5, BS3_CMN_NM(bs3CpuInstr2_o16_cmpxchg16b_rdi_ud2) }, + { false, 5, BS3_CMN_NM(bs3CpuInstr2_repz_cmpxchg16b_rdi_ud2) }, + { false, 5, BS3_CMN_NM(bs3CpuInstr2_repnz_cmpxchg16b_rdi_ud2) }, + { true, 1+4, BS3_CMN_NM(bs3CpuInstr2_lock_cmpxchg16b_rdi_ud2) }, + { true, 1+5, BS3_CMN_NM(bs3CpuInstr2_lock_o16_cmpxchg16b_rdi_ud2) }, + { true, 1+5, BS3_CMN_NM(bs3CpuInstr2_lock_repz_cmpxchg16b_rdi_ud2) }, + { true, 1+5, BS3_CMN_NM(bs3CpuInstr2_lock_repnz_cmpxchg16b_rdi_ud2) }, + }; + + /* Ensure the structures are allocated before we sample the stack pointer. */ + Bs3MemSet(&Ctx, 0, sizeof(Ctx)); + Bs3MemSet(&ExpectCtx, 0, sizeof(ExpectCtx)); + Bs3MemSet(&TrapFrame, 0, sizeof(TrapFrame)); + Bs3MemSet(pau128, 0, sizeof(pau128[0]) * 2); + + /* + * Create test context. + */ + Bs3RegCtxSaveEx(&Ctx, bMode, 512); + if (!fSupportCX16) + Bs3TestPrintf("Note! CMPXCHG16B is not supported by the CPU!\n"); + + /* + * One loop with the normal variant and one with the locked one + */ + g_usBs3TestStep = 0; + for (iWorker = 0; iWorker < RT_ELEMENTS(s_aWorkers); iWorker++) + { + Bs3RegCtxSetRipCsFromCurPtr(&Ctx, s_aWorkers[iWorker].pfnWorker); + + /* + * One loop with all status flags set, and one with them clear. + */ + Ctx.rflags.u16 |= X86_EFL_STATUS_BITS; + for (iFlags = 0; iFlags < 2; iFlags++) + { + Bs3MemCpy(&ExpectCtx, &Ctx, sizeof(ExpectCtx)); + + for (offBuf = 0; offBuf < sizeof(RTUINT128U); offBuf++) + { +# define CX16_OLD_LO UINT64_C(0xabb6345dcc9c4bbd) +# define CX16_OLD_HI UINT64_C(0x7b06ea35749549ab) +# define CX16_MISMATCH_LO UINT64_C(0xbace3e3590f18981) +# define CX16_MISMATCH_HI UINT64_C(0x9b385e8bfd5b4000) +# define CX16_STORE_LO UINT64_C(0x5cbd27d251f6559b) +# define CX16_STORE_HI UINT64_C(0x17ff434ed1b54963) + + PRTUINT128U pBuf = (PRTUINT128U)&pau128->au8[offBuf]; + + ExpectCtx.rax.u = Ctx.rax.u = CX16_MISMATCH_LO; + ExpectCtx.rdx.u = Ctx.rdx.u = CX16_MISMATCH_HI; + for (iMatch = 0; iMatch < 2; iMatch++) + { + uint8_t bExpectXcpt; + pBuf->s.Lo = CX16_OLD_LO; + pBuf->s.Hi = CX16_OLD_HI; + ExpectCtx.rdi.u = Ctx.rdi.u = (uintptr_t)pBuf; + Bs3TrapSetJmpAndRestore(&Ctx, &TrapFrame); + g_usBs3TestStep++; + //Bs3TestPrintf("Test: iFlags=%d offBuf=%d iMatch=%u iWorker=%u\n", iFlags, offBuf, iMatch, iWorker); + bExpectXcpt = X86_XCPT_UD; + if (fSupportCX16) + { + if (offBuf & 15) + { + bExpectXcpt = X86_XCPT_GP; + ExpectCtx.rip.u = Ctx.rip.u; + ExpectCtx.rflags.u32 = Ctx.rflags.u32; + } + else + { + ExpectCtx.rax.u = CX16_OLD_LO; + ExpectCtx.rdx.u = CX16_OLD_HI; + if (iMatch & 1) + ExpectCtx.rflags.u32 = Ctx.rflags.u32 | X86_EFL_ZF; + else + ExpectCtx.rflags.u32 = Ctx.rflags.u32 & ~X86_EFL_ZF; + ExpectCtx.rip.u = Ctx.rip.u + s_aWorkers[iWorker].offUd2; + } + ExpectCtx.rflags.u32 |= X86_EFL_RF; + } + if ( !Bs3TestCheckRegCtxEx(&TrapFrame.Ctx, &ExpectCtx, 0 /*cbPcAdjust*/, 0 /*cbSpAdjust*/, + 0 /*fExtraEfl*/, "lm64", 0 /*idTestStep*/) + || TrapFrame.bXcpt != bExpectXcpt) + { + if (TrapFrame.bXcpt != bExpectXcpt) + Bs3TestFailedF("Expected bXcpt=#%x, got %#x (%#x)", bExpectXcpt, TrapFrame.bXcpt, TrapFrame.uErrCd); + Bs3TestFailedF("^^^ iWorker=%d iFlags=%d offBuf=%d iMatch=%u\n", iWorker, iFlags, offBuf, iMatch); + ASMHalt(); + } + + ExpectCtx.rax.u = Ctx.rax.u = CX16_OLD_LO; + ExpectCtx.rdx.u = Ctx.rdx.u = CX16_OLD_HI; + } + } + Ctx.rflags.u16 &= ~X86_EFL_STATUS_BITS; + } + } + + return 0; +} + + +static void bs3CpuInstr2_fsgsbase_ExpectUD(uint8_t bMode, PBS3REGCTX pCtx, PBS3REGCTX pExpectCtx, PBS3TRAPFRAME pTrapFrame) +{ + pCtx->rbx.u = 0; + Bs3MemCpy(pExpectCtx, pCtx, sizeof(*pExpectCtx)); + Bs3TrapSetJmpAndRestore(pCtx, pTrapFrame); + pExpectCtx->rip.u = pCtx->rip.u; + pExpectCtx->rflags.u32 |= X86_EFL_RF; + if ( !Bs3TestCheckRegCtxEx(&pTrapFrame->Ctx, pExpectCtx, 0 /*cbPcAdjust*/, 0 /*cbSpAdjust*/, 0 /*fExtraEfl*/, "lm64", + 0 /*idTestStep*/) + || pTrapFrame->bXcpt != X86_XCPT_UD) + { + Bs3TestFailedF("Expected #UD, got %#x (%#x)", pTrapFrame->bXcpt, pTrapFrame->uErrCd); + ASMHalt(); + } +} + + +static bool bs3CpuInstr2_fsgsbase_VerifyWorker(uint8_t bMode, PBS3REGCTX pCtx, PBS3REGCTX pExpectCtx, PBS3TRAPFRAME pTrapFrame, + BS3CI2FSGSBASE const *pFsGsBaseWorker, unsigned *puIter) +{ + bool fPassed = true; + unsigned iValue = 0; + static const struct + { + bool fGP; + uint64_t u64Base; + } s_aValues64[] = + { + { false, UINT64_C(0x0000000000000000) }, + { false, UINT64_C(0x0000000000000001) }, + { false, UINT64_C(0x0000000000000010) }, + { false, UINT64_C(0x0000000000000123) }, + { false, UINT64_C(0x0000000000001234) }, + { false, UINT64_C(0x0000000000012345) }, + { false, UINT64_C(0x0000000000123456) }, + { false, UINT64_C(0x0000000001234567) }, + { false, UINT64_C(0x0000000012345678) }, + { false, UINT64_C(0x0000000123456789) }, + { false, UINT64_C(0x000000123456789a) }, + { false, UINT64_C(0x00000123456789ab) }, + { false, UINT64_C(0x0000123456789abc) }, + { false, UINT64_C(0x00007ffffeefefef) }, + { false, UINT64_C(0x00007fffffffffff) }, + { true, UINT64_C(0x0000800000000000) }, + { true, UINT64_C(0x0000800000000000) }, + { true, UINT64_C(0x0000800000000333) }, + { true, UINT64_C(0x0001000000000000) }, + { true, UINT64_C(0x0012000000000000) }, + { true, UINT64_C(0x0123000000000000) }, + { true, UINT64_C(0x1234000000000000) }, + { true, UINT64_C(0xffff300000000000) }, + { true, UINT64_C(0xffff7fffffffffff) }, + { true, UINT64_C(0xffff7fffffffffff) }, + { false, UINT64_C(0xffff800000000000) }, + { false, UINT64_C(0xffffffffffeefefe) }, + { false, UINT64_C(0xffffffffffffffff) }, + { false, UINT64_C(0xffffffffffffffff) }, + { false, UINT64_C(0x00000000efefefef) }, + { false, UINT64_C(0x0000000080204060) }, + { false, UINT64_C(0x00000000ddeeffaa) }, + { false, UINT64_C(0x00000000fdecdbca) }, + { false, UINT64_C(0x000000006098456b) }, + { false, UINT64_C(0x0000000098506099) }, + { false, UINT64_C(0x00000000206950bc) }, + { false, UINT64_C(0x000000009740395d) }, + { false, UINT64_C(0x0000000064a9455e) }, + { false, UINT64_C(0x00000000d20b6eff) }, + { false, UINT64_C(0x0000000085296d46) }, + { false, UINT64_C(0x0000000007000039) }, + { false, UINT64_C(0x000000000007fe00) }, + }; + + Bs3RegCtxSetRipCsFromCurPtr(pCtx, pFsGsBaseWorker->pfnVerifyWorker); + if (pFsGsBaseWorker->f64BitOperand) + { + for (iValue = 0; iValue < RT_ELEMENTS(s_aValues64); iValue++) + { + bool const fGP = s_aValues64[iValue].fGP; + + pCtx->rbx.u = s_aValues64[iValue].u64Base; + pCtx->rcx.u = 0; + pCtx->cr4.u |= X86_CR4_FSGSBASE; + Bs3MemCpy(pExpectCtx, pCtx, sizeof(*pExpectCtx)); + Bs3TrapSetJmpAndRestore(pCtx, pTrapFrame); + pExpectCtx->rip.u = pCtx->rip.u + (!fGP ? pFsGsBaseWorker->offVerifyWorkerUd2 : 0); + pExpectCtx->rbx.u = !fGP ? 0 : s_aValues64[iValue].u64Base; + pExpectCtx->rcx.u = !fGP ? s_aValues64[iValue].u64Base : 0; + pExpectCtx->rflags.u32 |= X86_EFL_RF; + if ( !Bs3TestCheckRegCtxEx(&pTrapFrame->Ctx, pExpectCtx, 0 /*cbPcAdjust*/, 0 /*cbSpAdjust*/, + 0 /*fExtraEfl*/, "lm64", 0 /*idTestStep*/) + || (fGP && pTrapFrame->bXcpt != X86_XCPT_GP)) + { + if (fGP && pTrapFrame->bXcpt != X86_XCPT_GP) + Bs3TestFailedF("Expected #GP, got %#x (%#x)", pTrapFrame->bXcpt, pTrapFrame->uErrCd); + fPassed = false; + break; + } + } + } + else + { + for (iValue = 0; iValue < RT_ELEMENTS(s_aValues64); iValue++) + { + pCtx->rbx.u = s_aValues64[iValue].u64Base; + pCtx->rcx.u = ~s_aValues64[iValue].u64Base; + pCtx->cr4.u |= X86_CR4_FSGSBASE; + Bs3MemCpy(pExpectCtx, pCtx, sizeof(*pExpectCtx)); + Bs3TrapSetJmpAndRestore(pCtx, pTrapFrame); + pExpectCtx->rip.u = pCtx->rip.u + pFsGsBaseWorker->offVerifyWorkerUd2; + pExpectCtx->rbx.u = 0; + pExpectCtx->rcx.u = s_aValues64[iValue].u64Base & UINT64_C(0x00000000ffffffff); + pExpectCtx->rflags.u32 |= X86_EFL_RF; + if (!Bs3TestCheckRegCtxEx(&pTrapFrame->Ctx, pExpectCtx, 0 /*cbPcAdjust*/, 0 /*cbSpAdjust*/, + 0 /*fExtraEfl*/, "lm64", 0 /*idTestStep*/)) + { + fPassed = false; + break; + } + } + } + + *puIter = iValue; + return fPassed; +} + + +static void bs3CpuInstr2_rdfsbase_rdgsbase_Common(uint8_t bMode, BS3CI2FSGSBASE const *paFsGsBaseWorkers, + unsigned cFsGsBaseWorkers, uint32_t idxFsGsBaseMsr) +{ + BS3REGCTX Ctx; + BS3REGCTX ExpectCtx; + BS3TRAPFRAME TrapFrame; + unsigned iWorker; + unsigned iIter; + uint32_t uDummy; + uint32_t uStdExtFeatEbx; + bool fSupportsFsGsBase; + + ASMCpuId_Idx_ECX(7, 0, &uDummy, &uStdExtFeatEbx, &uDummy, &uDummy); + fSupportsFsGsBase = RT_BOOL(uStdExtFeatEbx & X86_CPUID_STEXT_FEATURE_EBX_FSGSBASE); + + /* Ensure the structures are allocated before we sample the stack pointer. */ + Bs3MemSet(&Ctx, 0, sizeof(Ctx)); + Bs3MemSet(&ExpectCtx, 0, sizeof(ExpectCtx)); + Bs3MemSet(&TrapFrame, 0, sizeof(TrapFrame)); + + /* + * Create test context. + */ + Bs3RegCtxSaveEx(&Ctx, bMode, 512); + + for (iWorker = 0; iWorker < cFsGsBaseWorkers; iWorker++) + { + Bs3RegCtxSetRipCsFromCurPtr(&Ctx, paFsGsBaseWorkers[iWorker].pfnWorker); + if (fSupportsFsGsBase) + { + uint64_t const uBaseAddr = ASMRdMsr(idxFsGsBaseMsr); + + /* CR4.FSGSBASE disabled -> #UD. */ + Ctx.cr4.u &= ~X86_CR4_FSGSBASE; + bs3CpuInstr2_fsgsbase_ExpectUD(bMode, &Ctx, &ExpectCtx, &TrapFrame); + + /* Read and verify existing base address. */ + Ctx.rbx.u = 0; + Ctx.cr4.u |= X86_CR4_FSGSBASE; + Bs3MemCpy(&ExpectCtx, &Ctx, sizeof(ExpectCtx)); + Bs3TrapSetJmpAndRestore(&Ctx, &TrapFrame); + ExpectCtx.rip.u = Ctx.rip.u + paFsGsBaseWorkers[iWorker].offWorkerUd2; + ExpectCtx.rbx.u = uBaseAddr; + ExpectCtx.rflags.u32 |= X86_EFL_RF; + if (!Bs3TestCheckRegCtxEx(&TrapFrame.Ctx, &ExpectCtx, 0 /*cbPcAdjust*/, 0 /*cbSpAdjust*/, 0 /*fExtraEfl*/, "lm64", + 0 /*idTestStep*/)) + { + ASMHalt(); + } + + /* Write, read and verify series of base addresses. */ + if (!bs3CpuInstr2_fsgsbase_VerifyWorker(bMode, &Ctx, &ExpectCtx, &TrapFrame, &paFsGsBaseWorkers[iWorker], &iIter)) + { + Bs3TestFailedF("^^^ %s: iWorker=%u iIter=%u\n", paFsGsBaseWorkers[iWorker].pszDesc, iWorker, iIter); + ASMHalt(); + } + + /* Restore original base address. */ + ASMWrMsr(idxFsGsBaseMsr, uBaseAddr); + + /* Clean used GPRs. */ + Ctx.rbx.u = 0; + Ctx.rcx.u = 0; + } + else + { + /* Unsupported by CPUID -> #UD. */ + Bs3TestPrintf("Note! FSGSBASE is not supported by the CPU!\n"); + bs3CpuInstr2_fsgsbase_ExpectUD(bMode, &Ctx, &ExpectCtx, &TrapFrame); + } + } +} + + +static void bs3CpuInstr2_wrfsbase_wrgsbase_Common(uint8_t bMode, BS3CI2FSGSBASE const *paFsGsBaseWorkers, + unsigned cFsGsBaseWorkers, uint32_t idxFsGsBaseMsr) +{ + BS3REGCTX Ctx; + BS3REGCTX ExpectCtx; + BS3TRAPFRAME TrapFrame; + unsigned iWorker; + unsigned iIter; + uint32_t uDummy; + uint32_t uStdExtFeatEbx; + bool fSupportsFsGsBase; + + ASMCpuId_Idx_ECX(7, 0, &uDummy, &uStdExtFeatEbx, &uDummy, &uDummy); + fSupportsFsGsBase = RT_BOOL(uStdExtFeatEbx & X86_CPUID_STEXT_FEATURE_EBX_FSGSBASE); + + /* Ensure the structures are allocated before we sample the stack pointer. */ + Bs3MemSet(&Ctx, 0, sizeof(Ctx)); + Bs3MemSet(&ExpectCtx, 0, sizeof(ExpectCtx)); + Bs3MemSet(&TrapFrame, 0, sizeof(TrapFrame)); + + /* + * Create test context. + */ + Bs3RegCtxSaveEx(&Ctx, bMode, 512); + + for (iWorker = 0; iWorker < cFsGsBaseWorkers; iWorker++) + { + Bs3RegCtxSetRipCsFromCurPtr(&Ctx, paFsGsBaseWorkers[iWorker].pfnWorker); + if (fSupportsFsGsBase) + { + uint64_t const uBaseAddr = ASMRdMsr(idxFsGsBaseMsr); + + /* CR4.FSGSBASE disabled -> #UD. */ + Ctx.cr4.u &= ~X86_CR4_FSGSBASE; + bs3CpuInstr2_fsgsbase_ExpectUD(bMode, &Ctx, &ExpectCtx, &TrapFrame); + + /* Write a base address. */ + Ctx.rbx.u = 0xa0000; + Ctx.cr4.u |= X86_CR4_FSGSBASE; + Bs3MemCpy(&ExpectCtx, &Ctx, sizeof(ExpectCtx)); + Bs3TrapSetJmpAndRestore(&Ctx, &TrapFrame); + ExpectCtx.rip.u = Ctx.rip.u + paFsGsBaseWorkers[iWorker].offWorkerUd2; + ExpectCtx.rflags.u32 |= X86_EFL_RF; + if (!Bs3TestCheckRegCtxEx(&TrapFrame.Ctx, &ExpectCtx, 0 /*cbPcAdjust*/, 0 /*cbSpAdjust*/, 0 /*fExtraEfl*/, "lm64", + 0 /*idTestStep*/)) + { + ASMHalt(); + } + + /* Write and read back series of base addresses. */ + if (!bs3CpuInstr2_fsgsbase_VerifyWorker(bMode, &Ctx, &ExpectCtx, &TrapFrame, &paFsGsBaseWorkers[iWorker], &iIter)) + { + Bs3TestFailedF("^^^ %s: iWorker=%u iIter=%u\n", paFsGsBaseWorkers[iWorker].pszDesc, iWorker, iIter); + ASMHalt(); + } + + /* Restore original base address. */ + ASMWrMsr(idxFsGsBaseMsr, uBaseAddr); + + /* Clean used GPRs. */ + Ctx.rbx.u = 0; + Ctx.rcx.u = 0; + } + else + { + /* Unsupported by CPUID -> #UD. */ + Bs3TestPrintf("Note! FSGSBASE is not supported by the CPU!\n"); + bs3CpuInstr2_fsgsbase_ExpectUD(bMode, &Ctx, &ExpectCtx, &TrapFrame); + } + } +} + + +BS3_DECL_FAR(uint8_t) BS3_CMN_NM(bs3CpuInstr2_wrfsbase)(uint8_t bMode) +{ + bs3CpuInstr2_wrfsbase_wrgsbase_Common(bMode, s_aWrFsBaseWorkers, RT_ELEMENTS(s_aWrFsBaseWorkers), MSR_K8_FS_BASE); + return 0; +} + + +BS3_DECL_FAR(uint8_t) BS3_CMN_NM(bs3CpuInstr2_wrgsbase)(uint8_t bMode) +{ + bs3CpuInstr2_wrfsbase_wrgsbase_Common(bMode, s_aWrGsBaseWorkers, RT_ELEMENTS(s_aWrGsBaseWorkers), MSR_K8_GS_BASE); + return 0; +} + + +BS3_DECL_FAR(uint8_t) BS3_CMN_NM(bs3CpuInstr2_rdfsbase)(uint8_t bMode) +{ + bs3CpuInstr2_rdfsbase_rdgsbase_Common(bMode, s_aRdFsBaseWorkers, RT_ELEMENTS(s_aRdFsBaseWorkers), MSR_K8_FS_BASE); + return 0; +} + + +BS3_DECL_FAR(uint8_t) BS3_CMN_NM(bs3CpuInstr2_rdgsbase)(uint8_t bMode) +{ + bs3CpuInstr2_rdfsbase_rdgsbase_Common(bMode, s_aRdGsBaseWorkers, RT_ELEMENTS(s_aRdGsBaseWorkers), MSR_K8_GS_BASE); + return 0; +} +# endif /* ARCH_BITS == 64 */ + + +#endif /* BS3_INSTANTIATING_CMN */ + + + +/* + * Mode specific code. + * Mode specific code. + * Mode specific code. + */ +#ifdef BS3_INSTANTIATING_MODE + + +#endif /* BS3_INSTANTIATING_MODE */ + diff --git a/src/VBox/ValidationKit/bootsectors/bs3-cpu-instr-2-template.mac b/src/VBox/ValidationKit/bootsectors/bs3-cpu-instr-2-template.mac new file mode 100644 index 00000000..b0b8abc9 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3-cpu-instr-2-template.mac @@ -0,0 +1,286 @@ +; $Id: bs3-cpu-instr-2-template.mac $ +;; @file +; BS3Kit - bs3-cpu-instr-2 assembly template. +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + + +;********************************************************************************************************************************* +;* Header Files * +;********************************************************************************************************************************* +%include "bs3kit-template-header.mac" ; setup environment + + +;********************************************************************************************************************************* +;* External Symbols * +;********************************************************************************************************************************* +TMPL_BEGIN_TEXT + + +; +; Test code snippets containing code which differs between 16-bit, 32-bit +; and 64-bit CPUs modes. +; +%ifdef BS3_INSTANTIATING_CMN + +BS3_PROC_BEGIN_CMN bs3CpuInstr2_mul_xBX_ud2, BS3_PBC_NEAR + mul xBX +.again: + ud2 + jmp .again +BS3_PROC_END_CMN bs3CpuInstr2_mul_xBX_ud2 + + +BS3_PROC_BEGIN_CMN bs3CpuInstr2_imul_xBX_ud2, BS3_PBC_NEAR + imul xBX +.again: + ud2 + jmp .again +BS3_PROC_END_CMN bs3CpuInstr2_imul_xBX_ud2 + + +BS3_PROC_BEGIN_CMN bs3CpuInstr2_imul_xCX_xBX_ud2, BS3_PBC_NEAR + imul xCX, xBX +.again: + ud2 + jmp .again +BS3_PROC_END_CMN bs3CpuInstr2_imul_xCX_xBX_ud2 + + +BS3_PROC_BEGIN_CMN bs3CpuInstr2_div_xBX_ud2, BS3_PBC_NEAR + div xBX +.again: + ud2 + jmp .again +BS3_PROC_END_CMN bs3CpuInstr2_div_xBX_ud2 + + +BS3_PROC_BEGIN_CMN bs3CpuInstr2_idiv_xBX_ud2, BS3_PBC_NEAR + idiv xBX +.again: + ud2 + jmp .again +BS3_PROC_END_CMN bs3CpuInstr2_idiv_xBX_ud2 + + + %if TMPL_BITS == 64 +BS3_PROC_BEGIN_CMN bs3CpuInstr2_cmpxchg16b_rdi_ud2, BS3_PBC_NEAR + cmpxchg16b [rdi] +.again: + ud2 + jmp .again +AssertCompile(.again - BS3_LAST_LABEL == 4) +BS3_PROC_END_CMN bs3CpuInstr2_cmpxchg16b_rdi_ud2 + + +BS3_PROC_BEGIN_CMN bs3CpuInstr2_lock_cmpxchg16b_rdi_ud2, BS3_PBC_NEAR + lock cmpxchg16b [rdi] +.again: + ud2 + jmp .again +AssertCompile(.again - BS3_LAST_LABEL == 5) +BS3_PROC_END_CMN bs3CpuInstr2_lock_cmpxchg16b_rdi_ud2 + + +BS3_PROC_BEGIN_CMN bs3CpuInstr2_o16_cmpxchg16b_rdi_ud2, BS3_PBC_NEAR + o16 cmpxchg16b [rdi] +.again: + ud2 + jmp .again +AssertCompile(.again - BS3_LAST_LABEL == 5) +BS3_PROC_END_CMN bs3CpuInstr2_o16_cmpxchg16b_rdi_ud2 + + +BS3_PROC_BEGIN_CMN bs3CpuInstr2_lock_o16_cmpxchg16b_rdi_ud2, BS3_PBC_NEAR + db 0f0h, 066h + cmpxchg16b [rdi] +.again: + ud2 + jmp .again +AssertCompile(.again - BS3_LAST_LABEL == 6) +BS3_PROC_END_CMN bs3CpuInstr2_lock_o16_cmpxchg16b_rdi_ud2 + + +BS3_PROC_BEGIN_CMN bs3CpuInstr2_repz_cmpxchg16b_rdi_ud2, BS3_PBC_NEAR + repz cmpxchg16b [rdi] +.again: + ud2 + jmp .again +AssertCompile(.again - BS3_LAST_LABEL == 5) +BS3_PROC_END_CMN bs3CpuInstr2_repz_cmpxchg16b_rdi_ud2 + + +BS3_PROC_BEGIN_CMN bs3CpuInstr2_lock_repz_cmpxchg16b_rdi_ud2, BS3_PBC_NEAR + db 0f0h, 0f3h + cmpxchg16b [rdi] +.again: + ud2 + jmp .again +AssertCompile(.again - BS3_LAST_LABEL == 6) +BS3_PROC_END_CMN bs3CpuInstr2_lock_repz_cmpxchg16b_rdi_ud2 + +BS3_PROC_BEGIN_CMN bs3CpuInstr2_repnz_cmpxchg16b_rdi_ud2, BS3_PBC_NEAR + repnz cmpxchg16b [rdi] +.again: + ud2 + jmp .again +AssertCompile(.again - BS3_LAST_LABEL == 5) +BS3_PROC_END_CMN bs3CpuInstr2_repnz_cmpxchg16b_rdi_ud2 + + +BS3_PROC_BEGIN_CMN bs3CpuInstr2_lock_repnz_cmpxchg16b_rdi_ud2, BS3_PBC_NEAR + db 0f0h, 0f2h + cmpxchg16b [rdi] +.again: + ud2 + jmp .again +AssertCompile(.again - BS3_LAST_LABEL == 6) +BS3_PROC_END_CMN bs3CpuInstr2_lock_repnz_cmpxchg16b_rdi_ud2 + + +BS3_PROC_BEGIN_CMN bs3CpuInstr2_wrfsbase_rbx_ud2, BS3_PBC_NEAR + wrfsbase rbx +.again: + ud2 + jmp .again +AssertCompile(.again - BS3_LAST_LABEL == 5) +BS3_PROC_END_CMN bs3CpuInstr2_wrfsbase_rbx_ud2 + + +BS3_PROC_BEGIN_CMN bs3CpuInstr2_wrfsbase_ebx_ud2, BS3_PBC_NEAR + wrfsbase ebx +.again: + ud2 + jmp .again +AssertCompile(.again - BS3_LAST_LABEL == 4) +BS3_PROC_END_CMN bs3CpuInstr2_wrfsbase_ebx_ud2 + + +BS3_PROC_BEGIN_CMN bs3CpuInstr2_wrgsbase_rbx_ud2, BS3_PBC_NEAR + wrgsbase rbx +.again: + ud2 + jmp .again +AssertCompile(.again - BS3_LAST_LABEL == 5) +BS3_PROC_END_CMN bs3CpuInstr2_wrgsbase_rbx_ud2 + + +BS3_PROC_BEGIN_CMN bs3CpuInstr2_wrgsbase_ebx_ud2, BS3_PBC_NEAR + wrgsbase ebx +.again: + ud2 + jmp .again +AssertCompile(.again - BS3_LAST_LABEL == 4) +BS3_PROC_END_CMN bs3CpuInstr2_wrgsbase_ebx_ud2 + + +BS3_PROC_BEGIN_CMN bs3CpuInstr2_wrfsbase_rbx_rdfsbase_rcx_ud2, BS3_PBC_NEAR + wrfsbase rbx + xor rbx, rbx + rdfsbase rcx +.again: + ud2 + jmp .again +AssertCompile(.again - BS3_LAST_LABEL == 13) +BS3_PROC_END_CMN bs3CpuInstr2_wrfsbase_rbx_rdfsbase_rcx_ud2 + + +BS3_PROC_BEGIN_CMN bs3CpuInstr2_wrfsbase_ebx_rdfsbase_ecx_ud2, BS3_PBC_NEAR + wrfsbase ebx + xor ebx, ebx + rdfsbase ecx +.again: + ud2 + jmp .again +AssertCompile(.again - BS3_LAST_LABEL == 10) +BS3_PROC_END_CMN bs3CpuInstr2_wrfsbase_ebx_rdfsbase_ecx_ud2 + + +BS3_PROC_BEGIN_CMN bs3CpuInstr2_wrgsbase_rbx_rdgsbase_rcx_ud2, BS3_PBC_NEAR + wrgsbase rbx + xor rbx, rbx + rdgsbase rcx +.again: + ud2 + jmp .again +AssertCompile(.again - BS3_LAST_LABEL == 13) +BS3_PROC_END_CMN bs3CpuInstr2_wrgsbase_rbx_rdgsbase_rcx_ud2 + + +BS3_PROC_BEGIN_CMN bs3CpuInstr2_wrgsbase_ebx_rdgsbase_ecx_ud2, BS3_PBC_NEAR + wrgsbase ebx + xor ebx, ebx + rdgsbase ecx +.again: + ud2 + jmp .again +AssertCompile(.again - BS3_LAST_LABEL == 10) +BS3_PROC_END_CMN bs3CpuInstr2_wrfgbase_ebx_rdgsbase_ecx_ud2 + + +BS3_PROC_BEGIN_CMN bs3CpuInstr2_rdfsbase_rbx_ud2, BS3_PBC_NEAR + rdfsbase rbx +.again: + ud2 + jmp .again +AssertCompile(.again - BS3_LAST_LABEL == 5) +BS3_PROC_END_CMN bs3CpuInstr2_rdfsbase_rbx_ud2 + + +BS3_PROC_BEGIN_CMN bs3CpuInstr2_rdfsbase_ebx_ud2, BS3_PBC_NEAR + rdfsbase ebx +.again: + ud2 + jmp .again +AssertCompile(.again - BS3_LAST_LABEL == 4) +BS3_PROC_END_CMN bs3CpuInstr2_rdfsbase_ebx_ud2 + + +BS3_PROC_BEGIN_CMN bs3CpuInstr2_rdgsbase_rbx_ud2, BS3_PBC_NEAR + rdgsbase rbx +.again: + ud2 + jmp .again +AssertCompile(.again - BS3_LAST_LABEL == 5) +BS3_PROC_END_CMN bs3CpuInstr2_rdgsbase_rbx_ud2 + + +BS3_PROC_BEGIN_CMN bs3CpuInstr2_rdgsbase_ebx_ud2, BS3_PBC_NEAR + rdgsbase ebx +.again: + ud2 + jmp .again +AssertCompile(.again - BS3_LAST_LABEL == 4) +BS3_PROC_END_CMN bs3CpuInstr2_rdgsbase_ebx_ud2 + + +;; @todo figure out this fudge. sigh. +times (348) db 0cch ; fudge to avoid 'rderr' during boot. + + %endif ; TMPL_BITS == 64 + + +%endif ; BS3_INSTANTIATING_CMN + +%include "bs3kit-template-footer.mac" ; reset environment + diff --git a/src/VBox/ValidationKit/bootsectors/bs3-cpu-instr-2.c b/src/VBox/ValidationKit/bootsectors/bs3-cpu-instr-2.c new file mode 100644 index 00000000..da4d12de --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3-cpu-instr-2.c @@ -0,0 +1,74 @@ +/* $Id: bs3-cpu-instr-2.c $ */ +/** @file + * BS3Kit - bs3-cpu-instr-2, 16-bit C code. + */ + +/* + * Copyright (C) 2007-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include <bs3kit.h> + + +/********************************************************************************************************************************* +* Internal Functions * +*********************************************************************************************************************************/ +BS3TESTMODE_PROTOTYPES_CMN(bs3CpuInstr2_mul); +BS3TESTMODE_PROTOTYPES_CMN(bs3CpuInstr2_imul); +BS3TESTMODE_PROTOTYPES_CMN(bs3CpuInstr2_div); +BS3TESTMODE_PROTOTYPES_CMN(bs3CpuInstr2_idiv); +BS3TESTMODE_PROTOTYPES_CMN_64(bs3CpuInstr2_cmpxchg16b); +BS3TESTMODE_PROTOTYPES_CMN_64(bs3CpuInstr2_wrfsbase); +BS3TESTMODE_PROTOTYPES_CMN_64(bs3CpuInstr2_wrgsbase); +BS3TESTMODE_PROTOTYPES_CMN_64(bs3CpuInstr2_rdfsbase); +BS3TESTMODE_PROTOTYPES_CMN_64(bs3CpuInstr2_rdgsbase); + + +/********************************************************************************************************************************* +* Global Variables * +*********************************************************************************************************************************/ +static const BS3TESTMODEENTRY g_aModeTests[] = +{ + BS3TESTMODEENTRY_CMN("mul", bs3CpuInstr2_mul), + BS3TESTMODEENTRY_CMN("imul", bs3CpuInstr2_imul), + BS3TESTMODEENTRY_CMN("div", bs3CpuInstr2_div), + BS3TESTMODEENTRY_CMN("idiv", bs3CpuInstr2_idiv), + BS3TESTMODEENTRY_CMN_64("cmpxchg16b", bs3CpuInstr2_cmpxchg16b), + BS3TESTMODEENTRY_CMN_64("wrfsbase", bs3CpuInstr2_wrfsbase), + BS3TESTMODEENTRY_CMN_64("wrgsbase", bs3CpuInstr2_wrgsbase), + BS3TESTMODEENTRY_CMN_64("rdfsbase", bs3CpuInstr2_rdfsbase), + BS3TESTMODEENTRY_CMN_64("rdgsbase", bs3CpuInstr2_rdgsbase), +}; + + +BS3_DECL(void) Main_rm() +{ + Bs3InitAll_rm(); + Bs3TestInit("bs3-cpu-instr-2"); + + Bs3TestDoModes_rm(g_aModeTests, RT_ELEMENTS(g_aModeTests)); + + Bs3TestTerm(); +} + diff --git a/src/VBox/ValidationKit/bootsectors/bs3-cpu-weird-1-asm.asm b/src/VBox/ValidationKit/bootsectors/bs3-cpu-weird-1-asm.asm new file mode 100644 index 00000000..c3eefe96 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3-cpu-weird-1-asm.asm @@ -0,0 +1,59 @@ +; $Id: bs3-cpu-weird-1-asm.asm $ +;; @file +; BS3Kit - bs3-cpu-weird-1 +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + + +;********************************************************************************************************************************* +;* Header Files * +;********************************************************************************************************************************* +%include "bs3kit.mac" + + +;********************************************************************************************************************************* +;* Global Variables * +;********************************************************************************************************************************* +BS3_BEGIN_DATA16 + + +; +; CPU mode agnostic test code snippets. +; +BS3_BEGIN_TEXT16 + + +; +; CPU mode agnostic test code snippets. +; +BS3_BEGIN_TEXT32 + + +BS3_BEGIN_TEXT16 + +;; +;; Instantiate code templates. +;; +BS3_INSTANTIATE_COMMON_TEMPLATE "bs3-cpu-weird-1-template.mac" +; BS3_INSTANTIATE_TEMPLATE_WITH_WEIRD_ONES "bs3-cpu-weird-1-template.mac" + diff --git a/src/VBox/ValidationKit/bootsectors/bs3-cpu-weird-1-template.mac b/src/VBox/ValidationKit/bootsectors/bs3-cpu-weird-1-template.mac new file mode 100644 index 00000000..ee43e8d0 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3-cpu-weird-1-template.mac @@ -0,0 +1,111 @@ +; $Id: bs3-cpu-weird-1-template.mac $ +;; @file +; BS3Kit - bs3-cpu-weird-1 assembly template. +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + + +;********************************************************************************************************************************* +;* Header Files * +;********************************************************************************************************************************* +%include "bs3kit-template-header.mac" ; setup environment + + +;********************************************************************************************************************************* +;* External Symbols * +;********************************************************************************************************************************* +TMPL_BEGIN_TEXT + + +; +; Test code snippets containing code which differs between 16-bit, 32-bit +; and 64-bit CPUs modes. +; +%ifdef BS3_INSTANTIATING_CMN + + +; +; Inhibited int 80h. +; +BS3_PROC_BEGIN_CMN bs3CpuWeird1_InhibitedInt80, BS3_PBC_NEAR + ; Load SS from stack. This instruction causes fusing. +%if TMPL_BITS != 64 + pop ss +%else + mov ss, [rsp] +%endif + ; The ring transition instruction. +BS3_GLOBAL_NAME_EX BS3_CMN_NM(bs3CpuWeird1_InhibitedInt80_int80), , 0 + int 80h + ; We shouldn't get here! +.ud2_again: + ud2 + jmp .ud2_again +BS3_PROC_END_CMN bs3CpuWeird1_InhibitedInt80 + +; +; Inhibited int 3. +; +BS3_PROC_BEGIN_CMN bs3CpuWeird1_InhibitedInt3, BS3_PBC_NEAR + ; Load SS from stack. This instruction causes fusing. +%if TMPL_BITS != 64 + pop ss +%else + mov ss, [rsp] +%endif + ; The ring transition instruction. +BS3_GLOBAL_NAME_EX BS3_CMN_NM(bs3CpuWeird1_InhibitedInt3_int3), , 0 + int 3 + ; We shouldn't get here! +.ud2_again: + ud2 + jmp .ud2_again +AssertCompile(.ud2_again - BS3_CMN_NM(bs3CpuWeird1_InhibitedInt3_int3) == 2) +BS3_PROC_END_CMN bs3CpuWeird1_InhibitedInt3 + + +; +; Inhibited int3. +; +BS3_PROC_BEGIN_CMN bs3CpuWeird1_InhibitedBp, BS3_PBC_NEAR + ; Load SS from stack. This instruction causes fusing. +%if TMPL_BITS != 64 + pop ss +%else + mov ss, [rsp] +%endif + ; The ring transition instruction. +BS3_GLOBAL_NAME_EX BS3_CMN_NM(bs3CpuWeird1_InhibitedBp_int3), , 0 + int3 + ; We shouldn't get here! +.ud2_again: + ud2 + jmp .ud2_again +AssertCompile(.ud2_again - BS3_CMN_NM(bs3CpuWeird1_InhibitedBp_int3) == 1) +BS3_PROC_END_CMN bs3CpuWeird1_InhibitedBp + + +%endif ; BS3_INSTANTIATING_CMN + +%include "bs3kit-template-footer.mac" ; reset environment + diff --git a/src/VBox/ValidationKit/bootsectors/bs3-cpu-weird-1-x0.c b/src/VBox/ValidationKit/bootsectors/bs3-cpu-weird-1-x0.c new file mode 100644 index 00000000..31f6bce2 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3-cpu-weird-1-x0.c @@ -0,0 +1,521 @@ +/* $Id: bs3-cpu-weird-1-x0.c $ */ +/** @file + * BS3Kit - bs3-cpu-weird-2, C test driver code (16-bit). + */ + +/* + * Copyright (C) 2007-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#define BS3_USE_X0_TEXT_SEG +#include <bs3kit.h> +#include <iprt/asm.h> +#include <iprt/asm-amd64-x86.h> + + +/********************************************************************************************************************************* +* Defined Constants And Macros * +*********************************************************************************************************************************/ +#undef CHECK_MEMBER +#define CHECK_MEMBER(a_szName, a_szFmt, a_Actual, a_Expected) \ + do \ + { \ + if ((a_Actual) == (a_Expected)) { /* likely */ } \ + else bs3CpuWeird1_FailedF(a_szName "=" a_szFmt " expected " a_szFmt, (a_Actual), (a_Expected)); \ + } while (0) + + +/********************************************************************************************************************************* +* External Symbols * +*********************************************************************************************************************************/ +extern FNBS3FAR bs3CpuWeird1_InhibitedInt80_c16; +extern FNBS3FAR bs3CpuWeird1_InhibitedInt80_c32; +extern FNBS3FAR bs3CpuWeird1_InhibitedInt80_c64; +extern FNBS3FAR bs3CpuWeird1_InhibitedInt80_int80_c16; +extern FNBS3FAR bs3CpuWeird1_InhibitedInt80_int80_c32; +extern FNBS3FAR bs3CpuWeird1_InhibitedInt80_int80_c64; + +extern FNBS3FAR bs3CpuWeird1_InhibitedInt3_c16; +extern FNBS3FAR bs3CpuWeird1_InhibitedInt3_c32; +extern FNBS3FAR bs3CpuWeird1_InhibitedInt3_c64; +extern FNBS3FAR bs3CpuWeird1_InhibitedInt3_int3_c16; +extern FNBS3FAR bs3CpuWeird1_InhibitedInt3_int3_c32; +extern FNBS3FAR bs3CpuWeird1_InhibitedInt3_int3_c64; + +extern FNBS3FAR bs3CpuWeird1_InhibitedBp_c16; +extern FNBS3FAR bs3CpuWeird1_InhibitedBp_c32; +extern FNBS3FAR bs3CpuWeird1_InhibitedBp_c64; +extern FNBS3FAR bs3CpuWeird1_InhibitedBp_int3_c16; +extern FNBS3FAR bs3CpuWeird1_InhibitedBp_int3_c32; +extern FNBS3FAR bs3CpuWeird1_InhibitedBp_int3_c64; + + +/********************************************************************************************************************************* +* Global Variables * +*********************************************************************************************************************************/ +static const char BS3_FAR *g_pszTestMode = (const char *)1; +static BS3CPUVENDOR g_enmCpuVendor = BS3CPUVENDOR_INTEL; +static bool g_fVME = false; +//static uint8_t g_bTestMode = 1; +//static bool g_f16BitSys = 1; + + + +/** + * Sets globals according to the mode. + * + * @param bTestMode The test mode. + */ +static void bs3CpuWeird1_SetGlobals(uint8_t bTestMode) +{ +// g_bTestMode = bTestMode; + g_pszTestMode = Bs3GetModeName(bTestMode); +// g_f16BitSys = BS3_MODE_IS_16BIT_SYS(bTestMode); + g_usBs3TestStep = 0; + g_enmCpuVendor = Bs3GetCpuVendor(); + g_fVME = (g_uBs3CpuDetected & BS3CPU_TYPE_MASK) >= BS3CPU_80486 + && (Bs3RegGetCr4() & X86_CR4_VME); +} + + +/** + * Wrapper around Bs3TestFailedF that prefixes the error with g_usBs3TestStep + * and g_pszTestMode. + */ +static void bs3CpuWeird1_FailedF(const char *pszFormat, ...) +{ + va_list va; + + char szTmp[168]; + va_start(va, pszFormat); + Bs3StrPrintfV(szTmp, sizeof(szTmp), pszFormat, va); + va_end(va); + + Bs3TestFailedF("%u - %s: %s", g_usBs3TestStep, g_pszTestMode, szTmp); +} + + +/** + * Compares interrupt stuff. + */ +static void bs3CpuWeird1_CompareDbgInhibitRingXfer(PCBS3TRAPFRAME pTrapCtx, PCBS3REGCTX pStartCtx, uint8_t bXcpt, + int8_t cbPcAdjust, int8_t cbSpAdjust, uint32_t uDr6Expected, + uint8_t cbIretFrame, uint64_t uHandlerRsp) +{ + uint32_t uDr6 = (g_uBs3CpuDetected & BS3CPU_TYPE_MASK) >= BS3CPU_80386 ? Bs3RegGetDr6() : X86_DR6_INIT_VAL; + uint16_t const cErrorsBefore = Bs3TestSubErrorCount(); + CHECK_MEMBER("bXcpt", "%#04x", pTrapCtx->bXcpt, bXcpt); + CHECK_MEMBER("bErrCd", "%#06RX64", pTrapCtx->uErrCd, 0); + CHECK_MEMBER("cbIretFrame", "%#04x", pTrapCtx->cbIretFrame, cbIretFrame); + CHECK_MEMBER("uHandlerRsp", "%#06RX64", pTrapCtx->uHandlerRsp, uHandlerRsp); + if (uDr6 != uDr6Expected) + bs3CpuWeird1_FailedF("dr6=%#010RX32 expected %#010RX32", uDr6, uDr6Expected); + Bs3TestCheckRegCtxEx(&pTrapCtx->Ctx, pStartCtx, cbPcAdjust, cbSpAdjust, 0 /*fExtraEfl*/, g_pszTestMode, g_usBs3TestStep); + if (Bs3TestSubErrorCount() != cErrorsBefore) + { + Bs3TrapPrintFrame(pTrapCtx); + Bs3TestPrintf("DR6=%#RX32; Handler: CS=%04RX16 SS:ESP=%04RX16:%08RX64 EFL=%RX64 cbIret=%#x\n", + uDr6, pTrapCtx->uHandlerCs, pTrapCtx->uHandlerSs, pTrapCtx->uHandlerRsp, + pTrapCtx->fHandlerRfl, pTrapCtx->cbIretFrame); +#if 0 + Bs3TestPrintf("Halting in CompareIntCtx: bXcpt=%#x\n", bXcpt); + ASMHalt(); +#endif + } +} + +static uint64_t bs3CpuWeird1_GetTrapHandlerEIP(uint8_t bXcpt, uint8_t bMode, bool fV86) +{ + if ( BS3_MODE_IS_RM_SYS(bMode) + || (fV86 && BS3_MODE_IS_V86(bMode))) + { + PRTFAR16 paIvt = (PRTFAR16)Bs3XptrFlatToCurrent(0); + return paIvt[bXcpt].off; + } + if (BS3_MODE_IS_16BIT_SYS(bMode)) + return Bs3Idt16[bXcpt].Gate.u16OffsetLow; + if (BS3_MODE_IS_32BIT_SYS(bMode)) + return RT_MAKE_U32(Bs3Idt32[bXcpt].Gate.u16OffsetLow, Bs3Idt32[bXcpt].Gate.u16OffsetHigh); + return RT_MAKE_U64(RT_MAKE_U32(Bs3Idt64[bXcpt].Gate.u16OffsetLow, Bs3Idt32[bXcpt].Gate.u16OffsetHigh), + Bs3Idt64[bXcpt].Gate.u32OffsetTop); +} + + +static int bs3CpuWeird1_DbgInhibitRingXfer_Worker(uint8_t bTestMode, uint8_t bIntGate, uint8_t cbRingInstr, int8_t cbSpAdjust, + FPFNBS3FAR pfnTestCode, FPFNBS3FAR pfnTestLabel) +{ + BS3TRAPFRAME TrapCtx; + BS3TRAPFRAME TrapExpect; + BS3REGCTX Ctx; + uint8_t bSavedDpl; + uint8_t const offTestLabel = BS3_FP_OFF(pfnTestLabel) - BS3_FP_OFF(pfnTestCode); + //uint8_t const cbIretFrameSame = BS3_MODE_IS_RM_SYS(bTestMode) ? 6 + // : BS3_MODE_IS_16BIT_SYS(bTestMode) ? 12 + // : BS3_MODE_IS_64BIT_SYS(bTestMode) ? 40 : 12; + uint8_t cbIretFrameInt; + uint8_t cbIretFrameIntDb; + uint8_t const cbIretFrameSame = BS3_MODE_IS_16BIT_SYS(bTestMode) ? 6 + : BS3_MODE_IS_32BIT_SYS(bTestMode) ? 12 : 40; + uint8_t const cbSpAdjSame = BS3_MODE_IS_64BIT_SYS(bTestMode) ? 48 : cbIretFrameSame; + uint8_t bVmeMethod = 0; + uint64_t uHandlerRspInt; + uint64_t uHandlerRspIntDb; + BS3_XPTR_AUTO(uint32_t, StackXptr); + + /* make sure they're allocated */ + Bs3MemZero(&Ctx, sizeof(Ctx)); + Bs3MemZero(&TrapCtx, sizeof(TrapCtx)); + Bs3MemZero(&TrapExpect, sizeof(TrapExpect)); + + /* + * Make INT xx accessible from DPL 3 and create a ring-3 context that we can work with. + */ + bSavedDpl = Bs3TrapSetDpl(bIntGate, 3); + + Bs3RegCtxSaveEx(&Ctx, bTestMode, 1024); + Bs3RegCtxSetRipCsFromLnkPtr(&Ctx, pfnTestCode); + if (BS3_MODE_IS_16BIT_SYS(bTestMode)) + g_uBs3TrapEipHint = Ctx.rip.u32; + Ctx.rflags.u32 &= ~X86_EFL_RF; + + /* Raw-mode enablers. */ + Ctx.rflags.u32 |= X86_EFL_IF; + if ((g_uBs3CpuDetected & BS3CPU_TYPE_MASK) >= BS3CPU_80486) + Ctx.cr0.u32 |= X86_CR0_WP; + + /* We put the SS value on the stack so we can easily set breakpoints there. */ + Ctx.rsp.u32 -= 8; + BS3_XPTR_SET_FLAT(uint32_t, StackXptr, Ctx.rsp.u32); /* ASSUMES SS.BASE == 0!! */ + + /* ring-3 */ + if (!BS3_MODE_IS_RM_OR_V86(bTestMode)) + Bs3RegCtxConvertToRingX(&Ctx, 3); + + /* V8086: Set IOPL to 3. */ + if (BS3_MODE_IS_V86(bTestMode)) + { + Ctx.rflags.u32 |= X86_EFL_IOPL; + if (g_fVME) + { + Bs3RegSetTr(BS3_SEL_TSS32_IRB); +#if 0 + /* SDMv3b, 20.3.3 method 5: */ + ASMBitClear(&Bs3SharedIntRedirBm, bIntGate); + bVmeMethod = 5; +#else + /* SDMv3b, 20.3.3 method 4 (similar to non-VME): */ + ASMBitSet(&Bs3SharedIntRedirBm, bIntGate); + bVmeMethod = 4; + } +#endif + } + + /* + * Test #0: Test run. Calc expected delayed #DB from it. + */ + if ((g_uBs3CpuDetected & BS3CPU_TYPE_MASK) >= BS3CPU_80386) + { + Bs3RegSetDr7(0); + Bs3RegSetDr6(X86_DR6_INIT_VAL); + } + *BS3_XPTR_GET(uint32_t, StackXptr) = Ctx.ss; + Bs3TrapSetJmpAndRestore(&Ctx, &TrapExpect); + if (TrapExpect.bXcpt != bIntGate) + { + + Bs3TestFailedF("%u: bXcpt is %#x, expected %#x!\n", g_usBs3TestStep, TrapExpect.bXcpt, bIntGate); + Bs3TrapPrintFrame(&TrapExpect); + return 1; + } + + cbIretFrameInt = TrapExpect.cbIretFrame; + cbIretFrameIntDb = cbIretFrameInt + cbIretFrameSame; + uHandlerRspInt = TrapExpect.uHandlerRsp; + uHandlerRspIntDb = uHandlerRspInt - cbSpAdjSame; + + TrapExpect.Ctx.bCpl = 0; + TrapExpect.Ctx.cs = TrapExpect.uHandlerCs; + TrapExpect.Ctx.ss = TrapExpect.uHandlerSs; + TrapExpect.Ctx.rsp.u64 = TrapExpect.uHandlerRsp; + TrapExpect.Ctx.rflags.u64 = TrapExpect.fHandlerRfl; + if (BS3_MODE_IS_V86(bTestMode)) + { + if (bVmeMethod >= 5) + { + TrapExpect.Ctx.rflags.u32 |= X86_EFL_VM; + TrapExpect.Ctx.bCpl = 3; + TrapExpect.Ctx.rip.u64 = bs3CpuWeird1_GetTrapHandlerEIP(bIntGate, bTestMode, true); + cbIretFrameIntDb = 36; + if (BS3_MODE_IS_16BIT_SYS(bTestMode)) + uHandlerRspIntDb = Bs3Tss16.sp0 - cbIretFrameIntDb; + else + uHandlerRspIntDb = Bs3Tss32.esp0 - cbIretFrameIntDb; + } + else + { + TrapExpect.Ctx.ds = 0; + TrapExpect.Ctx.es = 0; + TrapExpect.Ctx.fs = 0; + TrapExpect.Ctx.gs = 0; + } + } + + /* + * Test #1: Single stepping ring-3. Ignored except for V8086 w/ VME. + */ + g_usBs3TestStep++; + if ((g_uBs3CpuDetected & BS3CPU_TYPE_MASK) >= BS3CPU_80386) + { + Bs3RegSetDr7(0); + Bs3RegSetDr6(X86_DR6_INIT_VAL); + } + *BS3_XPTR_GET(uint32_t, StackXptr) = Ctx.ss; + Ctx.rflags.u32 |= X86_EFL_TF; + + Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx); + if ( !BS3_MODE_IS_V86(bTestMode) + || bVmeMethod < 5) + bs3CpuWeird1_CompareDbgInhibitRingXfer(&TrapCtx, &Ctx, bIntGate, offTestLabel + cbRingInstr, cbSpAdjust, + X86_DR6_INIT_VAL, cbIretFrameInt, uHandlerRspInt); + else + { + TrapExpect.Ctx.rflags.u32 |= X86_EFL_TF; + bs3CpuWeird1_CompareDbgInhibitRingXfer(&TrapCtx, &TrapExpect.Ctx, X86_XCPT_DB, offTestLabel, -2, + X86_DR6_INIT_VAL | X86_DR6_BS, cbIretFrameIntDb, uHandlerRspIntDb); + TrapExpect.Ctx.rflags.u32 &= ~X86_EFL_TF; + } + + Ctx.rflags.u32 &= ~X86_EFL_TF; + if ((g_uBs3CpuDetected & BS3CPU_TYPE_MASK) >= BS3CPU_80386) + { + uint32_t uDr6Expect; + + /* + * Test #2: Execution breakpoint on ring transition instruction. + * This hits on AMD-V (threadripper) but not on VT-x (skylake). + */ + g_usBs3TestStep++; + Bs3RegSetDr0(Bs3SelRealModeCodeToFlat(pfnTestLabel)); + Bs3RegSetDr7(X86_DR7_L0 | X86_DR7_G0 | X86_DR7_RW(0, X86_DR7_RW_EO) | X86_DR7_LEN(0, X86_DR7_LEN_BYTE)); + Bs3RegSetDr6(X86_DR6_INIT_VAL); + *BS3_XPTR_GET(uint32_t, StackXptr) = Ctx.ss; + + Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx); + Bs3RegSetDr7(0); + if (g_enmCpuVendor == BS3CPUVENDOR_AMD) + bs3CpuWeird1_CompareDbgInhibitRingXfer(&TrapCtx, &Ctx, X86_XCPT_DB, offTestLabel, cbSpAdjust, + X86_DR6_INIT_VAL | X86_DR6_B0, cbIretFrameInt, uHandlerRspInt); + else + bs3CpuWeird1_CompareDbgInhibitRingXfer(&TrapCtx, &Ctx, bIntGate, offTestLabel + cbRingInstr, cbSpAdjust, + X86_DR6_INIT_VAL, cbIretFrameInt, uHandlerRspInt); + + /* + * Test #3: Same as above, but with the LE and GE flags set. + */ + g_usBs3TestStep++; + Bs3RegSetDr0(Bs3SelRealModeCodeToFlat(pfnTestLabel)); + Bs3RegSetDr7(X86_DR7_L0 | X86_DR7_G0 | X86_DR7_RW(0, X86_DR7_RW_EO) | X86_DR7_LEN(0, X86_DR7_LEN_BYTE) | X86_DR7_LE | X86_DR7_GE); + Bs3RegSetDr6(X86_DR6_INIT_VAL); + *BS3_XPTR_GET(uint32_t, StackXptr) = Ctx.ss; + + Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx); + if (g_enmCpuVendor == BS3CPUVENDOR_AMD) + bs3CpuWeird1_CompareDbgInhibitRingXfer(&TrapCtx, &Ctx, X86_XCPT_DB, offTestLabel, cbSpAdjust, + X86_DR6_INIT_VAL | X86_DR6_B0, cbIretFrameInt, uHandlerRspInt); + else + bs3CpuWeird1_CompareDbgInhibitRingXfer(&TrapCtx, &Ctx, bIntGate, offTestLabel + cbRingInstr, cbSpAdjust, + X86_DR6_INIT_VAL, cbIretFrameInt, uHandlerRspInt); + + /* + * Test #4: Execution breakpoint on pop ss / mov ss. Hits. + * Note! In real mode AMD-V updates the stack pointer, or something else is busted. Totally weird! + */ + g_usBs3TestStep++; + Bs3RegSetDr0(Bs3SelRealModeCodeToFlat(pfnTestCode)); + Bs3RegSetDr7(X86_DR7_L0 | X86_DR7_G0 | X86_DR7_RW(0, X86_DR7_RW_EO) | X86_DR7_LEN(0, X86_DR7_LEN_BYTE)); + Bs3RegSetDr6(X86_DR6_INIT_VAL); + *BS3_XPTR_GET(uint32_t, StackXptr) = Ctx.ss; + + Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx); + bs3CpuWeird1_CompareDbgInhibitRingXfer(&TrapCtx, &Ctx, X86_XCPT_DB, 0, 0, X86_DR6_INIT_VAL | X86_DR6_B0, + cbIretFrameInt, + uHandlerRspInt - (BS3_MODE_IS_RM_SYS(bTestMode) ? 2 : 0) ); + + /* + * Test #5: Same as above, but with the LE and GE flags set. + */ + g_usBs3TestStep++; + Bs3RegSetDr0(Bs3SelRealModeCodeToFlat(pfnTestCode)); + Bs3RegSetDr7(X86_DR7_L0 | X86_DR7_G0 | X86_DR7_RW(0, X86_DR7_RW_EO) | X86_DR7_LEN(0, X86_DR7_LEN_BYTE) | X86_DR7_LE | X86_DR7_GE); + Bs3RegSetDr6(X86_DR6_INIT_VAL); + *BS3_XPTR_GET(uint32_t, StackXptr) = Ctx.ss; + + Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx); + bs3CpuWeird1_CompareDbgInhibitRingXfer(&TrapCtx, &Ctx, X86_XCPT_DB, 0, 0, X86_DR6_INIT_VAL | X86_DR6_B0, + cbIretFrameInt, + uHandlerRspInt - (BS3_MODE_IS_RM_SYS(bTestMode) ? 2 : 0) ); + + /* + * Test #6: Data breakpoint on SS load. The #DB is delivered after ring transition. Weird! + * + * Note! Intel loses the B0 status, probably for reasons similar to Pentium Pro errata 3. Similar + * erratum is seen with virtually every march since, e.g. skylake SKL009 & SKL111. + * Weirdly enougth, they seem to get this right in real mode. Go figure. + */ + g_usBs3TestStep++; + *BS3_XPTR_GET(uint32_t, StackXptr) = Ctx.ss; + Bs3RegSetDr0(BS3_XPTR_GET_FLAT(uint32_t, StackXptr)); + Bs3RegSetDr7(X86_DR7_L0 | X86_DR7_G0 | X86_DR7_RW(0, X86_DR7_RW_RW) | X86_DR7_LEN(0, X86_DR7_LEN_WORD)); + Bs3RegSetDr6(X86_DR6_INIT_VAL); + + Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx); + TrapExpect.Ctx.rip = TrapCtx.Ctx.rip; /// @todo fixme + Bs3RegSetDr7(0); + uDr6Expect = X86_DR6_INIT_VAL | X86_DR6_B0; + if (g_enmCpuVendor == BS3CPUVENDOR_INTEL && bTestMode != BS3_MODE_RM) + uDr6Expect = X86_DR6_INIT_VAL; + bs3CpuWeird1_CompareDbgInhibitRingXfer(&TrapCtx, &TrapExpect.Ctx, X86_XCPT_DB, 0, 0, uDr6Expect, + cbIretFrameSame, uHandlerRspIntDb); + + /* + * Test #7: Same as above, but with the LE and GE flags set. + */ + g_usBs3TestStep++; + *BS3_XPTR_GET(uint32_t, StackXptr) = Ctx.ss; + Bs3RegSetDr0(BS3_XPTR_GET_FLAT(uint32_t, StackXptr)); + Bs3RegSetDr7(X86_DR7_L0 | X86_DR7_G0 | X86_DR7_RW(0, X86_DR7_RW_RW) | X86_DR7_LEN(0, X86_DR7_LEN_WORD) | X86_DR7_LE | X86_DR7_GE); + Bs3RegSetDr6(X86_DR6_INIT_VAL); + + Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx); + TrapExpect.Ctx.rip = TrapCtx.Ctx.rip; /// @todo fixme + Bs3RegSetDr7(0); + uDr6Expect = X86_DR6_INIT_VAL | X86_DR6_B0; + if (g_enmCpuVendor == BS3CPUVENDOR_INTEL && bTestMode != BS3_MODE_RM) + uDr6Expect = X86_DR6_INIT_VAL; + bs3CpuWeird1_CompareDbgInhibitRingXfer(&TrapCtx, &TrapExpect.Ctx, X86_XCPT_DB, 0, 0, uDr6Expect, + cbIretFrameSame, uHandlerRspIntDb); + + if (!BS3_MODE_IS_RM_OR_V86(bTestMode)) + { + /* + * Test #8: Data breakpoint on SS GDT entry. Half weird! + * Note! Intel loses the B1 status, see test #6. + */ + g_usBs3TestStep++; + *BS3_XPTR_GET(uint32_t, StackXptr) = (Ctx.ss & X86_SEL_RPL) | BS3_SEL_SPARE_00; + Bs3GdteSpare00 = Bs3Gdt[Ctx.ss / sizeof(Bs3Gdt[0])]; + + Bs3RegSetDr1(Bs3SelPtrToFlat(&Bs3GdteSpare00)); + Bs3RegSetDr7(X86_DR7_L1 | X86_DR7_G1 | X86_DR7_RW(1, X86_DR7_RW_RW) | X86_DR7_LEN(1, X86_DR7_LEN_DWORD)); + Bs3RegSetDr6(X86_DR6_INIT_VAL); + + Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx); + TrapExpect.Ctx.rip = TrapCtx.Ctx.rip; /// @todo fixme + Bs3RegSetDr7(0); + uDr6Expect = g_enmCpuVendor == BS3CPUVENDOR_INTEL ? X86_DR6_INIT_VAL : X86_DR6_INIT_VAL | X86_DR6_B1; + bs3CpuWeird1_CompareDbgInhibitRingXfer(&TrapCtx, &TrapExpect.Ctx, X86_XCPT_DB, 0, 0, uDr6Expect, + cbIretFrameSame, uHandlerRspIntDb); + + /* + * Test #9: Same as above, but with the LE and GE flags set. + */ + g_usBs3TestStep++; + *BS3_XPTR_GET(uint32_t, StackXptr) = (Ctx.ss & X86_SEL_RPL) | BS3_SEL_SPARE_00; + Bs3GdteSpare00 = Bs3Gdt[Ctx.ss / sizeof(Bs3Gdt[0])]; + + Bs3RegSetDr1(Bs3SelPtrToFlat(&Bs3GdteSpare00)); + Bs3RegSetDr7(X86_DR7_L1 | X86_DR7_G1 | X86_DR7_RW(1, X86_DR7_RW_RW) | X86_DR7_LEN(1, X86_DR7_LEN_DWORD) | X86_DR7_LE | X86_DR7_GE); + Bs3RegSetDr6(X86_DR6_INIT_VAL); + + Bs3TrapSetJmpAndRestore(&Ctx, &TrapCtx); + TrapExpect.Ctx.rip = TrapCtx.Ctx.rip; /// @todo fixme + Bs3RegSetDr7(0); + uDr6Expect = g_enmCpuVendor == BS3CPUVENDOR_INTEL ? X86_DR6_INIT_VAL : X86_DR6_INIT_VAL | X86_DR6_B1; + bs3CpuWeird1_CompareDbgInhibitRingXfer(&TrapCtx, &TrapExpect.Ctx, X86_XCPT_DB, 0, 0, uDr6Expect, + cbIretFrameSame, uHandlerRspIntDb); + } + + /* + * Cleanup. + */ + Bs3RegSetDr0(0); + Bs3RegSetDr1(0); + Bs3RegSetDr2(0); + Bs3RegSetDr3(0); + Bs3RegSetDr6(X86_DR6_INIT_VAL); + Bs3RegSetDr7(0); + } + Bs3TrapSetDpl(bIntGate, bSavedDpl); + return 0; +} + + +BS3_DECL_FAR(uint8_t) BS3_CMN_FAR_NM(bs3CpuWeird1_DbgInhibitRingXfer)(uint8_t bMode) +{ + if (BS3_MODE_IS_V86(bMode)) + switch (bMode) + { + /** @todo some busted stack stuff with the 16-bit guys. Also, if VME is + * enabled, we're probably not able to do any sensible testing. */ + case BS3_MODE_PP16_V86: + case BS3_MODE_PE16_V86: + case BS3_MODE_PAE16_V86: + return BS3TESTDOMODE_SKIPPED; + } + //if (bMode != BS3_MODE_PE16_V86) return BS3TESTDOMODE_SKIPPED; + //if (bMode != BS3_MODE_PAEV86) return BS3TESTDOMODE_SKIPPED; + + bs3CpuWeird1_SetGlobals(bMode); + + /** @todo test sysenter and syscall too. */ + /** @todo test INTO. */ + /** @todo test all V8086 software INT delivery modes (currently only 4 and 1). */ + + /* Note! Both ICEBP and BOUND has be checked cursorily and found not to be affected. */ + if (BS3_MODE_IS_16BIT_CODE(bMode)) + { + bs3CpuWeird1_DbgInhibitRingXfer_Worker(bMode, 0x80, 2, 2, bs3CpuWeird1_InhibitedInt80_c16, bs3CpuWeird1_InhibitedInt80_int80_c16); + if (!BS3_MODE_IS_V86(bMode) || !g_fVME) + { + /** @todo explain why these GURU */ + bs3CpuWeird1_DbgInhibitRingXfer_Worker(bMode, 0x03, 2, 2, bs3CpuWeird1_InhibitedInt3_c16, bs3CpuWeird1_InhibitedInt3_int3_c16); + bs3CpuWeird1_DbgInhibitRingXfer_Worker(bMode, 0x03, 1, 2, bs3CpuWeird1_InhibitedBp_c16, bs3CpuWeird1_InhibitedBp_int3_c16); + } + } + else if (BS3_MODE_IS_32BIT_CODE(bMode)) + { + bs3CpuWeird1_DbgInhibitRingXfer_Worker(bMode, 0x80, 2, 4, bs3CpuWeird1_InhibitedInt80_c32, bs3CpuWeird1_InhibitedInt80_int80_c32); + bs3CpuWeird1_DbgInhibitRingXfer_Worker(bMode, 0x03, 2, 4, bs3CpuWeird1_InhibitedInt3_c32, bs3CpuWeird1_InhibitedInt3_int3_c32); + bs3CpuWeird1_DbgInhibitRingXfer_Worker(bMode, 0x03, 1, 4, bs3CpuWeird1_InhibitedBp_c32, bs3CpuWeird1_InhibitedBp_int3_c32); + } + else + { + bs3CpuWeird1_DbgInhibitRingXfer_Worker(bMode, 0x80, 2, 0, bs3CpuWeird1_InhibitedInt80_c64, bs3CpuWeird1_InhibitedInt80_int80_c64); + bs3CpuWeird1_DbgInhibitRingXfer_Worker(bMode, 0x03, 2, 0, bs3CpuWeird1_InhibitedInt3_c64, bs3CpuWeird1_InhibitedInt3_int3_c64); + bs3CpuWeird1_DbgInhibitRingXfer_Worker(bMode, 0x03, 1, 0, bs3CpuWeird1_InhibitedBp_c64, bs3CpuWeird1_InhibitedBp_int3_c64); + } + + return 0; +} + diff --git a/src/VBox/ValidationKit/bootsectors/bs3-cpu-weird-1.c b/src/VBox/ValidationKit/bootsectors/bs3-cpu-weird-1.c new file mode 100644 index 00000000..93c3eac6 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3-cpu-weird-1.c @@ -0,0 +1,64 @@ +/* $Id: bs3-cpu-weird-1.c $ */ +/** @file + * BS3Kit - bs3-cpu-weird-1, 16-bit C code. + */ + +/* + * Copyright (C) 2007-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include <bs3kit.h> +#include <iprt/asm-amd64-x86.h> + + +/********************************************************************************************************************************* +* Internal Functions * +*********************************************************************************************************************************/ +FNBS3TESTDOMODE bs3CpuWeird1_DbgInhibitRingXfer_f16; + + +/********************************************************************************************************************************* +* Global Variables * +*********************************************************************************************************************************/ +static const BS3TESTMODEBYONEENTRY g_aModeByOneTests[] = +{ + { "dbg+inhibit+ringxfer", bs3CpuWeird1_DbgInhibitRingXfer_f16, 0 }, +}; + + +BS3_DECL(void) Main_rm() +{ + Bs3InitAll_rm(); + Bs3TestInit("bs3-cpu-weird-1"); + Bs3TestPrintf("g_uBs3CpuDetected=%#x\n", g_uBs3CpuDetected); + + /* + * Do tests driven from 16-bit code. + */ + Bs3TestDoModesByOne_rm(g_aModeByOneTests, RT_ELEMENTS(g_aModeByOneTests), 0); + + Bs3TestTerm(); +for (;;) { ASMHalt(); } +} + diff --git a/src/VBox/ValidationKit/bootsectors/bs3-fpustate-1-asm.asm b/src/VBox/ValidationKit/bootsectors/bs3-fpustate-1-asm.asm new file mode 100644 index 00000000..d619ed06 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3-fpustate-1-asm.asm @@ -0,0 +1,162 @@ +; $Id: bs3-fpustate-1-asm.asm $ +;; @file +; BS3Kit - bs3-fpustate-1, assembly helpers and template instantiation. +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + + +;********************************************************************************************************************************* +;* Header Files * +;********************************************************************************************************************************* +%include "bs3kit.mac" + + +;********************************************************************************************************************************* +;* Global Variables * +;********************************************************************************************************************************* +BS3_BEGIN_DATA16 +;; @name Floating point constants. +; @{ +g_r32_0dot1: dd 0.1 +g_r32_3dot2: dd 3.2 +g_r32_Zero: dd 0.0 +g_r32_One: dd 1.0 +g_r32_Two: dd 2.0 +g_r32_Three: dd 3.0 +g_r32_Ten: dd 10.0 +g_r32_Eleven: dd 11.0 +g_r32_ThirtyTwo:dd 32.0 +g_r32_Min: dd 000800000h +g_r32_Max: dd 07f7fffffh +g_r32_Inf: dd 07f800000h +g_r32_SNaN: dd 07f800001h +g_r32_SNaNMax: dd 07fbfffffh +g_r32_QNaN: dd 07fc00000h +g_r32_QNaNMax: dd 07fffffffh +g_r32_NegQNaN: dd 0ffc00000h + +g_r64_0dot1: dq 0.1 +g_r64_6dot9: dq 6.9 +g_r64_Zero: dq 0.0 +g_r64_One: dq 1.0 +g_r64_Two: dq 2.0 +g_r64_Three: dq 3.0 +g_r64_Ten: dq 10.0 +g_r64_Eleven: dq 11.0 +g_r64_ThirtyTwo:dq 32.0 +g_r64_Min: dq 00010000000000000h +g_r64_Max: dq 07fefffffffffffffh +g_r64_Inf: dq 07ff0000000000000h +g_r64_SNaN: dq 07ff0000000000001h +g_r64_SNaNMax: dq 07ff7ffffffffffffh +g_r64_NegQNaN: dq 0fff8000000000000h +g_r64_QNaN: dq 07ff8000000000000h +g_r64_QNaNMax: dq 07fffffffffffffffh +g_r64_DnMin: dq 00000000000000001h +g_r64_DnMax: dq 0000fffffffffffffh + + +g_r80_0dot1: dt 0.1 +g_r80_3dot2: dt 3.2 +g_r80_Zero: dt 0.0 +g_r80_One: dt 1.0 +g_r80_Two: dt 2.0 +g_r80_Three: dt 3.0 +g_r80_Ten: dt 10.0 +g_r80_Eleven: dt 11.0 +g_r80_ThirtyTwo:dt 32.0 +%ifdef __NASM__ +g_r80_Min: dq 08000000000000000h + dw 00001h +g_r80_Max: dq 0ffffffffffffffffh + dw 07ffeh +g_r80_Inf: dq 08000000000000000h + dw 07fffh +g_r80_QNaN: dq 0c000000000000000h + dw 07fffh +g_r80_QNaNMax: dq 0ffffffffffffffffh + dw 07fffh +g_r80_NegQNaN: dq 0c000000000000000h + dw 0ffffh +g_r80_SNaN: dq 08000000000000001h + dw 07fffh +g_r80_SNaNMax: dq 0bfffffffffffffffh + dw 07fffh +g_r80_DnMin: dq 00000000000000001h + dw 00000h +g_r80_DnMax: dq 07fffffffffffffffh + dw 00000h +%else +g_r80_Min: dt 000018000000000000000h +g_r80_Max: dt 07ffeffffffffffffffffh +g_r80_Inf: dt 07fff8000000000000000h +g_r80_QNaN: dt 07fffc000000000000000h +g_r80_QNaNMax: dt 07fffffffffffffffffffh +g_r80_NegQNaN: dt 0ffffc000000000000000h +g_r80_SNaN: dt 07fff8000000000000001h +g_r80_SNaNMax: dt 07fffbfffffffffffffffh +g_r80_DnMin: dt 000000000000000000001h +g_r80_DnMax: dt 000007fffffffffffffffh +%endif + +g_r32V1: dd 3.2 +g_r32V2: dd -1.9 +g_r64V1: dq 6.4 +g_r80V1: dt 8.0 + +; Denormal numbers. +g_r32D0: dd 000200000h +;; @} + +;; @name Upconverted Floating point constants +; @{ +;g_r80_r32_0dot1: dt 0.1 +%ifdef __NASM__ +g_r80_r32_3dot2: dq 0cccccd0000000000h + dw 04000h +%else +g_r80_r32_3dot2: dt 04000cccccd0000000000h +%endif +;g_r80_r32_Zero: dt 0.0 +;g_r80_r32_One: dt 1.0 +;g_r80_r32_Two: dt 2.0 +;g_r80_r32_Three: dt 3.0 +;g_r80_r32_Ten: dt 10.0 +;g_r80_r32_Eleven: dt 11.0 +;g_r80_r32_ThirtyTwo: dt 32.0 +;; @} + +;; @name Decimal constants. +; @{ +g_u64Zero: dd 0 +g_u32Zero: dw 0 +g_u64Two: dd 2 +g_u32Two: dw 2 +;; @} + + +; +; Instantiate code templates. +; +BS3_INSTANTIATE_TEMPLATE_ESSENTIALS "bs3-fpustate-1-template.mac" + diff --git a/src/VBox/ValidationKit/bootsectors/bs3-fpustate-1-template.c b/src/VBox/ValidationKit/bootsectors/bs3-fpustate-1-template.c new file mode 100644 index 00000000..c701e626 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3-fpustate-1-template.c @@ -0,0 +1,302 @@ +/* $Id: bs3-fpustate-1-template.c $ */ +/** @file + * BS3Kit - bs3-fpustate-1, C code template. + */ + +/* + * Copyright (C) 2007-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include <iprt/asm.h> +#include <iprt/asm-amd64-x86.h> +#include <VBox/VMMDevTesting.h> + + +/********************************************************************************************************************************* +* Defined Constants And Macros * +*********************************************************************************************************************************/ + + +#ifdef BS3_INSTANTIATING_CMN + +/** + * Displays the differences between the two states. + */ +# define bs3FpuState1_Diff BS3_CMN_NM(bs3FpuState1_Diff) +BS3_DECL_NEAR(void) bs3FpuState1_Diff(X86FXSTATE const BS3_FAR *pExpected, X86FXSTATE const BS3_FAR *pChecking) +{ + unsigned i; + +# define CHECK(a_Member, a_Fmt) \ + if (pExpected->a_Member != pChecking->a_Member) \ + Bs3TestPrintf(" " #a_Member ": " a_Fmt ", expected " a_Fmt "\n", pChecking->a_Member, pExpected->a_Member); \ + else do { } while (0) + CHECK(FCW, "%#RX16"); + CHECK(FSW, "%#RX16"); + CHECK(FTW, "%#RX16"); + CHECK(FOP, "%#RX16"); + CHECK(FPUIP, "%#RX32"); + CHECK(CS, "%#RX16"); + CHECK(Rsrvd1, "%#RX16"); + CHECK(FPUDP, "%#RX32"); + CHECK(DS, "%#RX16"); + CHECK(Rsrvd2, "%#RX16"); + CHECK(MXCSR, "%#RX32"); + CHECK(MXCSR_MASK, "%#RX32"); +# undef CHECK + for (i = 0; i < RT_ELEMENTS(pExpected->aRegs); i++) + if ( pChecking->aRegs[i].au64[0] != pExpected->aRegs[i].au64[0] + || pChecking->aRegs[i].au64[1] != pExpected->aRegs[i].au64[1]) + Bs3TestPrintf("st%u: %.16Rhxs\n" + "exp: %.16Rhxs\n", + i, &pChecking->aRegs[i], &pExpected->aRegs[i]); + for (i = 0; i < RT_ELEMENTS(pExpected->aXMM); i++) + if ( pChecking->aXMM[i].au64[0] != pExpected->aXMM[i].au64[0] + || pChecking->aXMM[i].au64[1] != pExpected->aXMM[i].au64[1]) + Bs3TestPrintf("xmm%u: %.16Rhxs\n" + " %sexp: %.16Rhxs\n", + i, &pChecking->aRegs[i], &pExpected->aRegs[i], i >= 10 ? " " : ""); +} + + +#endif /* BS3_INSTANTIATING_CMN */ + + +/* + * Mode specific code. + * Mode specific code. + * Mode specific code. + */ +#ifdef BS3_INSTANTIATING_MODE +# if TMPL_MODE == BS3_MODE_PE32 \ + || TMPL_MODE == BS3_MODE_PP32 \ + || TMPL_MODE == BS3_MODE_PAE32 \ + || TMPL_MODE == BS3_MODE_LM64 \ + || TMPL_MODE == BS3_MODE_RM + +/* Assembly helpers: */ +BS3_DECL_NEAR(void) TMPL_NM(bs3FpuState1_InitState)(X86FXSTATE BS3_FAR *pFxState, void BS3_FAR *pvMmioReg); +BS3_DECL_NEAR(void) TMPL_NM(bs3FpuState1_Restore)(X86FXSTATE const BS3_FAR *pFxState); +BS3_DECL_NEAR(void) TMPL_NM(bs3FpuState1_Save)(X86FXSTATE BS3_FAR *pFxState); + +BS3_DECL_NEAR(void) TMPL_NM(bs3FpuState1_FNStEnv)(void BS3_FAR *pvMmioReg); +BS3_DECL_NEAR(void) TMPL_NM(bs3FpuState1_MovDQU_Read)(void BS3_FAR *pvMmioReg); +BS3_DECL_NEAR(void) TMPL_NM(bs3FpuState1_MovDQU_Write)(void BS3_FAR *pvMmioReg); +BS3_DECL_NEAR(void) TMPL_NM(bs3FpuState1_FMul)(void BS3_FAR *pvMmioReg); + + +/** + * Tests for FPU state corruption. + * + * First we don't do anything to quit guest context for a while. + * Then we start testing weird MMIO accesses, some which amonger other things + * forces the use of the FPU state or host FPU to do the emulation. Both are a + * little complicated in raw-mode and ring-0 contexts. + * + * We ASSUME FXSAVE/FXRSTOR support here. + */ +BS3_DECL_FAR(uint8_t) TMPL_NM(bs3FpuState1_Corruption)(uint8_t bMode) +{ + /* We don't need to test that many modes, probably. */ + + uint8_t abBuf[sizeof(X86FXSTATE)*2 + 32]; + uint8_t BS3_FAR *pbTmp = &abBuf[0x10 - (((uintptr_t)abBuf) & 0x0f)]; + X86FXSTATE BS3_FAR *pExpected = (X86FXSTATE BS3_FAR *)pbTmp; + X86FXSTATE BS3_FAR *pChecking = pExpected + 1; + uint32_t iLoop; + uint32_t uStartTick; + bool fMmioReadback; + bool fReadBackError = false; + BS3PTRUNION MmioReg; + + +# undef CHECK_STATE +# define CHECK_STATE(a_Instr) \ + do { \ + TMPL_NM(bs3FpuState1_Save)(pChecking); \ + if (Bs3MemCmp(pExpected, pChecking, sizeof(*pExpected)) != 0) \ + { \ + Bs3TestFailedF("State differs after " #a_Instr " (write) in loop #%RU32\n", iLoop); \ + bs3FpuState1_Diff(pExpected, pChecking); \ + Bs3PitDisable(); \ + return 1; \ + } \ + } while (0) + + /* + * Setup the test. + */ + + /* Make this code executable in raw-mode. A bit tricky. */ + ASMSetCR0(ASMGetCR0() | X86_CR0_WP); + Bs3PitSetupAndEnablePeriodTimer(20); + ASMIntEnable(); +# if ARCH_BITS != 64 + ASMHalt(); +# endif + + /* Figure out which MMIO region we'll be using so we can correctly initialize FPUDS. */ +# if BS3_MODE_IS_RM_OR_V86(TMPL_MODE) + MmioReg.pv = BS3_FP_MAKE(0xffff, VMMDEV_TESTING_MMIO_BASE - _1M + 16); +# elif BS3_MODE_IS_16BIT_CODE(TMPL_MODE) + MmioReg.pv = BS3_FP_MAKE(BS3_SEL_VMMDEV_MMIO16, VMMDEV_TESTING_MMIO_BASE - _1M); +# else + MmioReg.pv = (uint8_t *)VMMDEV_TESTING_MMIO_BASE; +# endif + if (MmioReg.pu32[VMMDEV_TESTING_MMIO_OFF_NOP / sizeof(uint32_t)] == VMMDEV_TESTING_NOP_RET) + { + fMmioReadback = true; + MmioReg.pb += VMMDEV_TESTING_MMIO_OFF_READBACK; + } + else + { + Bs3TestPrintf("VMMDev MMIO not found, using VGA instead\n"); + fMmioReadback = false; + MmioReg.pv = Bs3XptrFlatToCurrent(0xa7800); + } + + /* Make 100% sure we don't trap accessing the FPU state and that we can use fxsave/fxrstor. */ + g_usBs3TestStep = 1; + ASMSetCR0((ASMGetCR0() & ~(X86_CR0_TS | X86_CR0_EM)) | X86_CR0_MP); + ASMSetCR4(ASMGetCR4() | X86_CR4_OSFXSR /*| X86_CR4_OSXMMEEXCPT*/); + + /* Come up with a distinct state. We do that from assembly (will do FPU in R0/RC). */ + g_usBs3TestStep = 2; + Bs3MemSet(abBuf, 0x42, sizeof(abBuf)); + TMPL_NM(bs3FpuState1_InitState)(pExpected, MmioReg.pb); + + + /* + * Test #1: Check that we can keep it consistent for a while. + */ + g_usBs3TestStep = 3; + uStartTick = g_cBs3PitTicks; + for (iLoop = 0; iLoop < _16M; iLoop++) + { + CHECK_STATE(nop); + if ( (iLoop & 0xffff) == 0xffff + && g_cBs3PitTicks - uStartTick >= 20 * 20) /* 20 seconds*/ + break; + } + + /* + * Test #2: Use various FPU, SSE and weird instructions to do MMIO writes. + * + * We'll use the VMMDev readback register if possible, but make do + * with VGA if not configured. + */ + g_usBs3TestStep = 4; + uStartTick = g_cBs3PitTicks; + for (iLoop = 0; iLoop < _1M; iLoop++) + { + unsigned off; + uint8_t abCompare[64]; + uint8_t abReadback[64]; + + /* Macros */ +# undef CHECK_READBACK_WRITE_RUN +# define CHECK_READBACK_WRITE_RUN(a_Instr, a_Worker, a_Type) \ + do { \ + off = (unsigned)(iLoop & (VMMDEV_TESTING_READBACK_SIZE / 2 - 1)); \ + if (off + sizeof(a_Type) > VMMDEV_TESTING_READBACK_SIZE) \ + off = VMMDEV_TESTING_READBACK_SIZE - sizeof(a_Type); \ + a_Worker((a_Type *)&MmioReg.pb[off]); \ + if (fMmioReadback && (!fReadBackError || iLoop == 0)) \ + { \ + a_Worker((a_Type *)&abCompare[0]); \ + Bs3MemCpy(abReadback, &MmioReg.pb[off], sizeof(a_Type)); \ + if (Bs3MemCmp(abReadback, abCompare, sizeof(a_Type)) != 0) \ + { \ + Bs3TestFailedF("Read back error for " #a_Instr " in loop #%RU32:\n%.*Rhxs expected:\n%.*Rhxs\n", \ + iLoop, sizeof(a_Type), abReadback, sizeof(a_Type), abCompare); \ + fReadBackError = true; \ + } \ + } \ + } while (0) + +# undef CHECK_READBACK_WRITE +# define CHECK_READBACK_WRITE(a_Instr, a_Worker, a_Type) \ + CHECK_READBACK_WRITE_RUN(a_Instr, a_Worker, a_Type); \ + CHECK_STATE(a_Instr) +# undef CHECK_READBACK_WRITE_Z +# define CHECK_READBACK_WRITE_Z(a_Instr, a_Worker, a_Type) \ + do { \ + if (fMmioReadback && (!fReadBackError || iLoop == 0)) \ + { \ + Bs3MemZero(&abCompare[0], sizeof(a_Type)); \ + off = (unsigned)(iLoop & (VMMDEV_TESTING_READBACK_SIZE / 2 - 1)); \ + if (off + sizeof(a_Type) > VMMDEV_TESTING_READBACK_SIZE) \ + off = VMMDEV_TESTING_READBACK_SIZE - sizeof(a_Type); \ + Bs3MemZero(&MmioReg.pb[off], sizeof(a_Type)); \ + } \ + CHECK_READBACK_WRITE(a_Instr, a_Worker, a_Type); \ + } while (0) + +# undef CHECK_READBACK_READ_RUN +# define CHECK_READBACK_READ_RUN(a_Instr, a_Worker, a_Type) \ + do { \ + off = (unsigned)(iLoop & (VMMDEV_TESTING_READBACK_SIZE / 2 - 1)); \ + if (off + sizeof(a_Type) > VMMDEV_TESTING_READBACK_SIZE) \ + off = VMMDEV_TESTING_READBACK_SIZE - sizeof(a_Type); \ + a_Worker((a_Type *)&MmioReg.pb[off]); \ + TMPL_NM(bs3FpuState1_Save)(pChecking); \ + } while (0) +# undef CHECK_READBACK_READ +# define CHECK_READBACK_READ(a_Instr, a_Worker, a_Type) \ + CHECK_READBACK_READ_RUN(a_Instr, a_Worker, a_Type); \ + CHECK_STATE(a_Instr) + + + /* The tests. */ + CHECK_READBACK_WRITE_Z(SIDT, ASMGetIDTR, RTIDTR); + CHECK_READBACK_WRITE_Z(FNSTENV, TMPL_NM(bs3FpuState1_FNStEnv), X86FSTENV32P); /** @todo x86.h is missing types */ + CHECK_READBACK_WRITE( MOVDQU, TMPL_NM(bs3FpuState1_MovDQU_Write), X86XMMREG); + CHECK_READBACK_READ( MOVDQU, TMPL_NM(bs3FpuState1_MovDQU_Read), X86XMMREG); + + /* Using the FPU is a little complicated, but we really need to check these things. */ + CHECK_READBACK_READ_RUN(FMUL, TMPL_NM(bs3FpuState1_FMul), uint64_t); + pExpected->FOP = 0x7dc; +# if ARCH_BITS == 64 + pExpected->FPUDP = (uint32_t) (uintptr_t)&MmioReg.pb[off]; + pExpected->DS = (uint16_t)((uintptr_t)&MmioReg.pb[off] >> 32); + pExpected->Rsrvd2 = (uint16_t)((uintptr_t)&MmioReg.pb[off] >> 48); +# elif BS3_MODE_IS_RM_OR_V86(TMPL_MODE) + pExpected->FPUDP = Bs3SelPtrToFlat(&MmioReg.pb[off]); +# else + pExpected->FPUDP = BS3_FP_OFF(&MmioReg.pb[off]); +# endif + CHECK_STATE(FMUL); + + /* check for timeout every now an then. */ + if ( (iLoop & 0xfff) == 0xfff + && g_cBs3PitTicks - uStartTick >= 20 * 20) /* 20 seconds*/ + break; + } + + Bs3PitDisable(); + return 0; +} +# endif +#endif /* BS3_INSTANTIATING_MODE */ + diff --git a/src/VBox/ValidationKit/bootsectors/bs3-fpustate-1-template.mac b/src/VBox/ValidationKit/bootsectors/bs3-fpustate-1-template.mac new file mode 100644 index 00000000..ccbde338 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3-fpustate-1-template.mac @@ -0,0 +1,330 @@ +; $Id: bs3-fpustate-1-template.mac $ +;; @file +; BS3Kit - bs3-fpustate-1, assembly template. +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + + +;********************************************************************************************************************************* +;* Header Files * +;********************************************************************************************************************************* +%include "bs3kit-template-header.mac" ; setup environment + + +;********************************************************************************************************************************* +;* External Symbols * +;********************************************************************************************************************************* +TMPL_BEGIN_TEXT + + +;; +; Initializes the FPU state and saves it to pFxState. +; +; BS3_DECL_NEAR(void) TMPL_NM(bs3FpuState1_InitState)(X86FXSTATE BS3_FAR *pFxState, void *pvMmioReg); +; +BS3_PROC_BEGIN_MODE bs3FpuState1_InitState, BS3_PBC_NEAR + BS3_CALL_CONV_PROLOG 2 + push xBP + mov xBP, xSP + push xBX +TONLY16 push ds + pushf +TONLY64 sub xSP, 20h + + ; + ; x87 state. + ; + fninit + fld dword [TMPL_DATA16_WRT(g_r32V1)] + fld qword [TMPL_DATA16_WRT(g_r64V1)] + fld tword [TMPL_DATA16_WRT(g_r80V1)] + fld qword [TMPL_DATA16_WRT(g_r64V1)] + fld dword [TMPL_DATA16_WRT(g_r32V2)] + fld dword [TMPL_DATA16_WRT(g_r80_QNaNMax)] + fld tword [TMPL_DATA16_WRT(g_r80_SNaNMax)] + fld tword [TMPL_DATA16_WRT(g_r80_ThirtyTwo)] + + ; + ; We'll later be using FMUL to test actually using the FPU in RC & R0, + ; so for everything to line up correctly with FPU CS:IP and FPU DS:DP, + ; we'll call the function here too. This has the benefitial side effect + ; of loading correct FPU DS/DS values so we can check that they don't + ; get lost either. Also, we now don't have to guess whether the CPU + ; emulation sets CS/DS or not. + ; +TONLY16 push xPRE [xBP + xCB + cbCurRetAddr + sCB + 2] + push xPRE [xBP + xCB + cbCurRetAddr + sCB] + BS3_CALL TMPL_NM(bs3FpuState1_FMul), 1 + add xSP, sCB + + ; + ; SSE state + ; + movdqu xmm0, [TMPL_DATA16_WRT(g_r32_0dot1)] + movdqu xmm1, [TMPL_DATA16_WRT(g_r32_Two)] + movdqu xmm2, [TMPL_DATA16_WRT(g_r32_ThirtyTwo)] + movdqu xmm3, [TMPL_DATA16_WRT(g_r32_ThirtyTwo)] + movdqu xmm4, [TMPL_DATA16_WRT(g_r32_SNaN)] + movdqu xmm5, [TMPL_DATA16_WRT(g_r32_NegQNaN)] + movdqu xmm6, [TMPL_DATA16_WRT(g_r64_Zero)] + movdqu xmm7, [TMPL_DATA16_WRT(g_r64_Two)] +%if TMPL_BITS == 64 + movdqu xmm8, [TMPL_DATA16_WRT(g_r64_Ten)] + movdqu xmm9, [TMPL_DATA16_WRT(g_r64_ThirtyTwo)] + movdqu xmm10, [TMPL_DATA16_WRT(g_r64_Max)] + movdqu xmm11, [TMPL_DATA16_WRT(g_r64_SNaN)] + movdqu xmm12, [TMPL_DATA16_WRT(g_r64_NegQNaN)] + movdqu xmm13, [TMPL_DATA16_WRT(g_r64_QNaNMax)] + movdqu xmm14, [TMPL_DATA16_WRT(g_r64_DnMax)] + movdqu xmm15, [TMPL_DATA16_WRT(g_r80_Eleven)] +%endif + + ;; @todo status regs + + ; + ; Save it. Note that DS is no longer valid in 16-bit code. + ; To be on the safe side, we load and save the state once again. + ; +TONLY16 mov ds, [xBP + xCB + cbCurRetAddr + 2] + mov xBX, [xBP + xCB + cbCurRetAddr] + cli +%if TMPL_BITS == 64 + o64 fxsave [xBX] + fninit + o64 fxrstor [xBX] + o64 fxsave [xBX] +%else + fxsave [xBX] + fninit + fxrstor [xBX] + fxsave [xBX] +%endif + +.return: +TONLY64 add xSP, 20h + popf +TONLY16 pop ds + pop xBX + mov xSP, xBP + pop xBP + BS3_CALL_CONV_EPILOG 2 + BS3_HYBRID_RET +BS3_PROC_END_MODE bs3FpuState1_InitState + + +;; +; BS3_DECL_NEAR(void) TMPL_NM(bs3FpuState1_Restore)(X86FXSTATE const BS3_FAR *pFxState); +; +BS3_PROC_BEGIN_MODE bs3FpuState1_Restore, BS3_PBC_NEAR + push xBP + mov xBP, xSP + +%if TMPL_BITS == 64 + o64 fxrstor [rcx] + +%elif TMPL_BITS == 32 + mov eax, [xBP + xCB*2] + fxrstor [eax] + +%elif TMPL_BITS == 16 + mov ax, ds + mov ds, [xBP + xCB + cbCurRetAddr + 2] + mov xBX, [xBP + xCB + cbCurRetAddr] + fxrstor [bx] + mov ds, ax +%else + %error TMPL_BITS +%endif + + mov xSP, xBP + pop xBP + BS3_HYBRID_RET +BS3_PROC_END_MODE bs3FpuState1_Restore + +;; +; BS3_DECL_NEAR(void) TMPL_NM(bs3FpuState1_Save)(X86FXSTATE BS3_FAR *pFxState); +; +BS3_PROC_BEGIN_MODE bs3FpuState1_Save, BS3_PBC_NEAR + push xBP + mov xBP, xSP + +%if TMPL_BITS == 64 + o64 fxsave [rcx] + +%elif TMPL_BITS == 32 + mov eax, [xBP + xCB*2] + fxsave [eax] + +%elif TMPL_BITS == 16 + push bx + push ds + mov ds, [xBP + xCB + cbCurRetAddr + 2] + mov bx, [xBP + xCB + cbCurRetAddr] + fxsave [bx] + pop ds + pop bx +%else + %error TMPL_BITS +%endif + + mov xSP, xBP + pop xBP + BS3_HYBRID_RET +BS3_PROC_END_MODE bs3FpuState1_Save + + +;; +; Performs a MOVDQU write on the specified memory. +; +; BS3_DECL_NEAR(void) TMPL_NM(bs3FpuState1_MovDQU_Write)(void *pvMmioReg); +; +BS3_PROC_BEGIN_MODE bs3FpuState1_MovDQU_Write, BS3_PBC_NEAR + BS3_CALL_CONV_PROLOG 1 + push xBP + mov xBP, xSP + push xBX +TONLY16 push ds + + ; Load the register pointer. + mov xBX, [xBP + xCB + cbCurRetAddr] +TONLY16 mov ds, [xBP + xCB + cbCurRetAddr + 2] + + ; Do read. + movdqu [xBX], xmm3 + +TONLY16 pop ds + pop xBX + leave + BS3_CALL_CONV_EPILOG 1 + BS3_HYBRID_RET +BS3_PROC_END_MODE bs3FpuState1_MovDQU_Write + + +;; +; Performs a MOVDQU write to the specified memory. +; +; BS3_DECL_NEAR(void) TMPL_NM(bs3FpuState1_MovDQU_Read)(void *pvMmioReg); +; +BS3_PROC_BEGIN_MODE bs3FpuState1_MovDQU_Read, BS3_PBC_NEAR + BS3_CALL_CONV_PROLOG 1 + push xBP + mov xBP, xSP + push xBX +TONLY16 push ds + sub xSP, 20h +%if TMPL_BITS == 16 + movdqu [xBP - xCB - xCB - 2 - 18h], xmm2 +%else + movdqu [xSP], xmm2 +%endif + + ; Load the register pointer. + mov xBX, [xBP + xCB + cbCurRetAddr] +TONLY16 mov ds, [xBP + xCB + cbCurRetAddr + 2] + + + ; Do read. + movdqu xmm2, [xBX] + +%if TMPL_BITS == 16 + movdqu xmm2, [xBP - xCB - xCB - 2 - 18h] +%else + movdqu xmm2, [xSP] +%endif + add xSP, 20h +TONLY16 pop ds + pop xBX + mov xSP, xBP + pop xBP + BS3_CALL_CONV_EPILOG 1 + BS3_HYBRID_RET +BS3_PROC_END_MODE bs3FpuState1_MovDQU_Read + + +;; +; Performs a FNSTENV write on the specified memory. +; +; BS3_DECL_NEAR(void) TMPL_NM(bs3FpuState1_FNStEnv)(void *pvMmioReg); +; +BS3_PROC_BEGIN_MODE bs3FpuState1_FNStEnv, BS3_PBC_NEAR + BS3_CALL_CONV_PROLOG 1 + push xBP + mov xBP, xSP + push xBX +TONLY16 push ds + + ; Load the register pointer. + mov xBX, [xBP + xCB + cbCurRetAddr] +TONLY16 mov ds, [xBP + xCB + cbCurRetAddr + 2] + + ; Just write. + fnstenv [xBX] + +TONLY16 pop ds + pop xBX + mov xSP, xBP + pop xBP + BS3_CALL_CONV_EPILOG 1 + BS3_HYBRID_RET +BS3_PROC_END_MODE bs3FpuState1_FNStEnv + + +;; +; Performs a FMUL on the specified memory, after writing a 64-bit value to it first. +; +; BS3_DECL_NEAR(void) TMPL_NM(bs3FpuState1_FMul)(void *pvMmioReg); +; +BS3_PROC_BEGIN_MODE bs3FpuState1_FMul, BS3_PBC_NEAR + BS3_CALL_CONV_PROLOG 1 + push xBP + mov xBP, xSP + push xBX +TONLY16 push ds + + ; Load the value we'll be multiplying with into register(s) while ds is DATA16. + mov sAX, [TMPL_DATA16_WRT(g_r64_One)] +TNOT64 mov edx, [4 + TMPL_DATA16_WRT(g_r64_One)] + + ; Load the register pointer. + mov xBX, [xBP + xCB + cbCurRetAddr] +TONLY16 mov ds, [xBP + xCB + cbCurRetAddr + 2] + + ; Just write. + mov [xBX], sAX +TNOT64 mov [xBX + 4], edx + call .do_it + +TONLY16 pop ds + pop xBX + mov xSP, xBP + pop xBP + BS3_CALL_CONV_EPILOG 1 + BS3_HYBRID_RET +.do_it: + fmul qword [xBX] + ret +BS3_PROC_END_MODE bs3FpuState1_FMul + + +%include "bs3kit-template-footer.mac" ; reset environment + diff --git a/src/VBox/ValidationKit/bootsectors/bs3-fpustate-1.c b/src/VBox/ValidationKit/bootsectors/bs3-fpustate-1.c new file mode 100644 index 00000000..9305d88c --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3-fpustate-1.c @@ -0,0 +1,84 @@ +/* $Id: bs3-fpustate-1.c $ */ +/** @file + * BS3Kit - bs3-fpustate-1, 16-bit C code. + */ + +/* + * Copyright (C) 2007-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include <bs3kit.h> +#include <iprt/asm-amd64-x86.h> + + +/********************************************************************************************************************************* +* Internal Functions * +*********************************************************************************************************************************/ +BS3TESTMODE_PROTOTYPES_MODE(bs3FpuState1_Corruption); + + +/********************************************************************************************************************************* +* Global Variables * +*********************************************************************************************************************************/ +static const BS3TESTMODEENTRY g_aModeTest[] = +{ + { + /*pszSubTest =*/ "corruption", + /*RM*/ bs3FpuState1_Corruption_rm, + /*PE16*/ NULL, //bs3FpuState1_Corruption_pe16, + /*PE16_32*/ NULL, //bs3FpuState1_Corruption_pe16_32, + /*PE16_V86*/ NULL, //bs3FpuState1_Corruption_pe16_v86, + /*PE32*/ bs3FpuState1_Corruption_pe32, + /*PE32_16*/ NULL, //bs3FpuState1_Corruption_pe32_16, + /*PEV86*/ NULL, //bs3FpuState1_Corruption_pev86, + /*PP16*/ NULL, //bs3FpuState1_Corruption_pp16, + /*PP16_32*/ NULL, //bs3FpuState1_Corruption_pp16_32, + /*PP16_V86*/ NULL, //bs3FpuState1_Corruption_pp16_v86, + /*PP32*/ bs3FpuState1_Corruption_pp32, + /*PP32_16*/ NULL, //bs3FpuState1_Corruption_pp32_16, + /*PPV86*/ NULL, //bs3FpuState1_Corruption_ppv86, + /*PAE16*/ NULL, //bs3FpuState1_Corruption_pae16, + /*PAE16_32*/ NULL, //bs3FpuState1_Corruption_pae16_32, + /*PAE16_V86*/ NULL, //bs3FpuState1_Corruption_pae16_v86, + /*PAE32*/ bs3FpuState1_Corruption_pae32, + /*PAE32_16*/ NULL, //bs3FpuState1_Corruption_pae32_16, + /*PAEV86*/ NULL, //bs3FpuState1_Corruption_paev86, + /*LM16*/ NULL, //bs3FpuState1_Corruption_lm16, + /*LM32*/ NULL, //bs3FpuState1_Corruption_lm32, + /*LM64*/ bs3FpuState1_Corruption_lm64, + } +}; + + +BS3_DECL(void) Main_rm() +{ + Bs3InitAll_rm(); + Bs3TestInit("bs3-fpustate-1"); + Bs3TestPrintf("g_uBs3CpuDetected=%#x\n", g_uBs3CpuDetected); + + Bs3TestDoModes_rm(g_aModeTest, RT_ELEMENTS(g_aModeTest)); + + Bs3TestTerm(); +} + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/Makefile.kmk b/src/VBox/ValidationKit/bootsectors/bs3kit/Makefile.kmk new file mode 100644 index 00000000..04b913c6 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/Makefile.kmk @@ -0,0 +1,679 @@ +# $Id: Makefile.kmk $ +## @file +# VirtualBox Validation Kit - Bootsector Kit v3 +# + +# +# Copyright (C) 2006-2019 Oracle Corporation +# +# This file is part of VirtualBox Open Source Edition (OSE), as +# available from http://www.virtualbox.org. This file is free software; +# you can redistribute it and/or modify it under the terms of the GNU +# General Public License (GPL) as published by the Free Software +# Foundation, in version 2 as it comes in the "COPYING" file of the +# VirtualBox OSE distribution. VirtualBox OSE is distributed in the +# hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +# +# The contents of this file may alternatively be used under the terms +# of the Common Development and Distribution License Version 1.0 +# (CDDL) only, as it comes in the "COPYING.CDDL" file of the +# VirtualBox OSE distribution, in which case the provisions of the +# CDDL are applicable instead of those of the GPL. +# +# You may elect to license modified versions of this file under the +# terms and conditions of either the GPL or the CDDL or both. +# + +SUB_DEPTH = ../../../../.. +include $(KBUILD_PATH)/subheader.kmk + + + +# Boot Sector post-link tool (used via the parent Config.kmk). +BLDPROGS += VBoxBs3Linker +VBoxBs3Linker_TEMPLATE = VBoxBldProg +VBoxBs3Linker_SOURCES = $(VBOX_PATH_BS3KIT_SRC)/VBoxBs3Linker.cpp + + +# 64-bit relocation conversion tool (used via the parent Config.kmk). +BLDPROGS += VBoxBs3ObjConverter +VBoxBs3ObjConverter_TEMPLATE = VBoxAdvBldProg +VBoxBs3ObjConverter_DEFS = BS3KIT_BS3CLASS16CODE=$(BS3KIT_BS3CLASS16CODE) +VBoxBs3ObjConverter_SOURCES = $(VBOX_PATH_BS3KIT_SRC)/VBoxBs3ObjConverter.cpp + + +# The boot sector. +MISCBINS += bs3-bootsector +bs3-bootsector_TEMPLATE = VBoxBS3KitBS +bs3-bootsector_SOURCES = bs3-bootsector.asm + + +# +# Common sources to be compiled into _p16, _p32 and _p64 versions. +# +VBOX_BS3KIT_COMMON_SOURCES = \ + bs3-cmn-A20Disable.asm \ + bs3-cmn-A20Enable.asm \ + bs3-cmn-GetCpuVendor.c \ + bs3-cmn-GetModeName.c \ + bs3-cmn-GetModeNameShortLower.c \ + bs3-cmn-KbdRead.asm \ + bs3-cmn-KbdWait.asm \ + bs3-cmn-KbdWrite.asm \ + bs3-cmn-Shutdown.asm \ + bs3-cmn-Panic.asm \ + bs3-cmn-PrintChr.asm \ + bs3-cmn-Printf.c \ + bs3-cmn-PrintU32.asm \ + bs3-cmn-PrintX32.asm \ + bs3-cmn-PrintStr.c \ + bs3-cmn-PrintStrN.asm \ + bs3-cmn-StrFormatV.c \ + bs3-cmn-StrPrintf.c \ + bs3-cmn-StrLen.c \ + bs3-cmn-StrNLen.c \ + bs3-cmn-StrCpy.c \ + bs3-cmn-MemChr.asm \ + bs3-cmn-MemCmp.asm \ + bs3-cmn-MemCpy.c \ + bs3-cmn-MemPCpy.c \ + bs3-cmn-MemMove.c \ + bs3-cmn-MemSet.asm \ + bs3-cmn-MemZero.asm \ + bs3-cmn-MemAlloc.c \ + bs3-cmn-MemAllocZ.c \ + bs3-cmn-MemFree.c \ + bs3-cmn-MemGuardedTestPage.c \ + bs3-cmn-MemPrintInfo.c \ + bs3-cmn-PagingData.c \ + bs3-cmn-PagingInitRootForPP.c \ + bs3-cmn-PagingInitRootForPAE.c \ + bs3-cmn-PagingInitRootForLM.c \ + bs3-cmn-PagingAlias.c \ + bs3-cmn-PagingProtect.c \ + bs3-cmn-PagingQueryAddressInfo.c \ + bs3-cmn-PagingSetupCanonicalTraps.c \ + bs3-cmn-pic-data.c \ + bs3-cmn-PicMaskAll.c \ + bs3-cmn-PicUpdateMask.c \ + bs3-cmn-PicSetup.c \ + bs3-cmn-pit.c \ + bs3-cmn-PitIrqHandler.c \ + bs3-cmn-RegCtxRestore.asm \ + bs3-cmn-RegCtxConvertToRingX.c \ + bs3-cmn-RegCtxPrint.c \ + bs3-cmn-RegCtxSave.asm \ + bs3-cmn-RegCtxSaveEx.asm \ + bs3-cmn-RegCtxSetGrpSegFromCurPtr.c \ + bs3-cmn-RegCtxSetGrpSegFromFlat.c \ + bs3-cmn-RegCtxSetRipCsFromCurPtr.c \ + bs3-cmn-RegCtxSetRipCsFromFlat.c \ + bs3-cmn-RegCtxSetRipCsFromLnkPtr.c \ + bs3-cmn-RegGetCr0.asm \ + bs3-cmn-RegGetCr2.asm \ + bs3-cmn-RegGetCr3.asm \ + bs3-cmn-RegGetCr4.asm \ + bs3-cmn-RegSetCr0.asm \ + bs3-cmn-RegSetCr2.asm \ + bs3-cmn-RegSetCr3.asm \ + bs3-cmn-RegSetCr4.asm \ + bs3-cmn-RegGetDr0.asm \ + bs3-cmn-RegGetDr1.asm \ + bs3-cmn-RegGetDr2.asm \ + bs3-cmn-RegGetDr3.asm \ + bs3-cmn-RegGetDr6.asm \ + bs3-cmn-RegGetDr7.asm \ + bs3-cmn-RegGetDrX.asm \ + bs3-cmn-RegSetDr0.asm \ + bs3-cmn-RegSetDr1.asm \ + bs3-cmn-RegSetDr2.asm \ + bs3-cmn-RegSetDr3.asm \ + bs3-cmn-RegSetDr6.asm \ + bs3-cmn-RegSetDr7.asm \ + bs3-cmn-RegSetDrX.asm \ + bs3-cmn-RegGetTr.asm \ + bs3-cmn-RegSetTr.asm \ + bs3-cmn-RegGetLdtr.asm \ + bs3-cmn-RegSetLdtr.asm \ + bs3-cmn-ExtCtxInit.c \ + bs3-cmn-ExtCtxSave.asm \ + bs3-cmn-ExtCtxRestore.asm \ + bs3-cmn-ExtCtxGetSize.c \ + bs3-cmn-ExtCtxAlloc.c \ + bs3-cmn-ExtCtxFree.c \ + bs3-cmn-ExtCtxCopy.c \ + bs3-cmn-SelFar32ToFlat32.c \ + bs3-cmn-SelFar32ToFlat32NoClobber.asm \ + bs3-cmn-SelProtFar32ToFlat32.c \ + bs3-cmn-SelProtModeCodeToRealMode.asm \ + bs3-cmn-SelRealModeCodeToProtMode.asm \ + bs3-cmn-SelFlatCodeToRealMode.asm \ + bs3-cmn-SelFlatCodeToProtFar16.asm \ + bs3-cmn-SelRealModeDataToProtFar16.asm \ + bs3-cmn-SelProtFar16DataToRealMode.asm \ + bs3-cmn-SelRealModeDataToFlat.asm \ + bs3-cmn-SelProtFar16DataToFlat.asm \ + bs3-cmn-SelFlatDataToProtFar16.asm \ + bs3-cmn-SelFlatDataToRealMode.asm \ + bs3-cmn-SelSetup16BitData.c \ + bs3-cmn-SelSetup16BitCode.c \ + bs3-cmn-SlabInit.c \ + bs3-cmn-SlabAlloc.c \ + bs3-cmn-SlabAllocEx.c \ + bs3-cmn-SlabFree.c \ + bs3-cmn-SlabListInit.c \ + bs3-cmn-SlabListAdd.c \ + bs3-cmn-SlabListAlloc.c \ + bs3-cmn-SlabListAllocEx.c \ + bs3-cmn-SlabListFree.c \ + bs3-cmn-SwitchHlpConvRealModeRetfPopBpDecBpAndReturn.asm \ + bs3-cmn-SwitchHlpConvProtModeRetfPopBpDecBpAndReturn.asm \ + bs3-cmn-SwitchToRing0.asm \ + bs3-cmn-SwitchToRing1.asm \ + bs3-cmn-SwitchToRing2.asm \ + bs3-cmn-SwitchToRing3.asm \ + bs3-cmn-SwitchToRingX.asm \ + bs3-cmn-SwitchTo16Bit.asm \ + bs3-cmn-SwitchTo16BitV86.asm \ + bs3-cmn-SwitchTo32Bit.asm \ + bs3-cmn-SwitchTo64Bit.asm \ + bs3-cmn-Syscall.asm \ + bs3-cmn-TestData.c \ + bs3-cmn-TestInit.c \ + bs3-cmn-TestFailed.c \ + bs3-cmn-TestSkipped.c \ + bs3-cmn-TestSub.c \ + bs3-cmn-TestSubDone.c \ + bs3-cmn-TestSubErrorCount.c \ + bs3-cmn-TestTerm.c \ + bs3-cmn-TestSendCmdWithStr.asm \ + bs3-cmn-TestSendCmdWithU32.asm \ + bs3-cmn-TestIsVmmDevTestingPresent.asm \ + bs3-cmn-TestCheckRegCtxEx.c \ + bs3-cmn-TestHostPrintf.c \ + bs3-cmn-TestPrintf.c \ + bs3-cmn-TrapReInit.c \ + bs3-cmn-TrapRmV86Init.c \ + bs3-cmn-TrapRmV86SetGate.c \ + bs3-cmn-Trap16Init.c \ + bs3-cmn-Trap16SetGate.c \ + bs3-cmn-Trap32Init.c \ + bs3-cmn-Trap32SetGate.c \ + bs3-cmn-Trap64Init.c \ + bs3-cmn-Trap64SetGate.c \ + bs3-cmn-TrapSetDpl.c \ + bs3-cmn-TrapDefaultHandler.c \ + bs3-cmn-TrapHandlersData.asm \ + bs3-cmn-TrapPrintFrame.c \ + bs3-cmn-TrapSetHandler.c \ + bs3-cmn-TrapSetHandlerEx.c \ + bs3-cmn-TrapSetJmp.asm \ + bs3-cmn-TrapSetJmpAndRestore.c \ + bs3-cmn-TrapUnsetJmp.c \ + bs3-cmn-UtilSetFullGdtr.asm \ + bs3-cmn-UtilSetFullIdtr.asm \ + bs3-cmn-TestDoModesByOneHlp.asm \ + ../../../Runtime/common/asm/ASMBitFirstClear.asm \ + ../../../Runtime/common/asm/ASMBitFirstSet.asm \ + ../../../Runtime/common/asm/ASMBitNextClear.asm \ + ../../../Runtime/common/asm/ASMBitNextSet.asm \ + ../../../Runtime/common/asm/ASMBitFirstSetU16.asm \ + ../../../Runtime/common/asm/ASMBitFirstSetU32.asm \ + ../../../Runtime/common/asm/ASMBitFirstSetU64.asm \ + ../../../Runtime/common/asm/ASMBitLastSetU16.asm \ + ../../../Runtime/common/asm/ASMBitLastSetU32.asm \ + ../../../Runtime/common/asm/ASMBitLastSetU64.asm \ + ../../../Runtime/common/asm/ASMMemFirstMismatchingU8.asm \ + ../../../Runtime/common/asm/ASMSerializeInstruction-cpuid.asm \ + ../../../Runtime/common/asm/ASMSerializeInstruction-iret.asm \ + ../../../Runtime/common/asm/ASMSerializeInstruction-rdtscp.asm \ + ../../../Runtime/common/asm/ASMCpuIdExSlow.asm \ + ../../../Runtime/common/asm/ASMCpuId.asm \ + ../../../Runtime/common/asm/ASMCpuId_Idx_ECX.asm \ + ../../../Runtime/common/asm/ASMGetXcr0.asm \ + ../../../Runtime/common/asm/ASMSetXcr0.asm \ + +# The 16-bit BS3Kit library. +LIBRARIES += bs3kit-common-16 +bs3kit-common-16_TEMPLATE = VBoxBS3KitImg +bs3kit-common-16_INSTTYPE = none +bs3kit-common-16_DEFS = TMPL_PE16 BS3_CMN_ONLY +bs3kit-common-16_ASDEFS = RT_ASMDEFS_INC_FIRST_FILE +bs3kit-common-16_SOURCES = $(VBOX_BS3KIT_COMMON_SOURCES) \ + bs3-system-data.asm \ + bs3-rm-InitAll.c \ + bs3-rm-InitMemory.c \ + bs3-rm-InitGdt.c \ + bs3-cmn-hexdigits.c \ + bs3-cmn-CpuDetectData.c \ + bs3-cmn-PerCpuData.c \ + bs3-cmn-ConvertRMStackToP16UsingCxReturnToAx.asm \ + bs3-cmn-UInt64Div.c \ + bs3-cmn-UInt32Div.c \ + bs3-wc16-U8DR.asm \ + bs3-wc16-U8DQ.asm \ + bs3-wc16-I8DR.asm \ + bs3-wc16-I8DQ.asm \ + bs3-wc16-I8RS.asm \ + bs3-wc16-U8RS.asm \ + bs3-wc16-U8LS.asm \ + bs3-wc16-U4D.asm \ + bs3-wc16-I4D.asm \ + bs3-c16-SwitchFromV86To16BitAndCallC.asm \ + bs3-c16-Trap16Generic.asm \ + bs3-c16-TrapRmV86Generic.asm \ + bs3-c16-TrapRmV86Data.c \ + bs3-c16-CreateHybridFarRet.asm +bs3kit-common-16_bs3-cmn-UInt64Div.c_CFLAGS = -oh -d0 # -d1+ vs -d0 saves 0x6a3-0x577 = 0x12C (300)! + +$(call BS3KIT_FN_GEN_CMN_FARSTUB,bs3kit-common-16,ASMMemFirstMismatchingU8,8) +$(call BS3KIT_FN_GEN_CMN_FARSTUB,bs3kit-common-16,ASMMemFirstNonZero,6) +$(call BS3KIT_FN_GEN_CMN_FARSTUB,bs3kit-common-16,ASMCpuIdExSlow,32) +$(call BS3KIT_FN_GEN_CMN_FARSTUB,bs3kit-common-16,ASMCpuId,20) +$(call BS3KIT_FN_GEN_CMN_FARSTUB,bs3kit-common-16,ASMSetXcr0,8) +$(call BS3KIT_FN_GEN_CMN_FARSTUB,bs3kit-common-16,ASMGetXcr0,0) +-include $(PATH_SUB_CURRENT)/bs3kit-autostubs.kmk # manually generated from headers, see bottom of this file. + +# The 32-bit BS3Kit library. +LIBRARIES += bs3kit-common-32 +bs3kit-common-32_TEMPLATE = VBoxBS3KitImg32 +bs3kit-common-32_INSTTYPE = none +bs3kit-common-32_DEFS = TMPL_PE32 BS3_CMN_ONLY +bs3kit-common-32_ASDEFS = RT_ASMDEFS_INC_FIRST_FILE +bs3kit-common-32_SOURCES = $(VBOX_BS3KIT_COMMON_SOURCES) \ + bs3-cmn-SwitchHlpConvFlatRetToRetfProtMode.asm \ + bs3-cmn-UInt64Div.c \ + bs3-wc32-U8D.asm \ + bs3-wc32-I8D.asm \ + bs3-wc32-I8RS.asm \ + bs3-wc32-U8RS.asm \ + bs3-wc32-U8LS.asm \ + bs3-c32-Trap32Generic.asm + +# The 64-bit BS3Kit library. +LIBRARIES += bs3kit-common-64 +bs3kit-common-64_TEMPLATE = VBoxBS3KitImg64 +bs3kit-common-64_INSTTYPE = none +bs3kit-common-64_DEFS = TMPL_LM64 BS3_CMN_ONLY +bs3kit-common-64_ASDEFS = RT_ASMDEFS_INC_FIRST_FILE +bs3kit-common-64_SOURCES = $(VBOX_BS3KIT_COMMON_SOURCES) \ + bs3-cmn-SwitchHlpConvFlatRetToRetfProtMode.asm \ + bs3-c64-Trap64Generic.asm \ + ../../../Runtime/common/asm/ASMGetIDTR.asm \ + ../../../Runtime/common/asm/ASMSetIDTR.asm \ + ../../../Runtime/common/asm/ASMGetGDTR.asm \ + ../../../Runtime/common/asm/ASMSetGDTR.asm \ + + +# +# Common sources to be compiled for each CPU mode. +# +VBOX_BS3KIT_MODE_SOURCES = \ + bs3-mode-Name.asm \ + bs3-mode-NameShortLower.asm \ + bs3-mode-SwitchToRM.asm \ + bs3-mode-SwitchToPE16.asm \ + bs3-mode-SwitchToPE16_32.asm \ + bs3-mode-SwitchToPE16_V86.asm \ + bs3-mode-SwitchToPE32.asm \ + bs3-mode-SwitchToPE32_16.asm \ + bs3-mode-SwitchToPEV86.asm \ + bs3-mode-SwitchToPP16.asm \ + bs3-mode-SwitchToPP16_32.asm \ + bs3-mode-SwitchToPP16_V86.asm \ + bs3-mode-SwitchToPP32.asm \ + bs3-mode-SwitchToPP32_16.asm \ + bs3-mode-SwitchToPPV86.asm \ + bs3-mode-SwitchToPAE16.asm \ + bs3-mode-SwitchToPAE16_32.asm \ + bs3-mode-SwitchToPAE16_V86.asm \ + bs3-mode-SwitchToPAE32.asm \ + bs3-mode-SwitchToPAE32_16.asm \ + bs3-mode-SwitchToPAEV86.asm \ + bs3-mode-SwitchToLM64.asm \ + bs3-mode-SwitchToLM32.asm \ + bs3-mode-SwitchToLM16.asm \ + bs3-mode-SwitchTo32BitAndCallC.asm \ + bs3-mode-EnteredMode.asm \ + bs3-mode-PagingGetRootForPP16.asm \ + bs3-mode-PagingGetRootForPP32.asm \ + bs3-mode-PagingGetRootForPAE16.asm \ + bs3-mode-PagingGetRootForPAE32.asm \ + bs3-mode-PagingGetRootForLM64.asm \ + bs3-mode-TrapInit.c \ + bs3-mode-TrapSystemCallHandler.asm \ + bs3-mode-TestDoModes.c \ + bs3-mode-TestDoModesByOne.c \ + bs3-mode-TestDoModesByMax.c \ + bs3-mode-TestDoModesHlp.asm \ + +# The 16-bit real mode BS3Kit library. +LIBRARIES += bs3kit-rm +bs3kit-rm_TEMPLATE = VBoxBS3KitImg +bs3kit-rm_INSTTYPE = none +bs3kit-rm_DEFS = TMPL_MODE=BS3_MODE_RM +bs3kit-rm_SOURCES = $(VBOX_BS3KIT_MODE_SOURCES) \ + bs3-first-rm.asm \ + bs3-mode-CpuDetect.asm \ + bs3-mode-TestDoModesStub.asm \ + bs3-mode-TestDoModesByOneStub.asm \ + bs3-mode-TestDoModesByMaxStub.asm \ + + +# The 16-bit BS3Kit library for 16-bit protected kernel+tss. +LIBRARIES += bs3kit-pe16 +bs3kit-pe16_TEMPLATE = VBoxBS3KitImg +bs3kit-pe16_INSTTYPE = none +bs3kit-pe16_DEFS = TMPL_MODE=BS3_MODE_PE16 +bs3kit-pe16_SOURCES = $(VBOX_BS3KIT_MODE_SOURCES) \ + bs3-first-pe16.asm \ + bs3-mode-TestDoModesStub.asm \ + bs3-mode-TestDoModesByOneStub.asm \ + bs3-mode-TestDoModesByMaxStub.asm \ +# bs3-mode-CpuDetect.asm + +# The 32-bit BS3Kit library for 16-bit protected kernel+tss. +LIBRARIES += bs3kit-pe16_32 +bs3kit-pe16_32_TEMPLATE = VBoxBS3KitImg32 +bs3kit-pe16_32_INSTTYPE = none +bs3kit-pe16_32_DEFS = TMPL_MODE=BS3_MODE_PE16_32 +bs3kit-pe16_32_SOURCES = $(VBOX_BS3KIT_MODE_SOURCES) \ + bs3-mode-TestDoModesStub.asm \ + bs3-mode-TestDoModesByOneStub.asm \ + bs3-mode-TestDoModesByMaxStub.asm \ + +# The v86 BS3Kit library for 16-bit protected kernel+tss. +LIBRARIES += bs3kit-pe16_v86 +bs3kit-pe16_v86_TEMPLATE = VBoxBS3KitImg +bs3kit-pe16_v86_INSTTYPE = none +bs3kit-pe16_v86_DEFS = TMPL_MODE=BS3_MODE_PE16_V86 +bs3kit-pe16_v86_SOURCES = $(VBOX_BS3KIT_MODE_SOURCES) \ + bs3-mode-TestDoModesStub.asm \ + bs3-mode-TestDoModesByOneStub.asm \ + bs3-mode-TestDoModesByMaxStub.asm \ + +# The 32-bit BS3Kit library for 32-bit protected kernel+tss. +LIBRARIES += bs3kit-pe32 +bs3kit-pe32_TEMPLATE = VBoxBS3KitImg32 +bs3kit-pe32_INSTTYPE = none +bs3kit-pe32_DEFS = TMPL_MODE=BS3_MODE_PE32 +bs3kit-pe32_SOURCES = $(VBOX_BS3KIT_MODE_SOURCES) \ + bs3-first-init-all-pe32.asm + +# The 16-bit BS3Kit library for 32-bit protected kernel+tss. +LIBRARIES += bs3kit-pe32_16 +bs3kit-pe32_16_TEMPLATE = VBoxBS3KitImg +bs3kit-pe32_16_INSTTYPE = none +bs3kit-pe32_16_DEFS = TMPL_MODE=BS3_MODE_PE32_16 +bs3kit-pe32_16_SOURCES = $(VBOX_BS3KIT_MODE_SOURCES) \ + bs3-mode-TestDoModesStub.asm \ + bs3-mode-TestDoModesByOneStub.asm \ + bs3-mode-TestDoModesByMaxStub.asm \ + +# The v8086 BS3Kit library for 32-bit protected kernel+tss. +LIBRARIES += bs3kit-pev86 +bs3kit-pev86_TEMPLATE = VBoxBS3KitImg +bs3kit-pev86_INSTTYPE = none +bs3kit-pev86_DEFS = TMPL_MODE=BS3_MODE_PEV86 +bs3kit-pev86_SOURCES = $(VBOX_BS3KIT_MODE_SOURCES) + +# The 16-bit BS3Kit library for 16-bit paged protected kernel+tss. +LIBRARIES += bs3kit-pp16 +bs3kit-pp16_TEMPLATE = VBoxBS3KitImg +bs3kit-pp16_INSTTYPE = none +bs3kit-pp16_DEFS = TMPL_MODE=BS3_MODE_PP16 +bs3kit-pp16_SOURCES = $(VBOX_BS3KIT_MODE_SOURCES) \ + bs3-mode-CpuDetect.asm \ + bs3-mode-TestDoModesStub.asm \ + bs3-mode-TestDoModesByOneStub.asm \ + bs3-mode-TestDoModesByMaxStub.asm \ + +# The 32-bit BS3Kit library for 16-bit paged protected kernel+tss. +LIBRARIES += bs3kit-pp16_32 +bs3kit-pp16_32_TEMPLATE = VBoxBS3KitImg32 +bs3kit-pp16_32_INSTTYPE = none +bs3kit-pp16_32_DEFS = TMPL_MODE=BS3_MODE_PP16_32 +bs3kit-pp16_32_SOURCES = $(VBOX_BS3KIT_MODE_SOURCES) + +# The v8086 BS3Kit library for 16-bit paged protected kernel+tss. +LIBRARIES += bs3kit-pp16_v86 +bs3kit-pp16_v86_TEMPLATE = VBoxBS3KitImg +bs3kit-pp16_v86_INSTTYPE = none +bs3kit-pp16_v86_DEFS = TMPL_MODE=BS3_MODE_PP16_V86 +bs3kit-pp16_v86_SOURCES = $(VBOX_BS3KIT_MODE_SOURCES) + +# The 32-bit BS3Kit library for 32-bit paged protected kernel+tss. +LIBRARIES += bs3kit-pp32 +bs3kit-pp32_TEMPLATE = VBoxBS3KitImg32 +bs3kit-pp32_INSTTYPE = none +bs3kit-pp32_DEFS = TMPL_MODE=BS3_MODE_PP32 +bs3kit-pp32_SOURCES = $(VBOX_BS3KIT_MODE_SOURCES) \ + bs3-first-init-all-pp32.asm + +# The 16-bit BS3Kit library for 32-bit paged protected kernel+tss. +LIBRARIES += bs3kit-pp32_16 +bs3kit-pp32_16_TEMPLATE = VBoxBS3KitImg +bs3kit-pp32_16_INSTTYPE = none +bs3kit-pp32_16_DEFS = TMPL_MODE=BS3_MODE_PP32_16 +bs3kit-pp32_16_SOURCES = $(VBOX_BS3KIT_MODE_SOURCES) \ + bs3-mode-TestDoModesStub.asm \ + bs3-mode-TestDoModesByOneStub.asm \ + bs3-mode-TestDoModesByMaxStub.asm \ + +# The v8086 BS3Kit library for 32-bit paged protected kernel+tss. +LIBRARIES += bs3kit-ppv86 +bs3kit-ppv86_TEMPLATE = VBoxBS3KitImg +bs3kit-ppv86_INSTTYPE = none +bs3kit-ppv86_DEFS = TMPL_MODE=BS3_MODE_PPV86 +bs3kit-ppv86_SOURCES = $(VBOX_BS3KIT_MODE_SOURCES) + + +# The 16-bit BS3Kit library for 16-bit PAE paged protected kernel+tss. +LIBRARIES += bs3kit-pae16 +bs3kit-pae16_TEMPLATE = VBoxBS3KitImg +bs3kit-pae16_INSTTYPE = none +bs3kit-pae16_DEFS = TMPL_MODE=BS3_MODE_PAE16 +bs3kit-pae16_SOURCES = $(VBOX_BS3KIT_MODE_SOURCES) \ + bs3-mode-CpuDetect.asm \ + bs3-mode-TestDoModesStub.asm \ + bs3-mode-TestDoModesByOneStub.asm \ + bs3-mode-TestDoModesByMaxStub.asm \ + +# The 16-bit BS3Kit library for 16-bit PAE paged protected kernel+tss. +LIBRARIES += bs3kit-pae16_32 +bs3kit-pae16_32_TEMPLATE = VBoxBS3KitImg32 +bs3kit-pae16_32_INSTTYPE = none +bs3kit-pae16_32_DEFS = TMPL_MODE=BS3_MODE_PAE16_32 +bs3kit-pae16_32_SOURCES = $(VBOX_BS3KIT_MODE_SOURCES) + +# The v8086 BS3Kit library for 16-bit PAE paged protected kernel+tss. +LIBRARIES += bs3kit-pae16_v86 +bs3kit-pae16_v86_TEMPLATE = VBoxBS3KitImg +bs3kit-pae16_v86_INSTTYPE = none +bs3kit-pae16_v86_DEFS = TMPL_MODE=BS3_MODE_PAE16_V86 +bs3kit-pae16_v86_SOURCES = $(VBOX_BS3KIT_MODE_SOURCES) + +# The 32-bit BS3Kit library for 32-bit PAE paged protected kernel+tss. +LIBRARIES += bs3kit-pae32 +bs3kit-pae32_TEMPLATE = VBoxBS3KitImg32 +bs3kit-pae32_INSTTYPE = none +bs3kit-pae32_DEFS = TMPL_MODE=BS3_MODE_PAE32 +bs3kit-pae32_SOURCES = $(VBOX_BS3KIT_MODE_SOURCES) + +# The 16-bit BS3Kit library for 32-bit PAE paged protected kernel+tss. +LIBRARIES += bs3kit-pae32_16 +bs3kit-pae32_16_TEMPLATE = VBoxBS3KitImg +bs3kit-pae32_16_INSTTYPE = none +bs3kit-pae32_16_DEFS = TMPL_MODE=BS3_MODE_PAE32_16 +bs3kit-pae32_16_SOURCES = $(VBOX_BS3KIT_MODE_SOURCES) \ + bs3-mode-TestDoModesStub.asm \ + bs3-mode-TestDoModesByOneStub.asm \ + bs3-mode-TestDoModesByMaxStub.asm \ + +# The v8086 BS3Kit library for 32-bit PAE paged protected kernel+tss. +LIBRARIES += bs3kit-paev86 +bs3kit-paev86_TEMPLATE = VBoxBS3KitImg +bs3kit-paev86_INSTTYPE = none +bs3kit-paev86_DEFS = TMPL_MODE=BS3_MODE_PAEV86 +bs3kit-paev86_SOURCES = $(VBOX_BS3KIT_MODE_SOURCES) + + +# The 16-bit long mode BS3Kit library. +LIBRARIES += bs3kit-lm16 +bs3kit-lm16_TEMPLATE = VBoxBS3KitImg +bs3kit-lm16_INSTTYPE = none +bs3kit-lm16_DEFS = TMPL_MODE=BS3_MODE_LM16 +bs3kit-lm16_SOURCES = $(VBOX_BS3KIT_MODE_SOURCES) \ + bs3-mode-TestDoModesStub.asm \ + bs3-mode-TestDoModesByOneStub.asm \ + bs3-mode-TestDoModesByMaxStub.asm \ + +# The 32-bit long mode BS3Kit library. +LIBRARIES += bs3kit-lm32 +bs3kit-lm32_TEMPLATE = VBoxBS3KitImg32 +bs3kit-lm32_INSTTYPE = none +bs3kit-lm32_DEFS = TMPL_MODE=BS3_MODE_LM32 +bs3kit-lm32_SOURCES = $(VBOX_BS3KIT_MODE_SOURCES) + +# The 64-bit long mode BS3Kit library. +LIBRARIES += bs3kit-lm64 +bs3kit-lm64_TEMPLATE = VBoxBS3KitImg64 +bs3kit-lm64_INSTTYPE = none +bs3kit-lm64_DEFS = TMPL_MODE=BS3_MODE_LM64 +bs3kit-lm64_SOURCES = $(VBOX_BS3KIT_MODE_SOURCES) + + +# +# shutdown example. +# +MISCBINS += bs3-shutdown +bs3-shutdown_TEMPLATE = VBoxBS3KitImg +bs3-shutdown_SOURCES = \ + bs3-first-pe16.asm \ + bs3-shutdown.c + + +# +# DOS Utilities / Testcases. +# +MISCBINS += bs3cpudt +bs3cpudt_TEMPLATE = VBoxBS3KitUtil +bs3cpudt_SOURCES = \ + bs3-first-dosexe.asm \ + bs3cpudt.c + + +# +# Rule for regenerating bs3kit-mangling-functions-undef.h. +# +bs3kit-mangling-code-undef.h: $(PATH_SUB_CURRENT)/bs3kit-mangling-code-define.h $(MAKEFILE) + $(SED) \ + -e 's/#\( *\)define \([a-zA-Z_][a-zA-Z0-9_]*\) .*$(DOLLAR)/#\1undef \2/' \ + -e 's/Function needing mangling.*$(DOLLAR)/Undefining function mangling - automatically generated by the $@ makefile rule./' \ + --output $(dir $<)bs3kit-mangling-code-undef.h \ + $< + +# +# Rule for regenerating bs3kit-mangling-functions-define.h. +# +bs3kit-mangling-code-define.h: \ + $(PATH_SUB_CURRENT)/bs3kit.h \ + $(PATH_SUB_CURRENT)/bs3-cmn-paging.h \ + $(PATH_SUB_CURRENT)/bs3-cmn-test.h \ + $(MAKEFILE) + $(APPEND) -tn "$(dir $<)$@" \ + '/* $(DOLLAR)Id: $(DOLLAR) */' \ + '/** @file' \ + ' * BS3Kit - Function needing mangling - generated by the $@ makefile rule.' \ + ' */' \ + '' \ + '/*' \ + ' * Copyright (C) 2007-2017 Oracle Corporation' \ + ' *' \ + ' * This file is part of VirtualBox Open Source Edition (OSE), as' \ + ' * available from http://www.virtualbox.org. This file is free software;' \ + ' * you can redistribute it and/or modify it under the terms of the GNU' \ + ' * General Public License (GPL) as published by the Free Software' \ + ' * Foundation, in version 2 as it comes in the "COPYING" file of the' \ + ' * VirtualBox OSE distribution. VirtualBox OSE is distributed in the' \ + ' * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.' \ + ' *' \ + ' * The contents of this file may alternatively be used under the terms' \ + ' * of the Common Development and Distribution License Version 1.0' \ + ' * (CDDL) only, as it comes in the "COPYING.CDDL" file of the' \ + ' * VirtualBox OSE distribution, in which case the provisions of the' \ + ' * CDDL are applicable instead of those of the GPL.' \ + ' *' \ + ' * You may elect to license modified versions of this file under the' \ + ' * terms and conditions of either the GPL or the CDDL or both.' \ + ' */' \ + '' + $(SED) -n \ + -e 's/^ *BS3_CMN_PROTO_STUB([^,]*, *\([a-zA-Z_][a-zA-Z0-9_]*\) *,.*$(DOLLAR)/#define \1 BS3_CMN_MANGLER(\1)/p' \ + -e 's/^ *BS3_CMN_PROTO_NOSB([^,]*, *\([a-zA-Z_][a-zA-Z0-9_]*\) *,.*$(DOLLAR)/#define \1 BS3_CMN_MANGLER(\1)/p' \ + -e 's/^ *BS3_CMN_PROTO_FARSTUB([^,]*,[^,]*, *\([a-zA-Z_][a-zA-Z0-9_]*\) *,.*$(DOLLAR)/#define \1 BS3_CMN_MANGLER(\1)/p' \ + $(filter %.h,$^) | sort >> "$(dir $<)bs3kit-mangling-code-define.h" + $(APPEND) -n "$(dir $<)$@" '#ifndef BS3_CMN_ONLY' + $(SED) -n \ + -e 's/^ *BS3_MODE_PROTO_STUB([^,]*, *\([a-zA-Z_][a-zA-Z0-9_]*\) *,.*$(DOLLAR)/# define \1 BS3_MODE_MANGLER(\1)/p' \ + -e 's/^ *BS3_MODE_PROTO_NOSB([^,]*, *\([a-zA-Z_][a-zA-Z0-9_]*\) *,.*$(DOLLAR)/# define \1 BS3_MODE_MANGLER(\1)/p' \ + -e 's/^ *BS3_MODE_PROTO_FARSTUB([^,]*,[^,]*, *\([a-zA-Z_][a-zA-Z0-9_]*\) *,.*$(DOLLAR)/# define \1 BS3_MODE_MANGLER(\1)/p' \ + $(filter %.h,$^) | sort >> "$(dir $<)bs3kit-mangling-code-define.h" + $(APPEND) -n "$(dir $<)$@" '#endif /* !BS3_CMN_ONLY */' + +# +# Rule for regenerating bs3kit-autostubs.kmk. +# +bs3kit-autostubs.kmk: \ + $(PATH_SUB_CURRENT)/bs3kit.h \ + $(PATH_SUB_CURRENT)/bs3-cmn-memory.h \ + $(PATH_SUB_CURRENT)/bs3-cmn-paging.h \ + $(PATH_SUB_CURRENT)/bs3-cmn-test.h \ + $(MAKEFILE) + $(APPEND) -tn "$(dir $<)$@" \ + '# $(DOLLAR)Id: $(DOLLAR)' \ + '## @file' \ + '# BS3Kit - Automatic near/far stubs - generated by the $@ makefile rule.' \ + '#' \ + '' \ + '#' \ + '# Copyright (C) 2007-2017 Oracle Corporation' \ + '#' \ + '# This file is part of VirtualBox Open Source Edition (OSE), as' \ + '# available from http://www.virtualbox.org. This file is free software;' \ + '# you can redistribute it and/or modify it under the terms of the GNU' \ + '# General Public License (GPL) as published by the Free Software' \ + '# Foundation, in version 2 as it comes in the "COPYING" file of the' \ + '# VirtualBox OSE distribution. VirtualBox OSE is distributed in the' \ + '# hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.' \ + '#' \ + '# The contents of this file may alternatively be used under the terms' \ + '# of the Common Development and Distribution License Version 1.0' \ + '# (CDDL) only, as it comes in the "COPYING.CDDL" file of the' \ + '# VirtualBox OSE distribution, in which case the provisions of the' \ + '# CDDL are applicable instead of those of the GPL.' \ + '#' \ + '# You may elect to license modified versions of this file under the' \ + '# terms and conditions of either the GPL or the CDDL or both.' \ + '#' \ + '' + $(SED) -n \ + -e '/^ *BS3_CMN_PROTO_STUB/p' \ + -e '/^ *BS3_CMN_PROTO_FARSTUB/p' \ + -e '/^ *BS3_MODE_PROTO_STUB/p' \ + -e '/^ *BS3_MODE_PROTO_FARSTUB/p' \ + $(filter %.h,$^) \ + | sort \ + | $(SED) -n \ + -e 's/^ *BS3_CMN_PROTO_STUB([^,]*, *\([a-zA-Z_][a-zA-Z0-9_]*\) *,.*$(DOLLAR)/\$(DOLLAR)(call BS3KIT_FN_GEN_CMN_NEARSTUB,bs3kit-common-16,\1)/p' \ + -e 's/^ *BS3_MODE_PROTO_STUB([^,]*, *\([a-zA-Z_][a-zA-Z0-9_]*\) *,.*$(DOLLAR)/\$(DOLLAR)(call BS3KIT_FN_GEN_MODE_NEARSTUB,bs3kit-common-16,\1)/p' \ + -e 's/^ *BS3_CMN_PROTO_FARSTUB( *\([^,]*\),[^,]*, *\([a-zA-Z_][a-zA-Z0-9_]*\) *,.*$(DOLLAR)/\$(DOLLAR)(call BS3KIT_FN_GEN_CMN_FARSTUB,bs3kit-common-16,\2,\1)/p' \ + -e 's/^ *BS3_MODE_PROTO_FARSTUB( *\([^,]*\),[^,]*, *\([a-zA-Z_][a-zA-Z0-9_]*\) *,.*$(DOLLAR)/\$(DOLLAR)(call BS3KIT_FN_GEN_MODE_FARSTUB,bs3kit-common-16,\2,\1)/p' \ + --append "$(dir $<)$@" + +bs3kit-update:: bs3kit-autostubs.kmk bs3kit-mangling-code-define.h bs3kit-mangling-code-undef.h +.NOTPARALLEL: bs3kit-autostubs.kmk bs3kit-mangling-code-define.h bs3kit-mangling-code-undef.h + + +include $(FILE_KBUILD_SUB_FOOTER) + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/VBoxBs3Linker.cpp b/src/VBox/ValidationKit/bootsectors/bs3kit/VBoxBs3Linker.cpp new file mode 100644 index 00000000..40407d69 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/VBoxBs3Linker.cpp @@ -0,0 +1,328 @@ +/* $Id: VBoxBs3Linker.cpp $ */ +/** @file + * VirtualBox Validation Kit - Boot Sector 3 "linker". + */ + +/* + * Copyright (C) 2006-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <iprt/types.h> +#include <iprt/assert.h> + + +/********************************************************************************************************************************* +* Structures and Typedefs * +*********************************************************************************************************************************/ +#pragma pack(1) +typedef struct BS3BOOTSECTOR +{ + uint8_t abJmp[3]; + char abOemId[8]; + /** @name EBPB, DOS 4.0 style. + * @{ */ + uint16_t cBytesPerSector; /**< 00bh */ + uint8_t cSectorsPerCluster; /**< 00dh */ + uint16_t cReservedSectors; /**< 00eh */ + uint8_t cFATs; /**< 010h */ + uint16_t cRootDirEntries; /**< 011h */ + uint16_t cTotalSectors; /**< 013h */ + uint8_t bMediaDescriptor; /**< 015h */ + uint16_t cSectorsPerFAT; /**< 016h */ + uint16_t cPhysSectorsPerTrack; /**< 018h */ + uint16_t cHeads; /**< 01ah */ + uint32_t cHiddentSectors; /**< 01ch */ + uint32_t cLargeTotalSectors; /**< 020h - We (ab)use this to indicate the number of sectors to load. */ + uint8_t bBootDrv; /**< 024h */ + uint8_t bFlagsEtc; /**< 025h */ + uint8_t bExtendedSignature; /**< 026h */ + uint32_t dwSerialNumber; /**< 027h */ + char abLabel[11]; /**< 02bh */ + char abFSType[8]; /**< 036h */ + /** @} */ +} BS3BOOTSECTOR; +#pragma pack() +typedef BS3BOOTSECTOR *PBS3BOOTSECTOR; + +AssertCompileMemberOffset(BS3BOOTSECTOR, cLargeTotalSectors, 0x20); +AssertCompileMemberOffset(BS3BOOTSECTOR, abLabel, 0x2b); +AssertCompileMemberOffset(BS3BOOTSECTOR, abFSType, 0x36); + +#define BS3_OEMID "BS3Kit\n\n" +#define BS3_FSTYPE "RawCode\n" +#define BS3_LABEL "VirtualBox\n" +#define BS3_MAX_SIZE UINT32_C(491520) /* 480KB */ + + +int main(int argc, char **argv) +{ + const char *pszOutput = NULL; + struct BS3LNKINPUT + { + const char *pszFile; + FILE *pFile; + uint32_t cbFile; + } *paInputs = (struct BS3LNKINPUT *)calloc(sizeof(paInputs[0]), argc); + unsigned cInputs = 0; + uint32_t cSectors = 0; + + /* + * Scan the arguments. + */ + for (int i = 1; i < argc; i++) + { + if (argv[i][0] == '-') + { + const char *pszOpt = &argv[i][1]; + if (*pszOpt == '-') + { + /* Convert long options to short ones. */ + pszOpt--; + if (!strcmp(pszOpt, "--output")) + pszOpt = "o"; + else if (!strcmp(pszOpt, "--version")) + pszOpt = "V"; + else if (!strcmp(pszOpt, "--help")) + pszOpt = "h"; + else + { + fprintf(stderr, "syntax errro: Unknown options '%s'\n", pszOpt); + free(paInputs); + return 2; + } + } + + /* Process the list of short options. */ + while (*pszOpt) + { + switch (*pszOpt++) + { + case 'o': + { + const char *pszValue = pszOpt; + pszOpt = strchr(pszOpt, '\0'); + if (*pszValue == '=') + pszValue++; + else if (!*pszValue) + { + if (i + 1 >= argc) + { + fprintf(stderr, "syntax error: The --output option expects a filename.\n"); + free(paInputs); + return 12; + } + pszValue = argv[++i]; + } + if (pszOutput) + { + fprintf(stderr, "Only one output file is allowed. You've specified '%s' and '%s'\n", + pszOutput, pszValue); + free(paInputs); + return 2; + } + pszOutput = pszValue; + pszOpt = ""; + break; + } + + case 'V': + printf("%s\n", "$Revision: 127855 $"); + free(paInputs); + return 0; + + case '?': + case 'h': + printf("usage: %s [options] -o <output> <input1> [input2 ... [inputN]]\n", + argv[0]); + free(paInputs); + return 0; + } + } + } + else + { + /* + * Add to input file collection. + */ + paInputs[cInputs].pszFile = argv[i]; +#if defined(RT_OS_OS2) || defined(RT_OS_WINDOWS) + FILE *pFile = fopen(paInputs[cInputs].pszFile, "rb"); +#else + FILE *pFile = fopen(paInputs[cInputs].pszFile, "r"); +#endif + if (pFile) + { + if (fseek(pFile, 0, SEEK_END) == 0) + { + paInputs[cInputs].cbFile = (uint32_t)ftell(pFile); + if (fseek(pFile, 0, SEEK_SET) == 0) + { + if (cInputs != 0 || paInputs[cInputs].cbFile == 512) + { + cSectors += RT_ALIGN_32(paInputs[cInputs].cbFile, 512) / 512; + if (cSectors <= BS3_MAX_SIZE / 512) + { + if (cSectors > 0) + { + paInputs[cInputs].pFile = pFile; + pFile = NULL; + } + else + fprintf(stderr, "error: empty input file: '%s'\n", paInputs[cInputs].pszFile); + } + else + fprintf(stderr, "error: input is too big: %u bytes, %u sectors (max %u bytes, %u sectors)\n" + "info: detected loading '%s'\n", + cSectors * 512, cSectors, BS3_MAX_SIZE, BS3_MAX_SIZE / 512, + paInputs[cInputs].pszFile); + } + else + fprintf(stderr, "error: first input file (%s) must be exactly 512 bytes\n", paInputs[cInputs].pszFile); + } + else + fprintf(stderr, "error: seeking to start of '%s' failed\n", paInputs[cInputs].pszFile); + } + else + fprintf(stderr, "error: seeking to end of '%s' failed\n", paInputs[cInputs].pszFile); + } + else + fprintf(stderr, "error: Failed to open input file '%s' for reading\n", paInputs[cInputs].pszFile); + if (pFile) + { + free(paInputs); + return 1; + } + cInputs++; + } + } + + if (!pszOutput) + { + fprintf(stderr, "syntax error: No output file was specified (-o or --output).\n"); + free(paInputs); + return 2; + } + if (cInputs == 0) + { + fprintf(stderr, "syntax error: No input files was specified.\n"); + free(paInputs); + return 2; + } + + /* + * Do the job. + */ + /* Open the output file. */ +#if defined(RT_OS_OS2) || defined(RT_OS_WINDOWS) + FILE *pOutput = fopen(pszOutput, "wb"); +#else + FILE *pOutput = fopen(pszOutput, "w"); +#endif + if (!pOutput) + { + fprintf(stderr, "error: Failed to open output file '%s' for writing\n", pszOutput); + free(paInputs); + return 1; + } + + /* Copy the input files to the output file, with sector padding applied. */ + int rcExit = 0; + size_t off = 0; + for (unsigned i = 0; i < cInputs && rcExit == 0; i++) + { + uint8_t abBuf[4096]; /* Must be multiple of 512! */ + uint32_t cbToRead = paInputs[i].cbFile; + while (cbToRead > 0) + { + /* Read a block from the input file. */ + uint32_t const cbThisRead = RT_MIN(cbToRead, sizeof(abBuf)); + size_t cbRead = fread(abBuf, sizeof(uint8_t), cbThisRead, paInputs[i].pFile); + if (cbRead != cbThisRead) + { + fprintf(stderr, "error: Error reading '%s' (got %d bytes, wanted %u).\n", + paInputs[i].pszFile, (int)cbRead, (unsigned)cbThisRead); + rcExit = 1; + break; + } + cbToRead -= cbThisRead; + + /* Padd the end of the file if necessary. */ + if ((cbRead & 0x1ff) != 0) + { + memset(&abBuf[cbRead], 0, 4096 - cbRead); + cbRead = (cbRead + 0x1ff) & ~0x1ffU; + } + + /* Patch the BPB of the first file. */ + if (off == 0) + { + PBS3BOOTSECTOR pBs = (PBS3BOOTSECTOR)&abBuf[0]; + if ( memcmp(pBs->abLabel, RT_STR_TUPLE(BS3_LABEL)) == 0 + && memcmp(pBs->abFSType, RT_STR_TUPLE(BS3_FSTYPE)) == 0 + && memcmp(pBs->abOemId, RT_STR_TUPLE(BS3_OEMID)) == 0) + pBs->cLargeTotalSectors = cSectors; + else + { + fprintf(stderr, "error: Didn't find magic strings in the first file (%s).\n", paInputs[i].pszFile); + rcExit = 1; + } + } + + /* Write the block to the output file. */ + if (fwrite(abBuf, sizeof(uint8_t), cbRead, pOutput) == cbRead) + off += cbRead; + else + { + fprintf(stderr, "error: fwrite failed\n"); + rcExit = 1; + break; + } + } + + if (ferror(paInputs[i].pFile)) + { + fprintf(stderr, "error: Error reading '%s'.\n", paInputs[i].pszFile); + rcExit = 1; + } + } + + /* Close the input files. */ + for (unsigned i = 0; i < cInputs && rcExit == 0; i++) + fclose(paInputs[i].pFile); + free(paInputs); + + /* Finally, close the output file (can fail because of buffered data). */ + if (fclose(stderr) != 0) + { + fprintf(stderr, "error: Error closing '%s'.\n", pszOutput); + rcExit = 1; + } + + fclose(pOutput); + return rcExit; +} + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/VBoxBs3ObjConverter.cpp b/src/VBox/ValidationKit/bootsectors/bs3kit/VBoxBs3ObjConverter.cpp new file mode 100644 index 00000000..fb4c4fc1 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/VBoxBs3ObjConverter.cpp @@ -0,0 +1,5499 @@ +/* $Id: VBoxBs3ObjConverter.cpp $ */ +/** @file + * VirtualBox Validation Kit - Boot Sector 3 object file convert. + */ + +/* + * Copyright (C) 2006-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <errno.h> +#include <iprt/types.h> +#include <iprt/ctype.h> +#include <iprt/assert.h> +#include <iprt/sort.h> +#include <iprt/x86.h> + +#include <iprt/formats/elf64.h> +#include <iprt/formats/elf-amd64.h> +#include <iprt/formats/pecoff.h> +#include <iprt/formats/omf.h> +#include <iprt/formats/codeview.h> + + +/********************************************************************************************************************************* +* Defined Constants And Macros * +*********************************************************************************************************************************/ +#if ARCH_BITS == 64 && !defined(RT_OS_WINDOWS) && !defined(RT_OS_DARWIN) +# define ELF_FMT_X64 "lx" +# define ELF_FMT_D64 "ld" +#else +# define ELF_FMT_X64 "llx" +# define ELF_FMT_D64 "lld" +#endif + +/** Compares an OMF string with a constant string. */ +#define IS_OMF_STR_EQUAL_EX(a_cch1, a_pch1, a_szConst2) \ + ( (a_cch1) == sizeof(a_szConst2) - 1 && memcmp(a_pch1, a_szConst2, sizeof(a_szConst2) - 1) == 0 ) + +/** Compares an OMF string with a constant string. */ +#define IS_OMF_STR_EQUAL(a_pchZeroPrefixed, a_szConst2) \ + IS_OMF_STR_EQUAL_EX((uint8_t)((a_pchZeroPrefixed)[0]), &((a_pchZeroPrefixed)[1]), a_szConst2) + + +/********************************************************************************************************************************* +* Global Variables * +*********************************************************************************************************************************/ +/** Verbosity level. */ +static unsigned g_cVerbose = 0; +/** Indicates that it's output from the 16-bit watcom C or C++ compiler. + * We will do some massaging for fixup records when this is used. */ +static bool g_f16BitWatcomC = false; + + +/** + * Opens a file for binary reading or writing. + * + * @returns File stream handle. + * @param pszFile The name of the file. + * @param fWrite Whether to open for writing or reading. + */ +static FILE *openfile(const char *pszFile, bool fWrite) +{ +#if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2) + FILE *pFile = fopen(pszFile, fWrite ? "wb" : "rb"); +#else + FILE *pFile = fopen(pszFile, fWrite ? "w" : "r"); +#endif + if (!pFile) + fprintf(stderr, "error: Failed to open '%s' for %s: %s (%d)\n", + pszFile, fWrite ? "writing" : "reading", strerror(errno), errno); + return pFile; +} + + +/** + * Read the given file into memory. + * + * @returns true on success, false on failure. + * @param pszFile The file to read. + * @param ppvFile Where to return the memory. + * @param pcbFile Where to return the size. + */ +static bool readfile(const char *pszFile, void **ppvFile, size_t *pcbFile) +{ + FILE *pFile = openfile(pszFile, false); + if (pFile) + { + /* + * Figure the size. + */ + if (fseek(pFile, 0, SEEK_END) == 0) + { + long cbFile = ftell(pFile); + if (cbFile > 0) + { + if (fseek(pFile, SEEK_SET, 0) == 0) + { + /* + * Allocate and read content. + */ + void *pvFile = malloc((size_t)cbFile); + if (pvFile) + { + if (fread(pvFile, cbFile, 1, pFile) == 1) + { + *ppvFile = pvFile; + *pcbFile = (size_t)cbFile; + fclose(pFile); + return true; + } + free(pvFile); + fprintf(stderr, "error: fread failed in '%s': %s (%d)\n", pszFile, strerror(errno), errno); + } + else + fprintf(stderr, "error: failed to allocate %ld bytes of memory for '%s'\n", cbFile, pszFile); + } + else + fprintf(stderr, "error: fseek #2 failed in '%s': %s (%d)\n", pszFile, strerror(errno), errno); + } + else + fprintf(stderr, "error: ftell failed in '%s': %s (%d)\n", pszFile, strerror(errno), errno); + } + else + fprintf(stderr, "error: fseek #1 failed in '%s': %s (%d)\n", pszFile, strerror(errno), errno); + fclose(pFile); + } + return false; +} + + +/** + * Write the given file into memory. + * + * @returns true on success, false on failure. + * @param pszFile The file to write. + * @param pvFile Where to return the memory. + * @param cbFile Where to return the size. + */ +static bool writefile(const char *pszFile, void const *pvFile, size_t cbFile) +{ + remove(pszFile); + + FILE *pFile = openfile(pszFile, true); + if (pFile) + { + if (fwrite(pvFile, cbFile, 1, pFile) == 1) + { + fclose(pFile); + return true; + } + fprintf(stderr, "error: fwrite failed in '%s': %s (%d)\n", pszFile, strerror(errno), errno); + fclose(pFile); + } + return false; +} + + +/** + * Reports an error and returns false. + * + * @returns false + * @param pszFile The filename. + * @param pszFormat The message format string. + * @param ... Format arguments. + */ +static bool error(const char *pszFile, const char *pszFormat, ...) +{ + fflush(stdout); + fprintf(stderr, "error: %s: ", pszFile); + va_list va; + va_start(va, pszFormat); + vfprintf(stderr, pszFormat, va); + va_end(va); + return false; +} + + + +/********************************************************************************************************************************* +* Common OMF Writer * +*********************************************************************************************************************************/ + +/** Entry for each segment/section in the source format for mapping it to a + * segment defintion. */ +typedef struct OMFTOSEGDEF +{ + /** The segment defintion index of the section, UINT16_MAX if not translated. */ + uint16_t iSegDef; + /** The group index for this segment, UINT16_MAX if not applicable. */ + uint16_t iGrpDef; + /** The class name table entry, UINT16_MAX if not applicable. */ + uint16_t iClassNm; + /** The group name for this segment, UINT16_MAX if not applicable. */ + uint16_t iGrpNm; + /** The group name for this segment, UINT16_MAX if not applicable. */ + uint16_t iSegNm; + /** The number of public definitions for this segment. */ + uint32_t cPubDefs; + /** The segment name (OMF). */ + char *pszName; +} OMFTOSEGDEF; +/** Pointer to a segment/section to segdef mapping. */ +typedef OMFTOSEGDEF *POMFTOSEGDEF; + +/** Symbol table translation type. */ +typedef enum OMFSYMTYPE +{ + /** Invalid symbol table entry (aux sym). */ + OMFSYMTYPE_INVALID = 0, + /** Ignored. */ + OMFSYMTYPE_IGNORED, + /** A public defintion. */ + OMFSYMTYPE_PUBDEF, + /** An external definition. */ + OMFSYMTYPE_EXTDEF, + /** A segment reference for fixups. */ + OMFSYMTYPE_SEGDEF, + /** Internal symbol that may be used for fixups. */ + OMFSYMTYPE_INTERNAL +} OMFSYMTYPE; + +/** Symbol table translation. */ +typedef struct OMFSYMBOL +{ + /** What this source symbol table entry should be translated into. */ + OMFSYMTYPE enmType; + /** The OMF table index. UINT16_MAX if not applicable. */ + uint16_t idx; + /** The OMF segment definition index. */ + uint16_t idxSegDef; + /** The OMF group definition index. */ + uint16_t idxGrpDef; +} OMFSYMBOL; +/** Pointer to an source symbol table translation entry. */ +typedef OMFSYMBOL *POMFSYMBOL; + +/** OMF Writer LNAME lookup record. */ +typedef struct OMFWRLNAME +{ + /** Pointer to the next entry with the name hash. */ + struct OMFWRLNAME *pNext; + /** The LNAMES index number. */ + uint16_t idxName; + /** The name length. */ + uint8_t cchName; + /** The name (variable size). */ + char szName[1]; +} OMFWRLNAME; +/** Pointer to the a OMF writer LNAME lookup record. */ +typedef OMFWRLNAME *POMFWRLNAME; + +/** + * OMF converter & writer instance. + */ +typedef struct OMFWRITER +{ + /** The source file name (for bitching). */ + const char *pszSrc; + /** The destination output file. */ + FILE *pDst; + + /** Pointer to the table mapping from source segments/section to segdefs. */ + POMFTOSEGDEF paSegments; + /** Number of source segments/sections. */ + uint32_t cSegments; + + /** Number of entries in the source symbol table. */ + uint32_t cSymbols; + /** Pointer to the table mapping from source symbols to OMF stuff. */ + POMFSYMBOL paSymbols; + + /** LEDATA segment offset. */ + uint32_t offSeg; + /** Start of the current LEDATA record. */ + uint32_t offSegRec; + /** The LEDATA end segment offset. */ + uint32_t offSegEnd; + /** The current LEDATA segment. */ + uint16_t idx; + + /** The index of the next list of names entry. */ + uint16_t idxNextName; + + /** The current record size. */ + uint16_t cbRec; + /** The current record type */ + uint8_t bType; + /** The record data buffer (too large, but whatever). */ + uint8_t abData[_1K + 64]; + + /** Current FIXUPP entry. */ + uint8_t iFixupp; + /** FIXUPP records being prepared for LEDATA currently stashed in abData. + * We may have to adjust addend values in the LEDATA when converting to OMF + * fixups. */ + struct + { + uint16_t cbRec; + uint8_t abData[_1K + 64]; + uint8_t abAlign[2]; /**< Alignment padding. */ + } aFixupps[3]; + + /** The index of the FLAT group. */ + uint16_t idxGrpFlat; + /** The EXTDEF index of the __ImageBase symbol. */ + uint16_t idxExtImageBase; + + /** LNAME lookup hash table. To avoid too many duplicates. */ + POMFWRLNAME apNameLookup[63]; +} OMFWRITE; +/** Pointer to an OMF writer. */ +typedef OMFWRITE *POMFWRITER; + + +/** + * Creates an OMF writer instance. + */ +static POMFWRITER omfWriter_Create(const char *pszSrc, uint32_t cSegments, uint32_t cSymbols, FILE *pDst) +{ + POMFWRITER pThis = (POMFWRITER)calloc(sizeof(OMFWRITER), 1); + if (pThis) + { + pThis->pszSrc = pszSrc; + pThis->idxNextName = 1; /* We start counting at 1. */ + pThis->cSegments = cSegments; + pThis->paSegments = (POMFTOSEGDEF)calloc(sizeof(OMFTOSEGDEF), cSegments); + if (pThis->paSegments) + { + pThis->cSymbols = cSymbols; + pThis->paSymbols = (POMFSYMBOL)calloc(sizeof(OMFSYMBOL), cSymbols); + if (pThis->paSymbols) + { + pThis->pDst = pDst; + return pThis; + } + free(pThis->paSegments); + } + free(pThis); + } + error(pszSrc, "Out of memory!\n"); + return NULL; +} + +/** + * Destroys the given OMF writer instance. + * @param pThis OMF writer instance. + */ +static void omfWriter_Destroy(POMFWRITER pThis) +{ + free(pThis->paSymbols); + + for (uint32_t i = 0; i < pThis->cSegments; i++) + if (pThis->paSegments[i].pszName) + free(pThis->paSegments[i].pszName); + + free(pThis->paSegments); + + uint32_t i = RT_ELEMENTS(pThis->apNameLookup); + while (i-- > 0) + { + POMFWRLNAME pNext = pThis->apNameLookup[i]; + pThis->apNameLookup[i] = NULL; + while (pNext) + { + POMFWRLNAME pFree = pNext; + pNext = pNext->pNext; + free(pFree); + } + } + + free(pThis); +} + +static bool omfWriter_RecBegin(POMFWRITER pThis, uint8_t bType) +{ + pThis->bType = bType; + pThis->cbRec = 0; + return true; +} + +static bool omfWriter_RecAddU8(POMFWRITER pThis, uint8_t b) +{ + if (pThis->cbRec < OMF_MAX_RECORD_PAYLOAD) + { + pThis->abData[pThis->cbRec++] = b; + return true; + } + return error(pThis->pszSrc, "Exceeded max OMF record length (bType=%#x)!\n", pThis->bType); +} + +static bool omfWriter_RecAddU16(POMFWRITER pThis, uint16_t u16) +{ + if (pThis->cbRec + 2U <= OMF_MAX_RECORD_PAYLOAD) + { + pThis->abData[pThis->cbRec++] = (uint8_t)u16; + pThis->abData[pThis->cbRec++] = (uint8_t)(u16 >> 8); + return true; + } + return error(pThis->pszSrc, "Exceeded max OMF record length (bType=%#x)!\n", pThis->bType); +} + +static bool omfWriter_RecAddU32(POMFWRITER pThis, uint32_t u32) +{ + if (pThis->cbRec + 4U <= OMF_MAX_RECORD_PAYLOAD) + { + pThis->abData[pThis->cbRec++] = (uint8_t)u32; + pThis->abData[pThis->cbRec++] = (uint8_t)(u32 >> 8); + pThis->abData[pThis->cbRec++] = (uint8_t)(u32 >> 16); + pThis->abData[pThis->cbRec++] = (uint8_t)(u32 >> 24); + return true; + } + return error(pThis->pszSrc, "Exceeded max OMF record length (bType=%#x)!\n", pThis->bType); +} + +static bool omfWriter_RecAddIdx(POMFWRITER pThis, uint16_t idx) +{ + if (idx < 128) + return omfWriter_RecAddU8(pThis, (uint8_t)idx); + if (idx < _32K) + return omfWriter_RecAddU8(pThis, (uint8_t)(idx >> 8) | 0x80) + && omfWriter_RecAddU8(pThis, (uint8_t)idx); + return error(pThis->pszSrc, "Index out of range %#x\n", idx); +} + +static bool omfWriter_RecAddBytes(POMFWRITER pThis, const void *pvData, size_t cbData) +{ + const uint16_t cbNasmHack = OMF_MAX_RECORD_PAYLOAD + 1; + if (cbData + pThis->cbRec <= cbNasmHack) + { + memcpy(&pThis->abData[pThis->cbRec], pvData, cbData); + pThis->cbRec += (uint16_t)cbData; + return true; + } + return error(pThis->pszSrc, "Exceeded max OMF record length (bType=%#x, cbData=%#x, cbRec=%#x, max=%#x)!\n", + pThis->bType, (unsigned)cbData, pThis->cbRec, OMF_MAX_RECORD_PAYLOAD); +} + +static bool omfWriter_RecAddStringNEx(POMFWRITER pThis, const char *pchString, size_t cchString, bool fPrependUnderscore) +{ + if (cchString < 256) + { + return omfWriter_RecAddU8(pThis, (uint8_t)cchString + fPrependUnderscore) + && (!fPrependUnderscore || omfWriter_RecAddU8(pThis, '_')) + && omfWriter_RecAddBytes(pThis, pchString, cchString); + } + return error(pThis->pszSrc, "String too long (%u bytes): '%*.*s'\n", + (unsigned)cchString, (int)cchString, (int)cchString, pchString); +} + +static bool omfWriter_RecAddStringN(POMFWRITER pThis, const char *pchString, size_t cchString) +{ + return omfWriter_RecAddStringNEx(pThis, pchString, cchString, false /*fPrependUnderscore*/); +} + +static bool omfWriter_RecAddString(POMFWRITER pThis, const char *pszString) +{ + return omfWriter_RecAddStringNEx(pThis, pszString, strlen(pszString), false /*fPrependUnderscore*/); +} + +static bool omfWriter_RecEnd(POMFWRITER pThis, bool fAddCrc) +{ + if ( !fAddCrc + || omfWriter_RecAddU8(pThis, 0)) + { + OMFRECHDR RecHdr = { pThis->bType, RT_H2LE_U16(pThis->cbRec) }; + if ( fwrite(&RecHdr, sizeof(RecHdr), 1, pThis->pDst) == 1 + && fwrite(pThis->abData, pThis->cbRec, 1, pThis->pDst) == 1) + { + pThis->bType = 0; + pThis->cbRec = 0; + return true; + } + return error(pThis->pszSrc, "Write error\n"); + } + return false; +} + +static bool omfWriter_RecEndWithCrc(POMFWRITER pThis) +{ + return omfWriter_RecEnd(pThis, true /*fAddCrc*/); +} + + +static bool omfWriter_BeginModule(POMFWRITER pThis, const char *pszFile) +{ + return omfWriter_RecBegin(pThis, OMF_THEADR) + && omfWriter_RecAddString(pThis, pszFile) + && omfWriter_RecEndWithCrc(pThis); +} + + +/** + * Simple stupid string hashing function (for LNAMES) + * @returns 8-bit hash. + * @param pchName The string. + * @param cchName The string length. + */ +DECLINLINE(uint8_t) omfWriter_HashStrU8(const char *pchName, size_t cchName) +{ + if (cchName) + return (uint8_t)(cchName + pchName[cchName >> 1]); + return 0; +} + +/** + * Looks up a LNAME. + * + * @returns Index (0..32K) if found, UINT16_MAX if not found. + * @param pThis The OMF writer. + * @param pchName The name to look up. + * @param cchName The length of the name. + */ +static uint16_t omfWriter_LNamesLookupN(POMFWRITER pThis, const char *pchName, size_t cchName) +{ + uint8_t uHash = omfWriter_HashStrU8(pchName, cchName); + uHash %= RT_ELEMENTS(pThis->apNameLookup); + + POMFWRLNAME pCur = pThis->apNameLookup[uHash]; + while (pCur) + { + if ( pCur->cchName == cchName + && memcmp(pCur->szName, pchName, cchName) == 0) + return pCur->idxName; + pCur = pCur->pNext; + } + + return UINT16_MAX; +} + +/** + * Add a LNAME lookup record. + * + * @returns success indicator. + * @param pThis The OMF writer. + * @param pchName The name to look up. + * @param cchName The length of the name. + * @param idxName The name index. + */ +static bool omfWriter_LNamesAddLookup(POMFWRITER pThis, const char *pchName, size_t cchName, uint16_t idxName) +{ + POMFWRLNAME pCur = (POMFWRLNAME)malloc(sizeof(*pCur) + cchName); + if (!pCur) + return error("???", "Out of memory!\n"); + + pCur->idxName = idxName; + pCur->cchName = (uint8_t)cchName; + memcpy(pCur->szName, pchName, cchName); + pCur->szName[cchName] = '\0'; + + uint8_t uHash = omfWriter_HashStrU8(pchName, cchName); + uHash %= RT_ELEMENTS(pThis->apNameLookup); + pCur->pNext = pThis->apNameLookup[uHash]; + pThis->apNameLookup[uHash] = pCur; + + return true; +} + + +static bool omfWriter_LNamesAddN(POMFWRITER pThis, const char *pchName, size_t cchName, uint16_t *pidxName) +{ + /* See if we've already got that name in the list. */ + uint16_t idxName; + if (pidxName) /* If pidxName is NULL, we assume the caller might just be passing stuff thru. */ + { + idxName = omfWriter_LNamesLookupN(pThis, pchName, cchName); + if (idxName != UINT16_MAX) + { + *pidxName = idxName; + return true; + } + } + + /* split? */ + if (pThis->cbRec + 1 /*len*/ + cchName + 1 /*crc*/ > OMF_MAX_RECORD_PAYLOAD) + { + if (pThis->cbRec == 0) + return error(pThis->pszSrc, "Too long LNAME '%*.*s'\n", (int)cchName, (int)cchName, pchName); + if ( !omfWriter_RecEndWithCrc(pThis) + || !omfWriter_RecBegin(pThis, OMF_LNAMES)) + return false; + } + + idxName = pThis->idxNextName++; + if (pidxName) + *pidxName = idxName; + return omfWriter_RecAddStringN(pThis, pchName, cchName) + && omfWriter_LNamesAddLookup(pThis, pchName, cchName, idxName); +} + +static bool omfWriter_LNamesAdd(POMFWRITER pThis, const char *pszName, uint16_t *pidxName) +{ + return omfWriter_LNamesAddN(pThis, pszName, strlen(pszName), pidxName); +} + +static bool omfWriter_LNamesBegin(POMFWRITER pThis, bool fAddZeroEntry) +{ + /* First entry is an empty string. */ + return omfWriter_RecBegin(pThis, OMF_LNAMES) + && ( pThis->idxNextName > 1 + || !fAddZeroEntry + || omfWriter_LNamesAddN(pThis, "", 0, NULL)); +} + +static bool omfWriter_LNamesEnd(POMFWRITER pThis) +{ + return omfWriter_RecEndWithCrc(pThis); +} + + +static bool omfWriter_SegDef(POMFWRITER pThis, uint8_t bSegAttr, uint32_t cbSeg, uint16_t idxSegName, uint16_t idxSegClass, + uint16_t idxOverlay = 1 /* NULL entry */) +{ + return omfWriter_RecBegin(pThis, OMF_SEGDEF32) + && omfWriter_RecAddU8(pThis, bSegAttr) + && omfWriter_RecAddU32(pThis, cbSeg) + && omfWriter_RecAddIdx(pThis, idxSegName) + && omfWriter_RecAddIdx(pThis, idxSegClass) + && omfWriter_RecAddIdx(pThis, idxOverlay) + && omfWriter_RecEndWithCrc(pThis); +} + +static bool omfWriter_SegDef16(POMFWRITER pThis, uint8_t bSegAttr, uint32_t cbSeg, uint16_t idxSegName, uint16_t idxSegClass, + uint16_t idxOverlay = 1 /* NULL entry */) +{ + Assert(cbSeg <= UINT16_MAX); + return omfWriter_RecBegin(pThis, OMF_SEGDEF16) + && omfWriter_RecAddU8(pThis, bSegAttr) + && omfWriter_RecAddU16(pThis, cbSeg) + && omfWriter_RecAddIdx(pThis, idxSegName) + && omfWriter_RecAddIdx(pThis, idxSegClass) + && omfWriter_RecAddIdx(pThis, idxOverlay) + && omfWriter_RecEndWithCrc(pThis); +} + +static bool omfWriter_GrpDefBegin(POMFWRITER pThis, uint16_t idxGrpName) +{ + return omfWriter_RecBegin(pThis, OMF_GRPDEF) + && omfWriter_RecAddIdx(pThis, idxGrpName); +} + +static bool omfWriter_GrpDefAddSegDef(POMFWRITER pThis, uint16_t idxSegDef) +{ + return omfWriter_RecAddU8(pThis, 0xff) + && omfWriter_RecAddIdx(pThis, idxSegDef); +} + +static bool omfWriter_GrpDefEnd(POMFWRITER pThis) +{ + return omfWriter_RecEndWithCrc(pThis); +} + + +static bool omfWriter_PubDefBegin(POMFWRITER pThis, uint16_t idxGrpDef, uint16_t idxSegDef) +{ + return omfWriter_RecBegin(pThis, OMF_PUBDEF32) + && omfWriter_RecAddIdx(pThis, idxGrpDef) + && omfWriter_RecAddIdx(pThis, idxSegDef) + && ( idxSegDef != 0 + || omfWriter_RecAddU16(pThis, 0)); + +} + +static bool omfWriter_PubDefAddN(POMFWRITER pThis, uint32_t uValue, const char *pchString, size_t cchString, + bool fPrependUnderscore) +{ + /* Split? */ + if (pThis->cbRec + 1 + cchString + 4 + 1 + 1 + fPrependUnderscore > OMF_MAX_RECORD_PAYLOAD) + { + if (cchString >= 256) + return error(pThis->pszSrc, "PUBDEF string too long %u ('%s')\n", + (unsigned)cchString, (int)cchString, (int)cchString, pchString); + if (!omfWriter_RecEndWithCrc(pThis)) + return false; + + /* Figure out the initial data length. */ + pThis->cbRec = 1 + ((pThis->abData[0] & 0x80) != 0); + if (pThis->abData[pThis->cbRec] != 0) + pThis->cbRec += 1 + ((pThis->abData[pThis->cbRec] & 0x80) != 0); + else + pThis->cbRec += 3; + pThis->bType = OMF_PUBDEF32; + } + + return omfWriter_RecAddStringNEx(pThis, pchString, cchString, fPrependUnderscore) + && omfWriter_RecAddU32(pThis, uValue) + && omfWriter_RecAddIdx(pThis, 0); /* type */ +} + +static bool omfWriter_PubDefAdd(POMFWRITER pThis, uint32_t uValue, const char *pszString, bool fPrependUnderscore) +{ + return omfWriter_PubDefAddN(pThis, uValue, pszString, strlen(pszString), fPrependUnderscore); +} + +static bool omfWriter_PubDefEnd(POMFWRITER pThis) +{ + return omfWriter_RecEndWithCrc(pThis); +} + +/** + * EXTDEF - Begin record. + */ +static bool omfWriter_ExtDefBegin(POMFWRITER pThis) +{ + return omfWriter_RecBegin(pThis, OMF_EXTDEF); + +} + +/** + * EXTDEF - Add an entry, split record if necessary. + */ +static bool omfWriter_ExtDefAddN(POMFWRITER pThis, const char *pchString, size_t cchString, uint16_t idxType, + bool fPrependUnderscore) +{ + /* Split? */ + if (pThis->cbRec + 1 + cchString + 1 + 1 + fPrependUnderscore > OMF_MAX_RECORD_PAYLOAD) + { + if (cchString >= 256) + return error(pThis->pszSrc, "EXTDEF string too long %u ('%s')\n", + (unsigned)cchString, (int)cchString, (int)cchString, pchString); + if ( !omfWriter_RecEndWithCrc(pThis) + || !omfWriter_RecBegin(pThis, OMF_EXTDEF)) + return false; + } + + return omfWriter_RecAddStringNEx(pThis, pchString, cchString, fPrependUnderscore) + && omfWriter_RecAddIdx(pThis, idxType); /* type */ +} + +/** + * EXTDEF - Add an entry, split record if necessary. + */ +static bool omfWriter_ExtDefAdd(POMFWRITER pThis, const char *pszString, bool fPrependUnderscore) +{ + return omfWriter_ExtDefAddN(pThis, pszString, strlen(pszString), 0, fPrependUnderscore); +} + +/** + * EXTDEF - End of record. + */ +static bool omfWriter_ExtDefEnd(POMFWRITER pThis) +{ + return omfWriter_RecEndWithCrc(pThis); +} + +/** + * COMENT/LINK_PASS_SEP - Add a link pass separator comment. + */ +static bool omfWriter_LinkPassSeparator(POMFWRITER pThis) +{ + return omfWriter_RecBegin(pThis, OMF_COMENT) + && omfWriter_RecAddU8(pThis, OMF_CTYP_NO_LIST) + && omfWriter_RecAddU8(pThis, OMF_CCLS_LINK_PASS_SEP) + && omfWriter_RecAddU8(pThis, 1) + && omfWriter_RecEndWithCrc(pThis); +} + + +/** + * LEDATA + FIXUPP - Begin records. + */ +static bool omfWriter_LEDataBegin(POMFWRITER pThis, uint16_t idxSeg, uint32_t offSeg) +{ + if ( omfWriter_RecBegin(pThis, OMF_LEDATA32) + && omfWriter_RecAddIdx(pThis, idxSeg) + && omfWriter_RecAddU32(pThis, offSeg)) + { + pThis->idx = idxSeg; + pThis->offSeg = offSeg; + pThis->offSegRec = offSeg; + pThis->offSegEnd = offSeg + OMF_MAX_RECORD_PAYLOAD - 1 /*CRC*/ - pThis->cbRec; + pThis->offSegEnd &= ~(uint32_t)7; /* qword align. */ + + /* Reset the associated FIXUPP records. */ + pThis->iFixupp = 0; + for (unsigned i = 0; i < RT_ELEMENTS(pThis->aFixupps); i++) + pThis->aFixupps[i].cbRec = 0; + return true; + } + return false; +} + +/** + * LEDATA + FIXUPP - Begin records. + */ +static bool omfWriter_LEDataBeginEx(POMFWRITER pThis, uint16_t idxSeg, uint32_t offSeg, + uint32_t cbData, uint32_t cbRawData, void const *pbRawData, uint8_t **ppbData) +{ + if ( omfWriter_RecBegin(pThis, OMF_LEDATA32) + && omfWriter_RecAddIdx(pThis, idxSeg) + && omfWriter_RecAddU32(pThis, offSeg)) + { + if ( cbData <= _1K + && pThis->cbRec + cbData + 1 <= OMF_MAX_RECORD_PAYLOAD) + { + uint8_t *pbDst = &pThis->abData[pThis->cbRec]; + if (ppbData) + *ppbData = pbDst; + + if (cbRawData) + memcpy(pbDst, pbRawData, RT_MIN(cbData, cbRawData)); + if (cbData > cbRawData) + memset(&pbDst[cbRawData], 0, cbData - cbRawData); + + pThis->cbRec += cbData; + pThis->idx = idxSeg; + pThis->offSegRec = offSeg; + pThis->offSeg = offSeg + cbData; + pThis->offSegEnd = offSeg + cbData; + + /* Reset the associated FIXUPP records. */ + pThis->iFixupp = 0; + for (unsigned i = 0; i < RT_ELEMENTS(pThis->aFixupps); i++) + pThis->aFixupps[i].cbRec = 0; + return true; + } + error(pThis->pszSrc, "Too much data for LEDATA record! (%#x)\n", (unsigned)cbData); + } + return false; +} + +/** + * LEDATA + FIXUPP - Add FIXUPP subrecord bytes, split if necessary. + */ +static bool omfWriter_LEDataAddFixuppBytes(POMFWRITER pThis, void *pvSubRec, size_t cbSubRec) +{ + /* Split? */ + unsigned iFixupp = pThis->iFixupp; + if (pThis->aFixupps[iFixupp].cbRec + cbSubRec >= OMF_MAX_RECORD_PAYLOAD) + { + if (g_cVerbose >= 2) + printf("debug: FIXUPP split\n"); + iFixupp++; + if (iFixupp >= RT_ELEMENTS(pThis->aFixupps)) + return error(pThis->pszSrc, "Out of FIXUPP records\n"); + pThis->iFixupp = iFixupp; + pThis->aFixupps[iFixupp].cbRec = 0; /* paranoia */ + } + + /* Append the sub-record data. */ + memcpy(&pThis->aFixupps[iFixupp].abData[pThis->aFixupps[iFixupp].cbRec], pvSubRec, cbSubRec); + pThis->aFixupps[iFixupp].cbRec += (uint16_t)cbSubRec; + return true; +} + +/** + * LEDATA + FIXUPP - Add fixup, split if necessary. + */ +static bool omfWriter_LEDataAddFixup(POMFWRITER pThis, uint16_t offDataRec, bool fSelfRel, uint8_t bLocation, + uint8_t bFrame, uint16_t idxFrame, + uint8_t bTarget, uint16_t idxTarget, bool fTargetDisp, uint32_t offTargetDisp) +{ + if (g_cVerbose >= 2) + printf("debug: FIXUP[%#x]: off=%#x frame=%u:%#x target=%u:%#x disp=%d:%#x\n", pThis->aFixupps[pThis->iFixupp].cbRec, + offDataRec, bFrame, idxFrame, bTarget, idxTarget, fTargetDisp, offTargetDisp); + + if ( offDataRec >= _1K + || bFrame >= 6 + || bTarget > 6 + || idxFrame >= _32K + || idxTarget >= _32K + || fTargetDisp != (bTarget <= OMF_FIX_T_FRAME_NO) ) + return error(pThis->pszSrc, + "Internal error: offDataRec=%#x bFrame=%u idxFrame=%#x bTarget=%u idxTarget=%#x fTargetDisp=%d offTargetDisp=%#x\n", + offDataRec, bFrame, idxFrame, bTarget, idxTarget, fTargetDisp, offTargetDisp); + + + /* + * Encode the FIXUP subrecord. + */ + uint8_t abFixup[16]; + uint8_t off = 0; + /* Location */ + abFixup[off++] = (offDataRec >> 8) | (bLocation << 2) | ((uint8_t)!fSelfRel << 6) | 0x80; + abFixup[off++] = (uint8_t)offDataRec; + /* Fix Data */ + abFixup[off++] = 0x00 /*F=0*/ | (bFrame << 4) | 0x00 /*T=0*/ | bTarget; + /* Frame Datum */ + if (bFrame <= OMF_FIX_F_FRAME_NO) + { + if (idxFrame >= 128) + abFixup[off++] = (uint8_t)(idxFrame >> 8) | 0x80; + abFixup[off++] = (uint8_t)idxFrame; + } + /* Target Datum */ + if (idxTarget >= 128) + abFixup[off++] = (uint8_t)(idxTarget >> 8) | 0x80; + abFixup[off++] = (uint8_t)idxTarget; + /* Target Displacement */ + if (fTargetDisp) + { + abFixup[off++] = RT_BYTE1(offTargetDisp); + abFixup[off++] = RT_BYTE2(offTargetDisp); + abFixup[off++] = RT_BYTE3(offTargetDisp); + abFixup[off++] = RT_BYTE4(offTargetDisp); + } + + return omfWriter_LEDataAddFixuppBytes(pThis, abFixup, off); +} + +/** + * LEDATA + FIXUPP - Add simple fixup, split if necessary. + */ +static bool omfWriter_LEDataAddFixupNoDisp(POMFWRITER pThis, uint16_t offDataRec, uint8_t bLocation, + uint8_t bFrame, uint16_t idxFrame, uint8_t bTarget, uint16_t idxTarget) +{ + return omfWriter_LEDataAddFixup(pThis, offDataRec, false /*fSelfRel*/, bLocation, bFrame, idxFrame, bTarget, idxTarget, + false /*fTargetDisp*/, 0 /*offTargetDisp*/); +} + + +/** + * LEDATA + FIXUPP - End of records. + */ +static bool omfWriter_LEDataEnd(POMFWRITER pThis) +{ + if (omfWriter_RecEndWithCrc(pThis)) + { + for (unsigned iFixupp = 0; iFixupp <= pThis->iFixupp; iFixupp++) + { + uint16_t const cbRec = pThis->aFixupps[iFixupp].cbRec; + if (!cbRec) + break; + if (g_cVerbose >= 3) + printf("debug: FIXUPP32 #%u cbRec=%#x\n", iFixupp, cbRec); + if ( !omfWriter_RecBegin(pThis, OMF_FIXUPP32) + || !omfWriter_RecAddBytes(pThis, pThis->aFixupps[iFixupp].abData, cbRec) + || !omfWriter_RecEndWithCrc(pThis)) + return false; + } + pThis->iFixupp = 0; + return true; + } + return false; +} + +/** + * LEDATA + FIXUPP - Splits the LEDATA record. + */ +static bool omfWriter_LEDataSplit(POMFWRITER pThis) +{ + return omfWriter_LEDataEnd(pThis) + && omfWriter_LEDataBegin(pThis, pThis->idx, pThis->offSeg); +} + +/** + * LEDATA + FIXUPP - Returns available space in current LEDATA record. + */ +static uint32_t omfWriter_LEDataAvailable(POMFWRITER pThis) +{ + if (pThis->offSeg < pThis->offSegEnd) + return pThis->offSegEnd - pThis->offSeg; + return 0; +} + +/** + * LEDATA + FIXUPP - Splits LEDATA record if less than @a cb bytes available. + */ +static bool omfWriter_LEDataEnsureSpace(POMFWRITER pThis, uint32_t cb) +{ + if ( omfWriter_LEDataAvailable(pThis) >= cb + || omfWriter_LEDataSplit(pThis)) + return true; + return false; +} + +/** + * LEDATA + FIXUPP - Adds data to the LEDATA record, splitting it if needed. + */ +static bool omfWriter_LEDataAddBytes(POMFWRITER pThis, void const *pvData, size_t cbData) +{ + while (cbData > 0) + { + uint32_t cbAvail = omfWriter_LEDataAvailable(pThis); + if (cbAvail >= cbData) + { + if (omfWriter_RecAddBytes(pThis, pvData, cbData)) + { + pThis->offSeg += (uint32_t)cbData; + break; + } + return false; + } + if (!omfWriter_RecAddBytes(pThis, pvData, cbAvail)) + return false; + pThis->offSeg += cbAvail; + pvData = (uint8_t const *)pvData + cbAvail; + cbData -= cbAvail; + if (!omfWriter_LEDataSplit(pThis)) + return false; + } + return true; +} + +/** + * LEDATA + FIXUPP - Adds a U32 to the LEDATA record, splitting if needed. + */ +static bool omfWriter_LEDataAddU32(POMFWRITER pThis, uint32_t u32) +{ + if ( omfWriter_LEDataEnsureSpace(pThis, 4) + && omfWriter_RecAddU32(pThis, u32)) + { + pThis->offSeg += 4; + return true; + } + return false; +} + +/** + * LEDATA + FIXUPP - Adds a U16 to the LEDATA record, splitting if needed. + */ +static bool omfWriter_LEDataAddU16(POMFWRITER pThis, uint16_t u16) +{ + if ( omfWriter_LEDataEnsureSpace(pThis, 2) + && omfWriter_RecAddU16(pThis, u16)) + { + pThis->offSeg += 2; + return true; + } + return false; +} + +#if 0 /* unused */ +/** + * LEDATA + FIXUPP - Adds a byte to the LEDATA record, splitting if needed. + */ +static bool omfWriter_LEDataAddU8(POMFWRITER pThis, uint8_t b) +{ + if ( omfWriter_LEDataEnsureSpace(pThis, 1) + && omfWriter_RecAddU8(pThis, b)) + { + pThis->offSeg += 1; + return true; + } + return false; +} +#endif + +/** + * MODEND - End of module, simple variant. + */ +static bool omfWriter_EndModule(POMFWRITER pThis) +{ + return omfWriter_RecBegin(pThis, OMF_MODEND32) + && omfWriter_RecAddU8(pThis, 0) + && omfWriter_RecEndWithCrc(pThis); +} + + + + +/********************************************************************************************************************************* +* ELF64/AMD64 -> ELF64/i386 Converter * +*********************************************************************************************************************************/ + +/** AMD64 relocation type names for ELF. */ +static const char * const g_apszElfAmd64RelTypes[] = +{ + "R_X86_64_NONE", + "R_X86_64_64", + "R_X86_64_PC32", + "R_X86_64_GOT32", + "R_X86_64_PLT32", + "R_X86_64_COPY", + "R_X86_64_GLOB_DAT", + "R_X86_64_JMP_SLOT", + "R_X86_64_RELATIVE", + "R_X86_64_GOTPCREL", + "R_X86_64_32", + "R_X86_64_32S", + "R_X86_64_16", + "R_X86_64_PC16", + "R_X86_64_8", + "R_X86_64_PC8", + "R_X86_64_DTPMOD64", + "R_X86_64_DTPOFF64", + "R_X86_64_TPOFF64", + "R_X86_64_TLSGD", + "R_X86_64_TLSLD", + "R_X86_64_DTPOFF32", + "R_X86_64_GOTTPOFF", + "R_X86_64_TPOFF32", +}; + +/** AMD64 relocation type sizes for ELF. */ +static uint8_t const g_acbElfAmd64RelTypes[] = +{ + 0, /* R_X86_64_NONE */ + 8, /* R_X86_64_64 */ + 4, /* R_X86_64_PC32 */ + 4, /* R_X86_64_GOT32 */ + 4, /* R_X86_64_PLT32 */ + 0, /* R_X86_64_COPY */ + 0, /* R_X86_64_GLOB_DAT */ + 0, /* R_X86_64_JMP_SLOT */ + 0, /* R_X86_64_RELATIVE */ + 0, /* R_X86_64_GOTPCREL */ + 4, /* R_X86_64_32 */ + 4, /* R_X86_64_32S */ + 2, /* R_X86_64_16 */ + 2, /* R_X86_64_PC16 */ + 1, /* R_X86_64_8 */ + 1, /* R_X86_64_PC8 */ + 0, /* R_X86_64_DTPMOD64 */ + 0, /* R_X86_64_DTPOFF64 */ + 0, /* R_X86_64_TPOFF64 */ + 0, /* R_X86_64_TLSGD */ + 0, /* R_X86_64_TLSLD */ + 0, /* R_X86_64_DTPOFF32 */ + 0, /* R_X86_64_GOTTPOFF */ + 0, /* R_X86_64_TPOFF32 */ +}; + +/** Macro for getting the size of a AMD64 ELF relocation. */ +#define ELF_AMD64_RELOC_SIZE(a_Type) ( (a_Type) < RT_ELEMENTS(g_acbElfAmd64RelTypes) ? g_acbElfAmd64RelTypes[(a_Type)] : 1) + + +typedef struct ELFDETAILS +{ + /** The ELF header. */ + Elf64_Ehdr const *pEhdr; + /** The section header table. */ + Elf64_Shdr const *paShdrs; + /** The string table for the section names. */ + const char *pchShStrTab; + + /** The symbol table section number. UINT16_MAX if not found. */ + uint16_t iSymSh; + /** The string table section number. UINT16_MAX if not found. */ + uint16_t iStrSh; + + /** The symbol table. */ + Elf64_Sym const *paSymbols; + /** The number of symbols in the symbol table. */ + uint32_t cSymbols; + + /** Pointer to the (symbol) string table if found. */ + const char *pchStrTab; + /** The string table size. */ + size_t cbStrTab; + +} ELFDETAILS; +typedef ELFDETAILS *PELFDETAILS; +typedef ELFDETAILS const *PCELFDETAILS; + + +static bool validateElf(const char *pszFile, uint8_t const *pbFile, size_t cbFile, PELFDETAILS pElfStuff) +{ + /* + * Initialize the ELF details structure. + */ + memset(pElfStuff, 0, sizeof(*pElfStuff)); + pElfStuff->iSymSh = UINT16_MAX; + pElfStuff->iStrSh = UINT16_MAX; + + /* + * Validate the header and our other expectations. + */ + Elf64_Ehdr const *pEhdr = (Elf64_Ehdr const *)pbFile; + pElfStuff->pEhdr = pEhdr; + if ( pEhdr->e_ident[EI_CLASS] != ELFCLASS64 + || pEhdr->e_ident[EI_DATA] != ELFDATA2LSB + || pEhdr->e_ehsize != sizeof(Elf64_Ehdr) + || pEhdr->e_shentsize != sizeof(Elf64_Shdr) + || pEhdr->e_version != EV_CURRENT ) + return error(pszFile, "Unsupported ELF config\n"); + if (pEhdr->e_type != ET_REL) + return error(pszFile, "Expected relocatable ELF file (e_type=%d)\n", pEhdr->e_type); + if (pEhdr->e_machine != EM_X86_64) + return error(pszFile, "Expected relocatable ELF file (e_type=%d)\n", pEhdr->e_machine); + if (pEhdr->e_phnum != 0) + return error(pszFile, "Expected e_phnum to be zero not %u\n", pEhdr->e_phnum); + if (pEhdr->e_shnum < 2) + return error(pszFile, "Expected e_shnum to be two or higher\n"); + if (pEhdr->e_shstrndx >= pEhdr->e_shnum || pEhdr->e_shstrndx == 0) + return error(pszFile, "Bad e_shstrndx=%u (e_shnum=%u)\n", pEhdr->e_shstrndx, pEhdr->e_shnum); + if ( pEhdr->e_shoff >= cbFile + || pEhdr->e_shoff + pEhdr->e_shnum * sizeof(Elf64_Shdr) > cbFile) + return error(pszFile, "Section table is outside the file (e_shoff=%#llx, e_shnum=%u, cbFile=%#llx)\n", + pEhdr->e_shstrndx, pEhdr->e_shnum, (uint64_t)cbFile); + + /* + * Locate the section name string table. + * We assume it's okay as we only reference it in verbose mode. + */ + Elf64_Shdr const *paShdrs = (Elf64_Shdr const *)&pbFile[pEhdr->e_shoff]; + pElfStuff->paShdrs = paShdrs; + + Elf64_Xword const cbShStrTab = paShdrs[pEhdr->e_shstrndx].sh_size; + if ( paShdrs[pEhdr->e_shstrndx].sh_offset > cbFile + || cbShStrTab > cbFile + || paShdrs[pEhdr->e_shstrndx].sh_offset + cbShStrTab > cbFile) + return error(pszFile, + "Section string table is outside the file (sh_offset=%#" ELF_FMT_X64 " sh_size=%#" ELF_FMT_X64 " cbFile=%#" ELF_FMT_X64 ")\n", + paShdrs[pEhdr->e_shstrndx].sh_offset, paShdrs[pEhdr->e_shstrndx].sh_size, (Elf64_Xword)cbFile); + const char *pchShStrTab = (const char *)&pbFile[paShdrs[pEhdr->e_shstrndx].sh_offset]; + pElfStuff->pchShStrTab = pchShStrTab; + + /* + * Work the section table. + */ + bool fRet = true; + for (uint32_t i = 1; i < pEhdr->e_shnum; i++) + { + if (paShdrs[i].sh_name >= cbShStrTab) + return error(pszFile, "Invalid sh_name value (%#x) for section #%u\n", paShdrs[i].sh_name, i); + const char *pszShNm = &pchShStrTab[paShdrs[i].sh_name]; + + if ( paShdrs[i].sh_offset > cbFile + || paShdrs[i].sh_size > cbFile + || paShdrs[i].sh_offset + paShdrs[i].sh_size > cbFile) + return error(pszFile, "Section #%u '%s' has data outside the file: %#" ELF_FMT_X64 " LB %#" ELF_FMT_X64 " (cbFile=%#" ELF_FMT_X64 ")\n", + i, pszShNm, paShdrs[i].sh_offset, paShdrs[i].sh_size, (Elf64_Xword)cbFile); + if (g_cVerbose) + printf("shdr[%u]: name=%#x '%s' type=%#x flags=%#" ELF_FMT_X64 " addr=%#" ELF_FMT_X64 " off=%#" ELF_FMT_X64 " size=%#" ELF_FMT_X64 "\n" + " link=%u info=%#x align=%#" ELF_FMT_X64 " entsize=%#" ELF_FMT_X64 "\n", + i, paShdrs[i].sh_name, pszShNm, paShdrs[i].sh_type, paShdrs[i].sh_flags, + paShdrs[i].sh_addr, paShdrs[i].sh_offset, paShdrs[i].sh_size, + paShdrs[i].sh_link, paShdrs[i].sh_info, paShdrs[i].sh_addralign, paShdrs[i].sh_entsize); + + if (paShdrs[i].sh_link >= pEhdr->e_shnum) + return error(pszFile, "Section #%u '%s' links to a section outside the section table: %#x, max %#x\n", + i, pszShNm, paShdrs[i].sh_link, pEhdr->e_shnum); + if (!RT_IS_POWER_OF_TWO(paShdrs[i].sh_addralign)) + return error(pszFile, "Section #%u '%s' alignment value is not a power of two: %#" ELF_FMT_X64 "\n", + i, pszShNm, paShdrs[i].sh_addralign); + if (!RT_IS_POWER_OF_TWO(paShdrs[i].sh_addralign)) + return error(pszFile, "Section #%u '%s' alignment value is not a power of two: %#" ELF_FMT_X64 "\n", + i, pszShNm, paShdrs[i].sh_addralign); + if (paShdrs[i].sh_addr != 0) + return error(pszFile, "Section #%u '%s' has non-zero address: %#" ELF_FMT_X64 "\n", i, pszShNm, paShdrs[i].sh_addr); + + if (paShdrs[i].sh_type == SHT_RELA) + { + if (paShdrs[i].sh_entsize != sizeof(Elf64_Rela)) + return error(pszFile, "Expected sh_entsize to be %u not %u for section #%u (%s)\n", (unsigned)sizeof(Elf64_Rela), + paShdrs[i].sh_entsize, i, pszShNm); + uint32_t const cRelocs = paShdrs[i].sh_size / sizeof(Elf64_Rela); + if (cRelocs * sizeof(Elf64_Rela) != paShdrs[i].sh_size) + return error(pszFile, "Uneven relocation entry count in #%u (%s): sh_size=%#" ELF_FMT_X64 "\n", + i, pszShNm, paShdrs[i].sh_size); + if ( paShdrs[i].sh_offset > cbFile + || paShdrs[i].sh_size >= cbFile + || paShdrs[i].sh_offset + paShdrs[i].sh_size > cbFile) + return error(pszFile, "The content of section #%u '%s' is outside the file (%#" ELF_FMT_X64 " LB %#" ELF_FMT_X64 ", cbFile=%#lx)\n", + i, pszShNm, paShdrs[i].sh_offset, paShdrs[i].sh_size, (unsigned long)cbFile); + if (paShdrs[i].sh_info != i - 1) + return error(pszFile, "Expected relocation section #%u (%s) to link to previous section: sh_info=%#u\n", + i, pszShNm, (unsigned)paShdrs[i].sh_link); + if (paShdrs[paShdrs[i].sh_link].sh_type != SHT_SYMTAB) + return error(pszFile, "Expected relocation section #%u (%s) to link to symbol table: sh_link=%#u -> sh_type=%#x\n", + i, pszShNm, (unsigned)paShdrs[i].sh_link, (unsigned)paShdrs[paShdrs[i].sh_link].sh_type); + uint32_t cSymbols = paShdrs[paShdrs[i].sh_link].sh_size / paShdrs[paShdrs[i].sh_link].sh_entsize; + + Elf64_Rela const *paRelocs = (Elf64_Rela *)&pbFile[paShdrs[i].sh_offset]; + for (uint32_t j = 0; j < cRelocs; j++) + { + uint8_t const bType = ELF64_R_TYPE(paRelocs[j].r_info); + if (RT_UNLIKELY(bType >= R_X86_64_COUNT)) + fRet = error(pszFile, + "%#018" ELF_FMT_X64 " %#018" ELF_FMT_X64 ": unknown fix up %#x (%+" ELF_FMT_D64 ")\n", + paRelocs[j].r_offset, paRelocs[j].r_info, bType, paRelocs[j].r_addend); + if (RT_UNLIKELY( paRelocs[j].r_offset > paShdrs[i - 1].sh_size + || paRelocs[j].r_offset + ELF_AMD64_RELOC_SIZE(ELF64_R_TYPE(paRelocs[j].r_info)) + > paShdrs[i - 1].sh_size)) + fRet = error(pszFile, + "%#018" ELF_FMT_X64 " %#018" ELF_FMT_X64 ": out of bounds (sh_size %" ELF_FMT_X64 ")\n", + paRelocs[j].r_offset, paRelocs[j].r_info, paShdrs[i - 1].sh_size); + + uint32_t const iSymbol = ELF64_R_SYM(paRelocs[j].r_info); + if (RT_UNLIKELY(iSymbol >= cSymbols)) + fRet = error(pszFile, + "%#018" ELF_FMT_X64 " %#018" ELF_FMT_X64 ": symbol index (%#x) out of bounds (%#x)\n", + paRelocs[j].r_offset, paRelocs[j].r_info, iSymbol, cSymbols); + } + } + else if (paShdrs[i].sh_type == SHT_REL) + fRet = error(pszFile, "Section #%u '%s': Unexpected SHT_REL section\n", i, pszShNm); + else if (paShdrs[i].sh_type == SHT_SYMTAB) + { + if (paShdrs[i].sh_entsize != sizeof(Elf64_Sym)) + fRet = error(pszFile, "Section #%u '%s': Unsupported symbol table entry size in : #%u (expected #%u)\n", + i, pszShNm, paShdrs[i].sh_entsize, sizeof(Elf64_Sym)); + Elf64_Xword const cSymbols = paShdrs[i].sh_size / paShdrs[i].sh_entsize; + if (cSymbols * paShdrs[i].sh_entsize != paShdrs[i].sh_size) + fRet = error(pszFile, "Section #%u '%s': Size not a multiple of entry size: %#" ELF_FMT_X64 " %% %#" ELF_FMT_X64 " = %#" ELF_FMT_X64 "\n", + i, pszShNm, paShdrs[i].sh_size, paShdrs[i].sh_entsize, paShdrs[i].sh_size % paShdrs[i].sh_entsize); + if (cSymbols > UINT32_MAX) + fRet = error(pszFile, "Section #%u '%s': too many symbols: %" ELF_FMT_X64 "\n", + i, pszShNm, paShdrs[i].sh_size, cSymbols); + + if (pElfStuff->iSymSh == UINT16_MAX) + { + pElfStuff->iSymSh = (uint16_t)i; + pElfStuff->paSymbols = (Elf64_Sym const *)&pbFile[paShdrs[i].sh_offset]; + pElfStuff->cSymbols = cSymbols; + + if (paShdrs[i].sh_link != 0) + { + /* Note! The symbol string table section header may not have been validated yet! */ + Elf64_Shdr const *pStrTabShdr = &paShdrs[paShdrs[i].sh_link]; + pElfStuff->iStrSh = paShdrs[i].sh_link; + pElfStuff->pchStrTab = (const char *)&pbFile[pStrTabShdr->sh_offset]; + pElfStuff->cbStrTab = (size_t)pStrTabShdr->sh_size; + } + else + fRet = error(pszFile, "Section #%u '%s': String table link is out of bounds (%#x)\n", + i, pszShNm, paShdrs[i].sh_link); + } + else + fRet = error(pszFile, "Section #%u '%s': Found additonal symbol table, previous in #%u\n", + i, pszShNm, pElfStuff->iSymSh); + } + } + return fRet; +} + + +static bool convertElfSectionsToSegDefsAndGrpDefs(POMFWRITER pThis, PCELFDETAILS pElfStuff) +{ + /* + * Do the list of names pass. + */ + uint16_t idxGrpFlat, idxGrpData; + uint16_t idxClassCode, idxClassData, idxClassDwarf; + if ( !omfWriter_LNamesBegin(pThis, true /*fAddZeroEntry*/) + || !omfWriter_LNamesAddN(pThis, RT_STR_TUPLE("FLAT"), &idxGrpFlat) + || !omfWriter_LNamesAddN(pThis, RT_STR_TUPLE("BS3DATA64_GROUP"), &idxGrpData) + || !omfWriter_LNamesAddN(pThis, RT_STR_TUPLE("BS3CLASS64CODE"), &idxClassCode) + || !omfWriter_LNamesAddN(pThis, RT_STR_TUPLE("FAR_DATA"), &idxClassData) + || !omfWriter_LNamesAddN(pThis, RT_STR_TUPLE("DWARF"), &idxClassDwarf) + ) + return false; + + bool fHaveData = false; + Elf64_Shdr const *pShdr = &pElfStuff->paShdrs[1]; + Elf64_Half const cSections = pElfStuff->pEhdr->e_shnum; + for (Elf64_Half i = 1; i < cSections; i++, pShdr++) + { + const char *pszName = &pElfStuff->pchShStrTab[pShdr->sh_name]; + if (*pszName == '\0') + return error(pThis->pszSrc, "Section #%u has an empty name!\n", i); + + switch (pShdr->sh_type) + { + case SHT_PROGBITS: + case SHT_NOBITS: + /* We drop a few sections we don't want:. */ + if ( strcmp(pszName, ".comment") != 0 /* compiler info */ + && strcmp(pszName, ".note.GNU-stack") != 0 /* some empty section for hinting the linker/whatever */ + && strcmp(pszName, ".eh_frame") != 0 /* unwind / exception info */ + ) + { + pThis->paSegments[i].iSegDef = UINT16_MAX; + pThis->paSegments[i].iGrpDef = UINT16_MAX; + + /* Translate the name and determine group and class. + Note! We currently strip sub-sections. */ + if ( strcmp(pszName, ".text") == 0 + || strncmp(pszName, RT_STR_TUPLE(".text.")) == 0) + { + pszName = "BS3TEXT64"; + pThis->paSegments[i].iGrpNm = idxGrpFlat; + pThis->paSegments[i].iClassNm = idxClassCode; + } + else if ( strcmp(pszName, ".data") == 0 + || strncmp(pszName, RT_STR_TUPLE(".data.")) == 0) + { + pszName = "BS3DATA64"; + pThis->paSegments[i].iGrpNm = idxGrpData; + pThis->paSegments[i].iClassNm = idxClassData; + } + else if (strcmp(pszName, ".bss") == 0) + { + pszName = "BS3BSS64"; + pThis->paSegments[i].iGrpNm = idxGrpData; + pThis->paSegments[i].iClassNm = idxClassData; + } + else if ( strcmp(pszName, ".rodata") == 0 + || strncmp(pszName, RT_STR_TUPLE(".rodata.")) == 0) + { + pszName = "BS3DATA64CONST"; + pThis->paSegments[i].iGrpNm = idxGrpData; + pThis->paSegments[i].iClassNm = idxClassData; + } + else if (strncmp(pszName, RT_STR_TUPLE(".debug_")) == 0) + { + pThis->paSegments[i].iGrpNm = UINT16_MAX; + pThis->paSegments[i].iClassNm = idxClassDwarf; + } + else + { + pThis->paSegments[i].iGrpNm = idxGrpData; + pThis->paSegments[i].iClassNm = idxClassData; + error(pThis->pszSrc, "Unknown data (?) segment: '%s'\n", pszName); + } + + /* Save the name. */ + pThis->paSegments[i].pszName = strdup(pszName); + if (!pThis->paSegments[i].pszName) + return error(pThis->pszSrc, "Out of memory!\n"); + + /* Add the section name. */ + if (!omfWriter_LNamesAdd(pThis, pThis->paSegments[i].pszName, &pThis->paSegments[i].iSegNm)) + return false; + + fHaveData |= pThis->paSegments[i].iGrpNm == idxGrpData; + break; + } + RT_FALL_THRU(); + + default: + pThis->paSegments[i].iSegDef = UINT16_MAX; + pThis->paSegments[i].iGrpDef = UINT16_MAX; + pThis->paSegments[i].iSegNm = UINT16_MAX; + pThis->paSegments[i].iGrpNm = UINT16_MAX; + pThis->paSegments[i].iClassNm = UINT16_MAX; + pThis->paSegments[i].pszName = NULL; + break; + } + } + + if (!omfWriter_LNamesEnd(pThis)) + return false; + + /* + * Emit segment definitions. + */ + uint16_t iSegDef = 1; /* Start counting at 1. */ + pShdr = &pElfStuff->paShdrs[1]; + for (Elf64_Half i = 1; i < cSections; i++, pShdr++) + { + if (pThis->paSegments[i].iSegNm == UINT16_MAX) + continue; + + uint8_t bSegAttr = 0; + + /* The A field. */ + switch (pShdr->sh_addralign) + { + case 0: + case 1: + bSegAttr |= 1 << 5; + break; + case 2: + bSegAttr |= 2 << 5; + break; + case 4: + bSegAttr |= 5 << 5; + break; + case 8: + case 16: + bSegAttr |= 3 << 5; + break; + case 32: + case 64: + case 128: + case 256: + bSegAttr |= 4 << 5; + break; + default: + bSegAttr |= 6 << 5; /* page aligned, pharlabs extension. */ + break; + } + + /* The C field. */ + bSegAttr |= 2 << 2; /* public */ + + /* The B field. We don't have 4GB segments, so leave it as zero. */ + + /* The D field shall be set as we're doing USE32. */ + bSegAttr |= 1; + + + /* Done. */ + if (!omfWriter_SegDef(pThis, bSegAttr, (uint32_t)pShdr->sh_size, + pThis->paSegments[i].iSegNm, + pThis->paSegments[i].iClassNm)) + return false; + pThis->paSegments[i].iSegDef = iSegDef++; + } + + /* + * Flat group definition (#1) - special, no members. + */ + uint16_t iGrpDef = 1; + if ( !omfWriter_GrpDefBegin(pThis, idxGrpFlat) + || !omfWriter_GrpDefEnd(pThis)) + return false; + for (uint16_t i = 0; i < cSections; i++) + if (pThis->paSegments[i].iGrpNm == idxGrpFlat) + pThis->paSegments[i].iGrpDef = iGrpDef; + pThis->idxGrpFlat = iGrpDef++; + + /* + * Data group definition (#2). + */ + /** @todo do we need to consider missing segments and ordering? */ + uint16_t cGrpNms = 0; + uint16_t aiGrpNms[2] = { 0, 0 }; /* Shut up, GCC. */ + if (fHaveData) + aiGrpNms[cGrpNms++] = idxGrpData; + for (uint32_t iGrpNm = 0; iGrpNm < cGrpNms; iGrpNm++) + { + if (!omfWriter_GrpDefBegin(pThis, aiGrpNms[iGrpNm])) + return false; + for (uint16_t i = 0; i < cSections; i++) + if (pThis->paSegments[i].iGrpNm == aiGrpNms[iGrpNm]) + { + pThis->paSegments[i].iGrpDef = iGrpDef; + if (!omfWriter_GrpDefAddSegDef(pThis, pThis->paSegments[i].iSegDef)) + return false; + } + if (!omfWriter_GrpDefEnd(pThis)) + return false; + iGrpDef++; + } + + return true; +} + +static bool convertElfSymbolsToPubDefsAndExtDefs(POMFWRITER pThis, PCELFDETAILS pElfStuff) +{ + if (!pElfStuff->cSymbols) + return true; + + /* + * Process the symbols the first. + */ + uint32_t cAbsSyms = 0; + uint32_t cExtSyms = 0; + uint32_t cPubSyms = 0; + for (uint32_t iSeg = 0; iSeg < pThis->cSegments; iSeg++) + pThis->paSegments[iSeg].cPubDefs = 0; + + uint32_t const cSections = pElfStuff->pEhdr->e_shnum; + uint32_t const cSymbols = pElfStuff->cSymbols; + Elf64_Sym const * const paSymbols = pElfStuff->paSymbols; + for (uint32_t iSym = 0; iSym < cSymbols; iSym++) + { + const uint8_t bBind = ELF64_ST_BIND(paSymbols[iSym].st_info); + const uint8_t bType = ELF64_ST_TYPE(paSymbols[iSym].st_info); + const char *pszSymName = &pElfStuff->pchStrTab[paSymbols[iSym].st_name]; + if ( *pszSymName == '\0' + && bType == STT_SECTION + && paSymbols[iSym].st_shndx < cSections) + pszSymName = &pElfStuff->pchShStrTab[pElfStuff->paShdrs[paSymbols[iSym].st_shndx].sh_name]; + + pThis->paSymbols[iSym].enmType = OMFSYMTYPE_IGNORED; + pThis->paSymbols[iSym].idx = UINT16_MAX; + pThis->paSymbols[iSym].idxSegDef = UINT16_MAX; + pThis->paSymbols[iSym].idxGrpDef = UINT16_MAX; + + uint32_t const idxSection = paSymbols[iSym].st_shndx; + if (idxSection == SHN_UNDEF) + { + if (bBind == STB_GLOBAL) + { + pThis->paSymbols[iSym].enmType = OMFSYMTYPE_EXTDEF; + cExtSyms++; + if (*pszSymName == '\0') + return error(pThis->pszSrc, "External symbol #%u (%s) has an empty name.\n", iSym, pszSymName); + } + else if (bBind != STB_LOCAL || iSym != 0) /* Entry zero is usually a dummy. */ + return error(pThis->pszSrc, "Unsupported or invalid bind type %#x for undefined symbol #%u (%s)\n", + bBind, iSym, pszSymName); + } + else if (idxSection < cSections) + { + pThis->paSymbols[iSym].idxSegDef = pThis->paSegments[idxSection].iSegDef; + pThis->paSymbols[iSym].idxGrpDef = pThis->paSegments[idxSection].iGrpDef; + if (bBind == STB_GLOBAL) + { + pThis->paSymbols[iSym].enmType = OMFSYMTYPE_PUBDEF; + pThis->paSegments[idxSection].cPubDefs++; + cPubSyms++; + if (bType == STT_SECTION) + return error(pThis->pszSrc, "Don't know how to export STT_SECTION symbol #%u (%s)\n", iSym, pszSymName); + if (*pszSymName == '\0') + return error(pThis->pszSrc, "Public symbol #%u (%s) has an empty name.\n", iSym, pszSymName); + } + else if (bType == STT_SECTION) + pThis->paSymbols[iSym].enmType = OMFSYMTYPE_SEGDEF; + else + pThis->paSymbols[iSym].enmType = OMFSYMTYPE_INTERNAL; + } + else if (idxSection == SHN_ABS) + { + if (bType != STT_FILE) + { + if (bBind == STB_GLOBAL) + { + pThis->paSymbols[iSym].enmType = OMFSYMTYPE_PUBDEF; + pThis->paSymbols[iSym].idxSegDef = 0; + pThis->paSymbols[iSym].idxGrpDef = 0; + cAbsSyms++; + if (*pszSymName == '\0') + return error(pThis->pszSrc, "Public absolute symbol #%u (%s) has an empty name.\n", iSym, pszSymName); + } + else + return error(pThis->pszSrc, "Unsupported or invalid bind type %#x for absolute symbol #%u (%s)\n", + bBind, iSym, pszSymName); + } + } + else if (idxSection == SHN_COMMON) + return error(pThis->pszSrc, "Symbol #%u (%s) is in the unsupported 'common' section.\n", iSym, pszSymName); + else + return error(pThis->pszSrc, "Unsupported or invalid section number %#x for symbol #%u (%s)\n", + idxSection, iSym, pszSymName); + } + + /* + * Emit the PUBDEFs the first time around (see order of records in TIS spec). + */ + uint16_t idxPubDef = 1; + if (cPubSyms) + { + for (uint32_t iSeg = 0; iSeg < pThis->cSegments; iSeg++) + if (pThis->paSegments[iSeg].cPubDefs > 0) + { + uint16_t const idxSegDef = pThis->paSegments[iSeg].iSegDef; + if (!omfWriter_PubDefBegin(pThis, pThis->paSegments[iSeg].iGrpDef, idxSegDef)) + return false; + for (uint16_t iSym = 0; iSym < cSymbols; iSym++) + if ( pThis->paSymbols[iSym].idxSegDef == idxSegDef + && pThis->paSymbols[iSym].enmType == OMFSYMTYPE_PUBDEF) + { + /* Underscore prefix all names not already underscored/mangled. */ + const char *pszName = &pElfStuff->pchStrTab[paSymbols[iSym].st_name]; + if (!omfWriter_PubDefAdd(pThis, paSymbols[iSym].st_value, pszName, pszName[0] != '_')) + return false; + pThis->paSymbols[iSym].idx = idxPubDef++; + } + if (!omfWriter_PubDefEnd(pThis)) + return false; + } + } + + if (cAbsSyms > 0) + { + if (!omfWriter_PubDefBegin(pThis, 0, 0)) + return false; + for (uint16_t iSym = 0; iSym < cSymbols; iSym++) + if ( pThis->paSymbols[iSym].idxSegDef == 0 + && pThis->paSymbols[iSym].enmType == OMFSYMTYPE_PUBDEF) + { + /* Underscore prefix all names not already underscored/mangled. */ + const char *pszName = &pElfStuff->pchStrTab[paSymbols[iSym].st_name]; + if (!omfWriter_PubDefAdd(pThis, paSymbols[iSym].st_value, pszName, pszName[0] != '_')) + return false; + pThis->paSymbols[iSym].idx = idxPubDef++; + } + if (!omfWriter_PubDefEnd(pThis)) + return false; + } + + /* + * Go over the symbol table and emit external definition records. + */ + if (!omfWriter_ExtDefBegin(pThis)) + return false; + uint16_t idxExtDef = 1; + for (uint16_t iSym = 0; iSym < cSymbols; iSym++) + if (pThis->paSymbols[iSym].enmType == OMFSYMTYPE_EXTDEF) + { + /* Underscore prefix all names not already underscored/mangled. */ + const char *pszName = &pElfStuff->pchStrTab[paSymbols[iSym].st_name]; + if (!omfWriter_ExtDefAdd(pThis, pszName, *pszName != '_')) + return false; + pThis->paSymbols[iSym].idx = idxExtDef++; + } + + if (!omfWriter_ExtDefEnd(pThis)) + return false; + + return true; +} + +/** + * @callback_method_impl{FNRTSORTCMP, For Elf64_Rela tables.} + */ +static DECLCALLBACK(int) convertElfCompareRelA(void const *pvElement1, void const *pvElement2, void *pvUser) +{ + Elf64_Rela const *pReloc1 = (Elf64_Rela const *)pvElement1; + Elf64_Rela const *pReloc2 = (Elf64_Rela const *)pvElement2; + if (pReloc1->r_offset < pReloc2->r_offset) + return -1; + if (pReloc1->r_offset > pReloc2->r_offset) + return 1; + RT_NOREF_PV(pvUser); + return 0; +} + +static bool convertElfSectionsToLeDataAndFixupps(POMFWRITER pThis, PCELFDETAILS pElfStuff, uint8_t const *pbFile, size_t cbFile) +{ + Elf64_Sym const *paSymbols = pElfStuff->paSymbols; + Elf64_Shdr const *paShdrs = pElfStuff->paShdrs; + bool fRet = true; + RT_NOREF_PV(cbFile); + + for (uint32_t i = 1; i < pThis->cSegments; i++) + { + if (pThis->paSegments[i].iSegDef == UINT16_MAX) + continue; + + const char *pszSegNm = &pElfStuff->pchShStrTab[paShdrs[i].sh_name]; + bool const fRelocs = i + 1 < pThis->cSegments && paShdrs[i + 1].sh_type == SHT_RELA; + uint32_t cRelocs = fRelocs ? paShdrs[i + 1].sh_size / sizeof(Elf64_Rela) : 0; + Elf64_Rela const *paRelocs = fRelocs ? (Elf64_Rela *)&pbFile[paShdrs[i + 1].sh_offset] : NULL; + Elf64_Xword cbVirtData = paShdrs[i].sh_size; + Elf64_Xword cbData = paShdrs[i].sh_type == SHT_NOBITS ? 0 : cbVirtData; + uint8_t const *pbData = &pbFile[paShdrs[i].sh_offset]; + uint32_t off = 0; + + /* We sort fixups by r_offset in order to more easily split them into chunks. */ + RTSortShell((void *)paRelocs, cRelocs, sizeof(paRelocs[0]), convertElfCompareRelA, NULL); + + /* The OMF record size requires us to split larger sections up. To make + life simple, we fill zeros for unitialized (BSS) stuff. */ + const uint32_t cbMaxData = RT_MIN(OMF_MAX_RECORD_PAYLOAD - 1 - (pThis->paSegments[i].iSegDef >= 128) - 4 - 1, _1K); + while (cbVirtData > 0) + { + /* Figure out how many bytes to put out in this chunk. Must make sure + fixups doesn't cross chunk boundraries. ASSUMES sorted relocs. */ + uint32_t cChunkRelocs = cRelocs; + uint32_t cbChunk = cbVirtData; + uint32_t offEnd = off + cbChunk; + if (cbChunk > cbMaxData) + { + cbChunk = cbMaxData; + offEnd = off + cbChunk; + cChunkRelocs = 0; + + /* Quickly determin the reloc range. */ + while ( cChunkRelocs < cRelocs + && paRelocs[cChunkRelocs].r_offset < offEnd) + cChunkRelocs++; + + /* Ensure final reloc doesn't go beyond chunk. */ + while ( cChunkRelocs > 0 + && paRelocs[cChunkRelocs - 1].r_offset + + ELF_AMD64_RELOC_SIZE(ELF64_R_TYPE(paRelocs[cChunkRelocs - 1].r_info)) + > offEnd) + { + uint32_t cbDrop = offEnd - paRelocs[cChunkRelocs - 1].r_offset; + cbChunk -= cbDrop; + offEnd -= cbDrop; + cChunkRelocs--; + } + + if (!cbVirtData) + return error(pThis->pszSrc, "Wtf? cbVirtData is zero!\n"); + } + if (g_cVerbose >= 2) + printf("debug: LEDATA off=%#x cb=%#x cRelocs=%#x sect=#%u segdef=%#x grpdef=%#x '%s'\n", + off, cbChunk, cRelocs, i, pThis->paSegments[i].iSegDef, pThis->paSegments[i].iGrpDef, pszSegNm); + + /* + * We stash the bytes into the OMF writer record buffer, receiving a + * pointer to the start of it so we can make adjustments if necessary. + */ + uint8_t *pbCopy; + if (!omfWriter_LEDataBeginEx(pThis, pThis->paSegments[i].iSegDef, off, cbChunk, cbData, pbData, &pbCopy)) + return false; + + /* + * Convert fiuxps. + */ + for (uint32_t iReloc = 0; iReloc < cChunkRelocs; iReloc++) + { + /* Get the OMF and ELF data for the symbol the reloc references. */ + uint32_t const uType = ELF64_R_TYPE(paRelocs[iReloc].r_info); + uint32_t const iSymbol = ELF64_R_SYM(paRelocs[iReloc].r_info); + Elf64_Sym const * const pElfSym = &paSymbols[iSymbol]; + POMFSYMBOL const pOmfSym = &pThis->paSymbols[iSymbol]; + const char * const pszSymName = &pElfStuff->pchStrTab[pElfSym->st_name]; + + /* Calc fixup location in the pending chunk and setup a flexible pointer to it. */ + uint16_t offDataRec = (uint16_t)(paRelocs[iReloc].r_offset - off); + RTPTRUNION uLoc; + uLoc.pu8 = &pbCopy[offDataRec]; + + /* OMF fixup data initialized with typical defaults. */ + bool fSelfRel = true; + uint8_t bLocation = OMF_FIX_LOC_32BIT_OFFSET; + uint8_t bFrame = OMF_FIX_F_GRPDEF; + uint16_t idxFrame = pThis->idxGrpFlat; + uint8_t bTarget; + uint16_t idxTarget; + bool fTargetDisp; + uint32_t offTargetDisp; + switch (pOmfSym->enmType) + { + case OMFSYMTYPE_INTERNAL: + case OMFSYMTYPE_PUBDEF: + bTarget = OMF_FIX_T_SEGDEF; + idxTarget = pOmfSym->idxSegDef; + fTargetDisp = true; + offTargetDisp = pElfSym->st_value; + break; + + case OMFSYMTYPE_SEGDEF: + bTarget = OMF_FIX_T_SEGDEF_NO_DISP; + idxTarget = pOmfSym->idxSegDef; + fTargetDisp = false; + offTargetDisp = 0; + break; + + case OMFSYMTYPE_EXTDEF: + bTarget = OMF_FIX_T_EXTDEF_NO_DISP; + idxTarget = pOmfSym->idx; + fTargetDisp = false; + offTargetDisp = 0; + break; + + default: + return error(pThis->pszSrc, "Relocation in segment #%u '%s' references ignored or invalid symbol (%s)\n", + i, pszSegNm, pszSymName); + } + + /* Do COFF relocation type conversion. */ + switch (uType) + { + case R_X86_64_64: + { + int64_t iAddend = paRelocs[iReloc].r_addend; + if (iAddend > _1G || iAddend < -_1G) + fRet = error(pThis->pszSrc, "R_X86_64_64 with large addend (%" ELF_FMT_D64 ") at %#x in segment #%u '%s'\n", + iAddend, paRelocs[iReloc].r_offset, i, pszSegNm); + *uLoc.pu64 = iAddend; + fSelfRel = false; + break; + } + + case R_X86_64_32: + case R_X86_64_32S: /* signed, unsigned, whatever. */ + fSelfRel = false; + RT_FALL_THRU(); + case R_X86_64_PC32: + case R_X86_64_PLT32: /* binutils commit 451875b4f976a527395e9303224c7881b65e12ed feature/regression. */ + { + /* defaults are ok, just handle the addend. */ + int32_t iAddend = paRelocs[iReloc].r_addend; + if (iAddend != paRelocs[iReloc].r_addend) + fRet = error(pThis->pszSrc, "R_X86_64_PC32 with large addend (%d) at %#x in segment #%u '%s'\n", + iAddend, paRelocs[iReloc].r_offset, i, pszSegNm); + if (fSelfRel) + *uLoc.pu32 = iAddend + 4; + else + *uLoc.pu32 = iAddend; + break; + } + + case R_X86_64_NONE: + continue; /* Ignore this one */ + + case R_X86_64_GOT32: + case R_X86_64_COPY: + case R_X86_64_GLOB_DAT: + case R_X86_64_JMP_SLOT: + case R_X86_64_RELATIVE: + case R_X86_64_GOTPCREL: + case R_X86_64_16: + case R_X86_64_PC16: + case R_X86_64_8: + case R_X86_64_PC8: + case R_X86_64_DTPMOD64: + case R_X86_64_DTPOFF64: + case R_X86_64_TPOFF64: + case R_X86_64_TLSGD: + case R_X86_64_TLSLD: + case R_X86_64_DTPOFF32: + case R_X86_64_GOTTPOFF: + case R_X86_64_TPOFF32: + default: + return error(pThis->pszSrc, "Unsupported fixup type %#x (%s) at rva=%#x in section #%u '%s' against '%s'\n", + uType, g_apszElfAmd64RelTypes[uType], paRelocs[iReloc].r_offset, i, pszSegNm, pszSymName); + } + + /* Add the fixup. */ + if (idxFrame == UINT16_MAX) + error(pThis->pszSrc, "idxFrame=UINT16_MAX for %s type=%s\n", pszSymName, g_apszElfAmd64RelTypes[uType]); + fRet = omfWriter_LEDataAddFixup(pThis, offDataRec, fSelfRel, bLocation, bFrame, idxFrame, + bTarget, idxTarget, fTargetDisp, offTargetDisp) && fRet; + } + + /* + * Write the LEDATA and associated FIXUPPs. + */ + if (!omfWriter_LEDataEnd(pThis)) + return false; + + /* + * Advance. + */ + paRelocs += cChunkRelocs; + cRelocs -= cChunkRelocs; + if (cbData > cbChunk) + { + cbData -= cbChunk; + pbData += cbChunk; + } + else + cbData = 0; + off += cbChunk; + cbVirtData -= cbChunk; + } + } + + return fRet; +} + + +static bool convertElfToOmf(const char *pszFile, uint8_t const *pbFile, size_t cbFile, FILE *pDst) +{ + /* + * Validate the source file a little. + */ + ELFDETAILS ElfStuff; + if (!validateElf(pszFile, pbFile, cbFile, &ElfStuff)) + return false; + + /* + * Instantiate the OMF writer. + */ + POMFWRITER pThis = omfWriter_Create(pszFile, ElfStuff.pEhdr->e_shnum, ElfStuff.cSymbols, pDst); + if (!pThis) + return false; + + /* + * Write the OMF object file. + */ + if (omfWriter_BeginModule(pThis, pszFile)) + { + if ( convertElfSectionsToSegDefsAndGrpDefs(pThis, &ElfStuff) + && convertElfSymbolsToPubDefsAndExtDefs(pThis, &ElfStuff) + && omfWriter_LinkPassSeparator(pThis) + && convertElfSectionsToLeDataAndFixupps(pThis, &ElfStuff, pbFile, cbFile) + && omfWriter_EndModule(pThis) ) + { + + omfWriter_Destroy(pThis); + return true; + } + } + + omfWriter_Destroy(pThis); + return false; +} + + + +/********************************************************************************************************************************* +* COFF -> OMF Converter * +*********************************************************************************************************************************/ + +/** AMD64 relocation type names for (Microsoft) COFF. */ +static const char * const g_apszCoffAmd64RelTypes[] = +{ + "ABSOLUTE", + "ADDR64", + "ADDR32", + "ADDR32NB", + "REL32", + "REL32_1", + "REL32_2", + "REL32_3", + "REL32_4", + "REL32_5", + "SECTION", + "SECREL", + "SECREL7", + "TOKEN", + "SREL32", + "PAIR", + "SSPAN32" +}; + +/** AMD64 relocation type sizes for (Microsoft) COFF. */ +static uint8_t const g_acbCoffAmd64RelTypes[] = +{ + 8, /* ABSOLUTE */ + 8, /* ADDR64 */ + 4, /* ADDR32 */ + 4, /* ADDR32NB */ + 4, /* REL32 */ + 4, /* REL32_1 */ + 4, /* REL32_2 */ + 4, /* REL32_3 */ + 4, /* REL32_4 */ + 4, /* REL32_5 */ + 2, /* SECTION */ + 4, /* SECREL */ + 1, /* SECREL7 */ + 0, /* TOKEN */ + 4, /* SREL32 */ + 0, /* PAIR */ + 4, /* SSPAN32 */ +}; + +/** Macro for getting the size of a AMD64 COFF relocation. */ +#define COFF_AMD64_RELOC_SIZE(a_Type) ( (a_Type) < RT_ELEMENTS(g_acbCoffAmd64RelTypes) ? g_acbCoffAmd64RelTypes[(a_Type)] : 1) + + +static const char *coffGetSymbolName(PCIMAGE_SYMBOL pSym, const char *pchStrTab, uint32_t cbStrTab, char pszShortName[16]) +{ + if (pSym->N.Name.Short != 0) + { + memcpy(pszShortName, pSym->N.ShortName, 8); + pszShortName[8] = '\0'; + return pszShortName; + } + if (pSym->N.Name.Long < cbStrTab) + { + uint32_t const cbLeft = cbStrTab - pSym->N.Name.Long; + const char *pszRet = pchStrTab + pSym->N.Name.Long; + if (memchr(pszRet, '\0', cbLeft) != NULL) + return pszRet; + } + error("<null>", "Invalid string table index %#x!\n", pSym->N.Name.Long); + return "Invalid Symbol Table Entry"; +} + +static bool validateCoff(const char *pszFile, uint8_t const *pbFile, size_t cbFile) +{ + /* + * Validate the header and our other expectations. + */ + PIMAGE_FILE_HEADER pHdr = (PIMAGE_FILE_HEADER)pbFile; + if (pHdr->Machine != IMAGE_FILE_MACHINE_AMD64) + return error(pszFile, "Expected IMAGE_FILE_MACHINE_AMD64 not %#x\n", pHdr->Machine); + if (pHdr->SizeOfOptionalHeader != 0) + return error(pszFile, "Expected SizeOfOptionalHeader to be zero, not %#x\n", pHdr->SizeOfOptionalHeader); + if (pHdr->NumberOfSections == 0) + return error(pszFile, "Expected NumberOfSections to be non-zero\n"); + uint32_t const cbHeaders = pHdr->NumberOfSections * sizeof(IMAGE_SECTION_HEADER) + sizeof(*pHdr); + if (cbHeaders > cbFile) + return error(pszFile, "Section table goes beyond the end of the of the file (cSections=%#x)\n", pHdr->NumberOfSections); + if (pHdr->NumberOfSymbols) + { + if ( pHdr->PointerToSymbolTable >= cbFile + || pHdr->NumberOfSymbols * (uint64_t)IMAGE_SIZE_OF_SYMBOL > cbFile) + return error(pszFile, "Symbol table goes beyond the end of the of the file (cSyms=%#x, offFile=%#x)\n", + pHdr->NumberOfSymbols, pHdr->PointerToSymbolTable); + } + + return true; +} + + +static bool convertCoffSectionsToSegDefsAndGrpDefs(POMFWRITER pThis, PCIMAGE_SECTION_HEADER paShdrs, uint16_t cSections) +{ + /* + * Do the list of names pass. + */ + uint16_t idxGrpFlat, idxGrpData; + uint16_t idxClassCode, idxClassData, idxClassDebugSymbols, idxClassDebugTypes; + if ( !omfWriter_LNamesBegin(pThis, true /*fAddZeroEntry*/) + || !omfWriter_LNamesAddN(pThis, RT_STR_TUPLE("FLAT"), &idxGrpFlat) + || !omfWriter_LNamesAddN(pThis, RT_STR_TUPLE("BS3DATA64_GROUP"), &idxGrpData) + || !omfWriter_LNamesAddN(pThis, RT_STR_TUPLE("BS3CLASS64CODE"), &idxClassCode) + || !omfWriter_LNamesAddN(pThis, RT_STR_TUPLE("FAR_DATA"), &idxClassData) + || !omfWriter_LNamesAddN(pThis, RT_STR_TUPLE("DEBSYM"), &idxClassDebugSymbols) + || !omfWriter_LNamesAddN(pThis, RT_STR_TUPLE("DEBTYP"), &idxClassDebugTypes) + ) + return false; + + bool fHaveData = false; + for (uint16_t i = 0; i < cSections; i++) + { + /* Copy the name and terminate it. */ + char szName[32]; + memcpy(szName, paShdrs[i].Name, sizeof(paShdrs[i].Name)); + unsigned cchName = sizeof(paShdrs[i].Name); + while (cchName > 0 && RT_C_IS_SPACE(szName[cchName - 1])) + cchName--; + if (cchName == 0) + return error(pThis->pszSrc, "Section #%u has an empty name!\n", i); + szName[cchName] = '\0'; + + if ( (paShdrs[i].Characteristics & (IMAGE_SCN_LNK_REMOVE | IMAGE_SCN_LNK_INFO)) + || strcmp(szName, ".pdata") == 0 /* Exception stuff, I think, so discard it. */ + || strcmp(szName, ".xdata") == 0 /* Ditto. */ ) + { + pThis->paSegments[i].iSegDef = UINT16_MAX; + pThis->paSegments[i].iGrpDef = UINT16_MAX; + pThis->paSegments[i].iSegNm = UINT16_MAX; + pThis->paSegments[i].iGrpNm = UINT16_MAX; + pThis->paSegments[i].iClassNm = UINT16_MAX; + pThis->paSegments[i].pszName = NULL; + } + else + { + /* Translate the name, group and class. */ + if (strcmp(szName, ".text") == 0) + { + strcpy(szName, "BS3TEXT64"); + pThis->paSegments[i].iGrpNm = idxGrpFlat; + pThis->paSegments[i].iClassNm = idxClassCode; + } + else if (strcmp(szName, ".data") == 0) + { + strcpy(szName, "BS3DATA64"); + pThis->paSegments[i].iGrpNm = idxGrpData; + pThis->paSegments[i].iClassNm = idxClassData; + } + else if (strcmp(szName, ".bss") == 0) + { + strcpy(szName, "BS3BSS64"); + pThis->paSegments[i].iGrpNm = idxGrpData; + pThis->paSegments[i].iClassNm = idxClassData; + } + else if (strcmp(szName, ".rdata") == 0) + { + strcpy(szName, "BS3DATA64CONST"); + pThis->paSegments[i].iGrpNm = idxGrpData; + pThis->paSegments[i].iClassNm = idxClassData; + } + else if (strcmp(szName, ".debug$S") == 0) + { + strcpy(szName, "$$SYMBOLS"); + pThis->paSegments[i].iGrpNm = UINT16_MAX; + pThis->paSegments[i].iClassNm = idxClassDebugSymbols; + } + else if (strcmp(szName, ".debug$T") == 0) + { + strcpy(szName, "$$TYPES"); + pThis->paSegments[i].iGrpNm = UINT16_MAX; + pThis->paSegments[i].iClassNm = idxClassDebugTypes; + } + else if (paShdrs[i].Characteristics & (IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_CNT_CODE)) + { + pThis->paSegments[i].iGrpNm = idxGrpFlat; + pThis->paSegments[i].iClassNm = idxClassCode; + error(pThis->pszSrc, "Unknown code segment: '%s'\n", szName); + } + else + { + pThis->paSegments[i].iGrpNm = idxGrpData; + pThis->paSegments[i].iClassNm = idxClassData; + error(pThis->pszSrc, "Unknown data (?) segment: '%s'\n", szName); + } + + /* Save the name. */ + pThis->paSegments[i].pszName = strdup(szName); + if (!pThis->paSegments[i].pszName) + return error(pThis->pszSrc, "Out of memory!\n"); + + /* Add the section name. */ + if (!omfWriter_LNamesAdd(pThis, pThis->paSegments[i].pszName, &pThis->paSegments[i].iSegNm)) + return false; + + fHaveData |= pThis->paSegments[i].iGrpNm == idxGrpData; + } + } + + if (!omfWriter_LNamesEnd(pThis)) + return false; + + /* + * Emit segment definitions. + */ + uint16_t iSegDef = 1; /* Start counting at 1. */ + for (uint16_t i = 0; i < cSections; i++) + { + if (pThis->paSegments[i].iSegDef == UINT16_MAX) + continue; + + uint8_t bSegAttr = 0; + + /* The A field. */ + switch (paShdrs[i].Characteristics & IMAGE_SCN_ALIGN_MASK) + { + default: + case IMAGE_SCN_ALIGN_1BYTES: + bSegAttr |= 1 << 5; + break; + case IMAGE_SCN_ALIGN_2BYTES: + bSegAttr |= 2 << 5; + break; + case IMAGE_SCN_ALIGN_4BYTES: + bSegAttr |= 5 << 5; + break; + case IMAGE_SCN_ALIGN_8BYTES: + case IMAGE_SCN_ALIGN_16BYTES: + bSegAttr |= 3 << 5; + break; + case IMAGE_SCN_ALIGN_32BYTES: + case IMAGE_SCN_ALIGN_64BYTES: + case IMAGE_SCN_ALIGN_128BYTES: + case IMAGE_SCN_ALIGN_256BYTES: + bSegAttr |= 4 << 5; + break; + case IMAGE_SCN_ALIGN_512BYTES: + case IMAGE_SCN_ALIGN_1024BYTES: + case IMAGE_SCN_ALIGN_2048BYTES: + case IMAGE_SCN_ALIGN_4096BYTES: + case IMAGE_SCN_ALIGN_8192BYTES: + bSegAttr |= 6 << 5; /* page aligned, pharlabs extension. */ + break; + } + + /* The C field. */ + bSegAttr |= 2 << 2; /* public */ + + /* The B field. We don't have 4GB segments, so leave it as zero. */ + + /* The D field shall be set as we're doing USE32. */ + bSegAttr |= 1; + + + /* Done. */ + if (!omfWriter_SegDef(pThis, bSegAttr, paShdrs[i].SizeOfRawData, + pThis->paSegments[i].iSegNm, + pThis->paSegments[i].iClassNm)) + return false; + pThis->paSegments[i].iSegDef = iSegDef++; + } + + /* + * Flat group definition (#1) - special, no members. + */ + uint16_t iGrpDef = 1; + if ( !omfWriter_GrpDefBegin(pThis, idxGrpFlat) + || !omfWriter_GrpDefEnd(pThis)) + return false; + for (uint16_t i = 0; i < cSections; i++) + if (pThis->paSegments[i].iGrpNm == idxGrpFlat) + pThis->paSegments[i].iGrpDef = iGrpDef; + pThis->idxGrpFlat = iGrpDef++; + + /* + * Data group definition (#2). + */ + /** @todo do we need to consider missing segments and ordering? */ + uint16_t cGrpNms = 0; + uint16_t aiGrpNms[2] = { 0, 0 }; /* Shut up, GCC. */ + if (fHaveData) + aiGrpNms[cGrpNms++] = idxGrpData; + for (uint32_t iGrpNm = 0; iGrpNm < cGrpNms; iGrpNm++) + { + if (!omfWriter_GrpDefBegin(pThis, aiGrpNms[iGrpNm])) + return false; + for (uint16_t i = 0; i < cSections; i++) + if (pThis->paSegments[i].iGrpNm == aiGrpNms[iGrpNm]) + { + pThis->paSegments[i].iGrpDef = iGrpDef; + if (!omfWriter_GrpDefAddSegDef(pThis, pThis->paSegments[i].iSegDef)) + return false; + } + if (!omfWriter_GrpDefEnd(pThis)) + return false; + iGrpDef++; + } + + return true; +} + +/** + * This is for matching STATIC symbols with value 0 against the section name, + * to see if it's a section reference or symbol at offset 0 reference. + * + * @returns true / false. + * @param pszSymbol The symbol name. + * @param pachSectName8 The section name (8-bytes). + */ +static bool isCoffSymbolMatchingSectionName(const char *pszSymbol, uint8_t const pachSectName8[8]) +{ + uint32_t off = 0; + char ch; + while (off < 8 && (ch = pszSymbol[off]) != '\0') + { + if (ch != pachSectName8[off]) + return false; + off++; + } + while (off < 8) + { + if (!RT_C_IS_SPACE((ch = pachSectName8[off]))) + return ch == '\0'; + off++; + } + return true; +} + +static bool convertCoffSymbolsToPubDefsAndExtDefs(POMFWRITER pThis, PCIMAGE_SYMBOL paSymbols, uint16_t cSymbols, + const char *pchStrTab, PCIMAGE_SECTION_HEADER paShdrs) +{ + + if (!cSymbols) + return true; + uint32_t const cbStrTab = *(uint32_t const *)pchStrTab; + char szShort[16]; + + /* + * Process the symbols the first. + */ + uint32_t iSymImageBase = UINT32_MAX; + uint32_t cAbsSyms = 0; + uint32_t cExtSyms = 0; + uint32_t cPubSyms = 0; + for (uint32_t iSeg = 0; iSeg < pThis->cSegments; iSeg++) + pThis->paSegments[iSeg].cPubDefs = 0; + + for (uint16_t iSym = 0; iSym < cSymbols; iSym++) + { + const char *pszSymName = coffGetSymbolName(&paSymbols[iSym], pchStrTab, cbStrTab, szShort); + + pThis->paSymbols[iSym].enmType = OMFSYMTYPE_IGNORED; + pThis->paSymbols[iSym].idx = UINT16_MAX; + pThis->paSymbols[iSym].idxSegDef = UINT16_MAX; + pThis->paSymbols[iSym].idxGrpDef = UINT16_MAX; + + int16_t const idxSection = paSymbols[iSym].SectionNumber; + if ( (idxSection >= 1 && idxSection <= (int32_t)pThis->cSegments) + || idxSection == IMAGE_SYM_ABSOLUTE) + { + switch (paSymbols[iSym].StorageClass) + { + case IMAGE_SYM_CLASS_EXTERNAL: + if (idxSection != IMAGE_SYM_ABSOLUTE) + { + if (pThis->paSegments[idxSection - 1].iSegDef != UINT16_MAX) + { + pThis->paSymbols[iSym].enmType = OMFSYMTYPE_PUBDEF; + pThis->paSymbols[iSym].idxSegDef = pThis->paSegments[idxSection - 1].iSegDef; + pThis->paSymbols[iSym].idxGrpDef = pThis->paSegments[idxSection - 1].iGrpDef; + pThis->paSegments[idxSection - 1].cPubDefs++; + cPubSyms++; + } + } + else + { + pThis->paSymbols[iSym].enmType = OMFSYMTYPE_PUBDEF; + pThis->paSymbols[iSym].idxSegDef = 0; + pThis->paSymbols[iSym].idxGrpDef = 0; + cAbsSyms++; + } + break; + + case IMAGE_SYM_CLASS_STATIC: + if ( paSymbols[iSym].Value == 0 + && idxSection != IMAGE_SYM_ABSOLUTE + && isCoffSymbolMatchingSectionName(pszSymName, paShdrs[idxSection - 1].Name) ) + { + pThis->paSymbols[iSym].enmType = OMFSYMTYPE_SEGDEF; + pThis->paSymbols[iSym].idxSegDef = pThis->paSegments[idxSection - 1].iSegDef; + pThis->paSymbols[iSym].idxGrpDef = pThis->paSegments[idxSection - 1].iGrpDef; + break; + } + RT_FALL_THRU(); + + case IMAGE_SYM_CLASS_END_OF_FUNCTION: + case IMAGE_SYM_CLASS_AUTOMATIC: + case IMAGE_SYM_CLASS_REGISTER: + case IMAGE_SYM_CLASS_LABEL: + case IMAGE_SYM_CLASS_MEMBER_OF_STRUCT: + case IMAGE_SYM_CLASS_ARGUMENT: + case IMAGE_SYM_CLASS_STRUCT_TAG: + case IMAGE_SYM_CLASS_MEMBER_OF_UNION: + case IMAGE_SYM_CLASS_UNION_TAG: + case IMAGE_SYM_CLASS_TYPE_DEFINITION: + case IMAGE_SYM_CLASS_ENUM_TAG: + case IMAGE_SYM_CLASS_MEMBER_OF_ENUM: + case IMAGE_SYM_CLASS_REGISTER_PARAM: + case IMAGE_SYM_CLASS_BIT_FIELD: + case IMAGE_SYM_CLASS_BLOCK: + case IMAGE_SYM_CLASS_FUNCTION: + case IMAGE_SYM_CLASS_END_OF_STRUCT: + case IMAGE_SYM_CLASS_FILE: + pThis->paSymbols[iSym].enmType = OMFSYMTYPE_INTERNAL; + if (idxSection != IMAGE_SYM_ABSOLUTE) + { + pThis->paSymbols[iSym].idxSegDef = pThis->paSegments[idxSection - 1].iSegDef; + pThis->paSymbols[iSym].idxGrpDef = pThis->paSegments[idxSection - 1].iGrpDef; + } + else + { + pThis->paSymbols[iSym].idxSegDef = 0; + pThis->paSymbols[iSym].idxGrpDef = 0; + } + break; + + case IMAGE_SYM_CLASS_SECTION: + case IMAGE_SYM_CLASS_EXTERNAL_DEF: + case IMAGE_SYM_CLASS_NULL: + case IMAGE_SYM_CLASS_UNDEFINED_LABEL: + case IMAGE_SYM_CLASS_UNDEFINED_STATIC: + case IMAGE_SYM_CLASS_CLR_TOKEN: + case IMAGE_SYM_CLASS_FAR_EXTERNAL: + case IMAGE_SYM_CLASS_WEAK_EXTERNAL: + return error(pThis->pszSrc, "Unsupported storage class value %#x for symbol #%u (%s)\n", + paSymbols[iSym].StorageClass, iSym, pszSymName); + + default: + return error(pThis->pszSrc, "Unknown storage class value %#x for symbol #%u (%s)\n", + paSymbols[iSym].StorageClass, iSym, pszSymName); + } + } + else if (idxSection == IMAGE_SYM_UNDEFINED) + { + if ( paSymbols[iSym].StorageClass == IMAGE_SYM_CLASS_EXTERNAL + || paSymbols[iSym].StorageClass == IMAGE_SYM_CLASS_EXTERNAL_DEF) + { + pThis->paSymbols[iSym].enmType = OMFSYMTYPE_EXTDEF; + cExtSyms++; + if (iSymImageBase == UINT32_MAX && strcmp(pszSymName, "__ImageBase") == 0) + iSymImageBase = iSym; + } + else + return error(pThis->pszSrc, "Unknown/unknown storage class value %#x for undefined symbol #%u (%s)\n", + paSymbols[iSym].StorageClass, iSym, pszSymName); + } + else if (idxSection != IMAGE_SYM_DEBUG) + return error(pThis->pszSrc, "Invalid section number %#x for symbol #%u (%s)\n", idxSection, iSym, pszSymName); + + /* Skip AUX symbols. */ + uint8_t cAuxSyms = paSymbols[iSym].NumberOfAuxSymbols; + while (cAuxSyms-- > 0) + { + iSym++; + pThis->paSymbols[iSym].enmType = OMFSYMTYPE_INVALID; + pThis->paSymbols[iSym].idx = UINT16_MAX; + } + } + + /* + * Emit the PUBDEFs the first time around (see order of records in TIS spec). + */ + uint16_t idxPubDef = 1; + if (cPubSyms) + { + for (uint32_t iSeg = 0; iSeg < pThis->cSegments; iSeg++) + if (pThis->paSegments[iSeg].cPubDefs > 0) + { + uint16_t const idxSegDef = pThis->paSegments[iSeg].iSegDef; + if (!omfWriter_PubDefBegin(pThis, pThis->paSegments[iSeg].iGrpDef, idxSegDef)) + return false; + for (uint16_t iSym = 0; iSym < cSymbols; iSym++) + if ( pThis->paSymbols[iSym].idxSegDef == idxSegDef + && pThis->paSymbols[iSym].enmType == OMFSYMTYPE_PUBDEF) + { + /* Underscore prefix all symbols not already underscored or mangled. */ + const char *pszName = coffGetSymbolName(&paSymbols[iSym], pchStrTab, cbStrTab, szShort); + if (!omfWriter_PubDefAdd(pThis, paSymbols[iSym].Value, pszName, pszName[0] != '_' && pszName[0] != '?')) + return false; + pThis->paSymbols[iSym].idx = idxPubDef++; + } + if (!omfWriter_PubDefEnd(pThis)) + return false; + } + } + + if (cAbsSyms > 0) + { + if (!omfWriter_PubDefBegin(pThis, 0, 0)) + return false; + for (uint16_t iSym = 0; iSym < cSymbols; iSym++) + if ( pThis->paSymbols[iSym].idxSegDef == 0 + && pThis->paSymbols[iSym].enmType == OMFSYMTYPE_PUBDEF) + { + /* Underscore prefix all symbols not already underscored or mangled. */ + const char *pszName = coffGetSymbolName(&paSymbols[iSym], pchStrTab, cbStrTab, szShort); + if (!omfWriter_PubDefAdd(pThis, paSymbols[iSym].Value, pszName, pszName[0] != '_' && pszName[0] != '?') ) + return false; + pThis->paSymbols[iSym].idx = idxPubDef++; + } + if (!omfWriter_PubDefEnd(pThis)) + return false; + } + + /* + * Go over the symbol table and emit external definition records. + */ + if (!omfWriter_ExtDefBegin(pThis)) + return false; + uint16_t idxExtDef = 1; + for (uint16_t iSym = 0; iSym < cSymbols; iSym++) + if (pThis->paSymbols[iSym].enmType == OMFSYMTYPE_EXTDEF) + { + /* Underscore prefix all symbols not already underscored or mangled. */ + const char *pszName = coffGetSymbolName(&paSymbols[iSym], pchStrTab, cbStrTab, szShort); + if (!omfWriter_ExtDefAdd(pThis, pszName, pszName[0] != '_' && pszName[0] != '?')) + return false; + pThis->paSymbols[iSym].idx = idxExtDef++; + } + + /* Always add an __ImageBase reference, in case we need it to deal with ADDR32NB fixups. */ + /** @todo maybe we don't actually need this and could use FLAT instead? */ + if (iSymImageBase != UINT32_MAX) + pThis->idxExtImageBase = pThis->paSymbols[iSymImageBase].idx; + else if (omfWriter_ExtDefAdd(pThis, "__ImageBase", false /*fPrependUnderscore*/)) + pThis->idxExtImageBase = idxExtDef; + else + return false; + + if (!omfWriter_ExtDefEnd(pThis)) + return false; + + return true; +} + + +static bool convertCoffSectionsToLeDataAndFixupps(POMFWRITER pThis, uint8_t const *pbFile, size_t cbFile, + PCIMAGE_SECTION_HEADER paShdrs, uint16_t cSections, + PCIMAGE_SYMBOL paSymbols, uint16_t cSymbols, const char *pchStrTab) +{ + RT_NOREF_PV(cbFile); + RT_NOREF_PV(cSections); + RT_NOREF_PV(cSymbols); + + uint32_t const cbStrTab = *(uint32_t const *)pchStrTab; + bool fRet = true; + for (uint32_t i = 0; i < pThis->cSegments; i++) + { + if (pThis->paSegments[i].iSegDef == UINT16_MAX) + continue; + + char szShortName[16]; + const char *pszSegNm = pThis->paSegments[i].pszName; + uint16_t cRelocs = paShdrs[i].NumberOfRelocations; + PCIMAGE_RELOCATION paRelocs = (PCIMAGE_RELOCATION)&pbFile[paShdrs[i].PointerToRelocations]; + uint32_t cbVirtData = paShdrs[i].SizeOfRawData; + uint32_t cbData = paShdrs[i].Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA ? 0 : cbVirtData; + uint8_t const *pbData = &pbFile[paShdrs[i].PointerToRawData]; + uint32_t off = 0; + + /* Check that the relocations are sorted and within the section. */ + for (uint32_t iReloc = 1; iReloc < cRelocs; iReloc++) + if (paRelocs[iReloc - 1].u.VirtualAddress >= paRelocs[iReloc].u.VirtualAddress) + return error(pThis->pszSrc, "Section #%u (%s) relocations aren't sorted\n", i, pszSegNm); + if ( cRelocs > 0 + && paRelocs[cRelocs - 1].u.VirtualAddress - paShdrs[i].VirtualAddress + + COFF_AMD64_RELOC_SIZE(paRelocs[cRelocs - 1].Type) > cbVirtData) + return error(pThis->pszSrc, + "Section #%u (%s) relocations beyond section data! cbVirtData=%#x RvaFix=%#x RVASeg=%#x type=%#x\n", + i, pszSegNm, cbVirtData, paRelocs[cRelocs - 1].u.VirtualAddress, paShdrs[i].VirtualAddress, + paRelocs[cRelocs - 1].Type); + + /* The OMF record size requires us to split larger sections up. To make + life simple, we fill zeros for unitialized (BSS) stuff. */ + const uint32_t cbMaxData = RT_MIN(OMF_MAX_RECORD_PAYLOAD - 1 - (pThis->paSegments[i].iSegDef >= 128) - 4 - 1, _1K); + while (cbVirtData > 0) + { + /* Figure out how many bytes to put out in this chunk. Must make sure + fixups doesn't cross chunk boundraries. ASSUMES sorted relocs. */ + uint32_t cChunkRelocs = cRelocs; + uint32_t cbChunk = cbVirtData; + uint32_t uRvaEnd = paShdrs[i].VirtualAddress + off + cbChunk; + if (cbChunk > cbMaxData) + { + cbChunk = cbMaxData; + uRvaEnd = paShdrs[i].VirtualAddress + off + cbChunk; + cChunkRelocs = 0; + + /* Quickly determin the reloc range. */ + while ( cChunkRelocs < cRelocs + && paRelocs[cChunkRelocs].u.VirtualAddress < uRvaEnd) + cChunkRelocs++; + + /* Ensure final reloc doesn't go beyond chunk. */ + while ( cChunkRelocs > 0 + && paRelocs[cChunkRelocs - 1].u.VirtualAddress + COFF_AMD64_RELOC_SIZE(paRelocs[cChunkRelocs - 1].Type) + > uRvaEnd) + { + uint32_t cbDrop = uRvaEnd - paRelocs[cChunkRelocs - 1].u.VirtualAddress; + cbChunk -= cbDrop; + uRvaEnd -= cbDrop; + cChunkRelocs--; + } + + if (!cbVirtData) + return error(pThis->pszSrc, "Wtf? cbVirtData is zero!\n"); + } + + /* + * We stash the bytes into the OMF writer record buffer, receiving a + * pointer to the start of it so we can make adjustments if necessary. + */ + uint8_t *pbCopy; + if (!omfWriter_LEDataBeginEx(pThis, pThis->paSegments[i].iSegDef, off, cbChunk, cbData, pbData, &pbCopy)) + return false; + + /* + * Convert fiuxps. + */ + uint32_t const uRvaChunk = paShdrs[i].VirtualAddress + off; + for (uint32_t iReloc = 0; iReloc < cChunkRelocs; iReloc++) + { + /* Get the OMF and COFF data for the symbol the reloc references. */ + if (paRelocs[iReloc].SymbolTableIndex >= pThis->cSymbols) + return error(pThis->pszSrc, "Relocation symtab index (%#x) is out of range in segment #%u '%s'\n", + paRelocs[iReloc].SymbolTableIndex, i, pszSegNm); + PCIMAGE_SYMBOL pCoffSym = &paSymbols[paRelocs[iReloc].SymbolTableIndex]; + POMFSYMBOL pOmfSym = &pThis->paSymbols[paRelocs[iReloc].SymbolTableIndex]; + + /* Calc fixup location in the pending chunk and setup a flexible pointer to it. */ + uint16_t offDataRec = (uint16_t)(paRelocs[iReloc].u.VirtualAddress - uRvaChunk); + RTPTRUNION uLoc; + uLoc.pu8 = &pbCopy[offDataRec]; + + /* OMF fixup data initialized with typical defaults. */ + bool fSelfRel = true; + uint8_t bLocation = OMF_FIX_LOC_32BIT_OFFSET; + uint8_t bFrame = OMF_FIX_F_GRPDEF; + uint16_t idxFrame = pThis->idxGrpFlat; + uint8_t bTarget; + uint16_t idxTarget; + bool fTargetDisp; + uint32_t offTargetDisp; + switch (pOmfSym->enmType) + { + case OMFSYMTYPE_INTERNAL: + case OMFSYMTYPE_PUBDEF: + bTarget = OMF_FIX_T_SEGDEF; + idxTarget = pOmfSym->idxSegDef; + fTargetDisp = true; + offTargetDisp = pCoffSym->Value; + break; + + case OMFSYMTYPE_SEGDEF: + bTarget = OMF_FIX_T_SEGDEF_NO_DISP; + idxTarget = pOmfSym->idxSegDef; + fTargetDisp = false; + offTargetDisp = 0; + break; + + case OMFSYMTYPE_EXTDEF: + bTarget = OMF_FIX_T_EXTDEF_NO_DISP; + idxTarget = pOmfSym->idx; + fTargetDisp = false; + offTargetDisp = 0; + break; + + default: + return error(pThis->pszSrc, "Relocation in segment #%u '%s' references ignored or invalid symbol (%s)\n", + i, pszSegNm, coffGetSymbolName(pCoffSym, pchStrTab, cbStrTab, szShortName)); + } + + /* Do COFF relocation type conversion. */ + switch (paRelocs[iReloc].Type) + { + case IMAGE_REL_AMD64_ADDR64: + { + uint64_t uAddend = *uLoc.pu64; + if (uAddend > _1G) + fRet = error(pThis->pszSrc, "ADDR64 with large addend (%#llx) at %#x in segment #%u '%s'\n", + uAddend, paRelocs[iReloc].u.VirtualAddress, i, pszSegNm); + fSelfRel = false; + break; + } + + case IMAGE_REL_AMD64_REL32_1: + case IMAGE_REL_AMD64_REL32_2: + case IMAGE_REL_AMD64_REL32_3: + case IMAGE_REL_AMD64_REL32_4: + case IMAGE_REL_AMD64_REL32_5: + /** @todo Check whether OMF read addends from the data or relies on the + * displacement. Also, check what it's relative to. */ + *uLoc.pu32 -= paRelocs[iReloc].Type - IMAGE_REL_AMD64_REL32; + break; + + case IMAGE_REL_AMD64_ADDR32: + fSelfRel = false; + break; + + case IMAGE_REL_AMD64_ADDR32NB: + fSelfRel = false; + bFrame = OMF_FIX_F_EXTDEF; + idxFrame = pThis->idxExtImageBase; + break; + + case IMAGE_REL_AMD64_REL32: + /* defaults are ok. */ + break; + + case IMAGE_REL_AMD64_SECTION: + bLocation = OMF_FIX_LOC_16BIT_SEGMENT; + RT_FALL_THRU(); + + case IMAGE_REL_AMD64_SECREL: + fSelfRel = false; + if (pOmfSym->enmType == OMFSYMTYPE_EXTDEF) + { + bFrame = OMF_FIX_F_EXTDEF; + idxFrame = pOmfSym->idx; + } + else + { + bFrame = OMF_FIX_F_SEGDEF; + idxFrame = pOmfSym->idxSegDef; + } + break; + + case IMAGE_REL_AMD64_ABSOLUTE: + continue; /* Ignore it like the PECOFF.DOC says we should. */ + + case IMAGE_REL_AMD64_SECREL7: + default: + return error(pThis->pszSrc, "Unsupported fixup type %#x (%s) at rva=%#x in section #%u '%-8.8s'\n", + paRelocs[iReloc].Type, + paRelocs[iReloc].Type < RT_ELEMENTS(g_apszCoffAmd64RelTypes) + ? g_apszCoffAmd64RelTypes[paRelocs[iReloc].Type] : "unknown", + paRelocs[iReloc].u.VirtualAddress, i, paShdrs[i].Name); + } + + /* Add the fixup. */ + if (idxFrame == UINT16_MAX) + error(pThis->pszSrc, "idxFrame=UINT16_MAX for %s type=%s\n", + coffGetSymbolName(pCoffSym, pchStrTab, cbStrTab, szShortName), + g_apszCoffAmd64RelTypes[paRelocs[iReloc].Type]); + fRet = omfWriter_LEDataAddFixup(pThis, offDataRec, fSelfRel, bLocation, bFrame, idxFrame, + bTarget, idxTarget, fTargetDisp, offTargetDisp) && fRet; + } + + /* + * Write the LEDATA and associated FIXUPPs. + */ + if (!omfWriter_LEDataEnd(pThis)) + return false; + + /* + * Advance. + */ + paRelocs += cChunkRelocs; + cRelocs -= cChunkRelocs; + if (cbData > cbChunk) + { + cbData -= cbChunk; + pbData += cbChunk; + } + else + cbData = 0; + off += cbChunk; + cbVirtData -= cbChunk; + } + } + + return fRet; +} + + +static bool convertCoffToOmf(const char *pszFile, uint8_t const *pbFile, size_t cbFile, FILE *pDst) +{ + /* + * Validate the source file a little. + */ + if (!validateCoff(pszFile, pbFile, cbFile)) + return false; + + /* + * Instantiate the OMF writer. + */ + PIMAGE_FILE_HEADER pHdr = (PIMAGE_FILE_HEADER)pbFile; + POMFWRITER pThis = omfWriter_Create(pszFile, pHdr->NumberOfSections, pHdr->NumberOfSymbols, pDst); + if (!pThis) + return false; + + /* + * Write the OMF object file. + */ + if (omfWriter_BeginModule(pThis, pszFile)) + { + PCIMAGE_SECTION_HEADER paShdrs = (PCIMAGE_SECTION_HEADER)(pHdr + 1); + PCIMAGE_SYMBOL paSymTab = (PCIMAGE_SYMBOL)&pbFile[pHdr->PointerToSymbolTable]; + const char *pchStrTab = (const char *)&paSymTab[pHdr->NumberOfSymbols]; + if ( convertCoffSectionsToSegDefsAndGrpDefs(pThis, paShdrs, pHdr->NumberOfSections) + && convertCoffSymbolsToPubDefsAndExtDefs(pThis, paSymTab, pHdr->NumberOfSymbols, pchStrTab, paShdrs) + && omfWriter_LinkPassSeparator(pThis) + && convertCoffSectionsToLeDataAndFixupps(pThis, pbFile, cbFile, paShdrs, pHdr->NumberOfSections, + paSymTab, pHdr->NumberOfSymbols, pchStrTab) + && omfWriter_EndModule(pThis) ) + { + + omfWriter_Destroy(pThis); + return true; + } + } + + omfWriter_Destroy(pThis); + return false; +} + + +/********************************************************************************************************************************* +* Mach-O/AMD64 -> OMF/i386 Converter * +*********************************************************************************************************************************/ + +//#define MACHO_TO_OMF_CONVERSION +#ifdef MACHO_TO_OMF_CONVERSION + +/** AMD64 relocation type names for Mach-O. */ +static const char * const g_apszMachOAmd64RelTypes[] = +{ + "X86_64_RELOC_UNSIGNED", + "X86_64_RELOC_SIGNED", + "X86_64_RELOC_BRANCH", + "X86_64_RELOC_GOT_LOAD", + "X86_64_RELOC_GOT", + "X86_64_RELOC_SUBTRACTOR", + "X86_64_RELOC_SIGNED_1", + "X86_64_RELOC_SIGNED_2", + "X86_64_RELOC_SIGNED_4" +}; + +/** AMD64 relocation type sizes for Mach-O. */ +static uint8_t const g_acbMachOAmd64RelTypes[] = +{ + 8, /* X86_64_RELOC_UNSIGNED */ + 4, /* X86_64_RELOC_SIGNED */ + 4, /* X86_64_RELOC_BRANCH */ + 4, /* X86_64_RELOC_GOT_LOAD */ + 4, /* X86_64_RELOC_GOT */ + 8, /* X86_64_RELOC_SUBTRACTOR */ + 4, /* X86_64_RELOC_SIGNED_1 */ + 4, /* X86_64_RELOC_SIGNED_2 */ + 4, /* X86_64_RELOC_SIGNED_4 */ +}; + +/** Macro for getting the size of a AMD64 Mach-O relocation. */ +#define MACHO_AMD64_RELOC_SIZE(a_Type) ( (a_Type) < RT_ELEMENTS(g_acbMachOAmd64RelTypes) ? g_acbMachOAmd64RelTypes[(a_Type)] : 1) + + +typedef struct MACHODETAILS +{ + /** The ELF header. */ + Elf64_Ehdr const *pEhdr; + /** The section header table. */ + Elf64_Shdr const *paShdrs; + /** The string table for the section names. */ + const char *pchShStrTab; + + /** The symbol table section number. UINT16_MAX if not found. */ + uint16_t iSymSh; + /** The string table section number. UINT16_MAX if not found. */ + uint16_t iStrSh; + + /** The symbol table. */ + Elf64_Sym const *paSymbols; + /** The number of symbols in the symbol table. */ + uint32_t cSymbols; + + /** Pointer to the (symbol) string table if found. */ + const char *pchStrTab; + /** The string table size. */ + size_t cbStrTab; + +} MACHODETAILS; +typedef MACHODETAILS *PMACHODETAILS; +typedef MACHODETAILS const *PCMACHODETAILS; + + +static bool validateMacho(const char *pszFile, uint8_t const *pbFile, size_t cbFile, PMACHODETAILS pMachOStuff) +{ + /* + * Initialize the Mach-O details structure. + */ + memset(pMachOStuff, 0, sizeof(*pMachOStuff)); + pMachOStuff->iSymSh = UINT16_MAX; + pMachOStuff->iStrSh = UINT16_MAX; + + /* + * Validate the header and our other expectations. + */ + Elf64_Ehdr const *pEhdr = (Elf64_Ehdr const *)pbFile; + pMachOStuff->pEhdr = pEhdr; + if ( pEhdr->e_ident[EI_CLASS] != ELFCLASS64 + || pEhdr->e_ident[EI_DATA] != ELFDATA2LSB + || pEhdr->e_ehsize != sizeof(Elf64_Ehdr) + || pEhdr->e_shentsize != sizeof(Elf64_Shdr) + || pEhdr->e_version != EV_CURRENT ) + return error(pszFile, "Unsupported ELF config\n"); + if (pEhdr->e_type != ET_REL) + return error(pszFile, "Expected relocatable ELF file (e_type=%d)\n", pEhdr->e_type); + if (pEhdr->e_machine != EM_X86_64) + return error(pszFile, "Expected relocatable ELF file (e_type=%d)\n", pEhdr->e_machine); + if (pEhdr->e_phnum != 0) + return error(pszFile, "Expected e_phnum to be zero not %u\n", pEhdr->e_phnum); + if (pEhdr->e_shnum < 2) + return error(pszFile, "Expected e_shnum to be two or higher\n"); + if (pEhdr->e_shstrndx >= pEhdr->e_shnum || pEhdr->e_shstrndx == 0) + return error(pszFile, "Bad e_shstrndx=%u (e_shnum=%u)\n", pEhdr->e_shstrndx, pEhdr->e_shnum); + if ( pEhdr->e_shoff >= cbFile + || pEhdr->e_shoff + pEhdr->e_shnum * sizeof(Elf64_Shdr) > cbFile) + return error(pszFile, "Section table is outside the file (e_shoff=%#llx, e_shnum=%u, cbFile=%#llx)\n", + pEhdr->e_shstrndx, pEhdr->e_shnum, (uint64_t)cbFile); + + /* + * Locate the section name string table. + * We assume it's okay as we only reference it in verbose mode. + */ + Elf64_Shdr const *paShdrs = (Elf64_Shdr const *)&pbFile[pEhdr->e_shoff]; + pMachOStuff->paShdrs = paShdrs; + + Elf64_Xword const cbShStrTab = paShdrs[pEhdr->e_shstrndx].sh_size; + if ( paShdrs[pEhdr->e_shstrndx].sh_offset > cbFile + || cbShStrTab > cbFile + || paShdrs[pEhdr->e_shstrndx].sh_offset + cbShStrTab > cbFile) + return error(pszFile, + "Section string table is outside the file (sh_offset=%#" ELF_FMT_X64 " sh_size=%#" ELF_FMT_X64 " cbFile=%#" ELF_FMT_X64 ")\n", + paShdrs[pEhdr->e_shstrndx].sh_offset, paShdrs[pEhdr->e_shstrndx].sh_size, (Elf64_Xword)cbFile); + const char *pchShStrTab = (const char *)&pbFile[paShdrs[pEhdr->e_shstrndx].sh_offset]; + pMachOStuff->pchShStrTab = pchShStrTab; + + /* + * Work the section table. + */ + bool fRet = true; + for (uint32_t i = 1; i < pEhdr->e_shnum; i++) + { + if (paShdrs[i].sh_name >= cbShStrTab) + return error(pszFile, "Invalid sh_name value (%#x) for section #%u\n", paShdrs[i].sh_name, i); + const char *pszShNm = &pchShStrTab[paShdrs[i].sh_name]; + + if ( paShdrs[i].sh_offset > cbFile + || paShdrs[i].sh_size > cbFile + || paShdrs[i].sh_offset + paShdrs[i].sh_size > cbFile) + return error(pszFile, "Section #%u '%s' has data outside the file: %#" ELF_FMT_X64 " LB %#" ELF_FMT_X64 " (cbFile=%#" ELF_FMT_X64 ")\n", + i, pszShNm, paShdrs[i].sh_offset, paShdrs[i].sh_size, (Elf64_Xword)cbFile); + if (g_cVerbose) + printf("shdr[%u]: name=%#x '%s' type=%#x flags=%#" ELF_FMT_X64 " addr=%#" ELF_FMT_X64 " off=%#" ELF_FMT_X64 " size=%#" ELF_FMT_X64 "\n" + " link=%u info=%#x align=%#" ELF_FMT_X64 " entsize=%#" ELF_FMT_X64 "\n", + i, paShdrs[i].sh_name, pszShNm, paShdrs[i].sh_type, paShdrs[i].sh_flags, + paShdrs[i].sh_addr, paShdrs[i].sh_offset, paShdrs[i].sh_size, + paShdrs[i].sh_link, paShdrs[i].sh_info, paShdrs[i].sh_addralign, paShdrs[i].sh_entsize); + + if (paShdrs[i].sh_link >= pEhdr->e_shnum) + return error(pszFile, "Section #%u '%s' links to a section outside the section table: %#x, max %#x\n", + i, pszShNm, paShdrs[i].sh_link, pEhdr->e_shnum); + if (!RT_IS_POWER_OF_TWO(paShdrs[i].sh_addralign)) + return error(pszFile, "Section #%u '%s' alignment value is not a power of two: %#" ELF_FMT_X64 "\n", + i, pszShNm, paShdrs[i].sh_addralign); + if (!RT_IS_POWER_OF_TWO(paShdrs[i].sh_addralign)) + return error(pszFile, "Section #%u '%s' alignment value is not a power of two: %#" ELF_FMT_X64 "\n", + i, pszShNm, paShdrs[i].sh_addralign); + if (paShdrs[i].sh_addr != 0) + return error(pszFile, "Section #%u '%s' has non-zero address: %#" ELF_FMT_X64 "\n", i, pszShNm, paShdrs[i].sh_addr); + + if (paShdrs[i].sh_type == SHT_RELA) + { + if (paShdrs[i].sh_entsize != sizeof(Elf64_Rela)) + return error(pszFile, "Expected sh_entsize to be %u not %u for section #%u (%s)\n", (unsigned)sizeof(Elf64_Rela), + paShdrs[i].sh_entsize, i, pszShNm); + uint32_t const cRelocs = paShdrs[i].sh_size / sizeof(Elf64_Rela); + if (cRelocs * sizeof(Elf64_Rela) != paShdrs[i].sh_size) + return error(pszFile, "Uneven relocation entry count in #%u (%s): sh_size=%#" ELF_FMT_X64 "\n", + i, pszShNm, paShdrs[i].sh_size); + if ( paShdrs[i].sh_offset > cbFile + || paShdrs[i].sh_size >= cbFile + || paShdrs[i].sh_offset + paShdrs[i].sh_size > cbFile) + return error(pszFile, "The content of section #%u '%s' is outside the file (%#" ELF_FMT_X64 " LB %#" ELF_FMT_X64 ", cbFile=%#lx)\n", + i, pszShNm, paShdrs[i].sh_offset, paShdrs[i].sh_size, (unsigned long)cbFile); + if (paShdrs[i].sh_info != i - 1) + return error(pszFile, "Expected relocation section #%u (%s) to link to previous section: sh_info=%#u\n", + i, pszShNm, (unsigned)paShdrs[i].sh_link); + if (paShdrs[paShdrs[i].sh_link].sh_type != SHT_SYMTAB) + return error(pszFile, "Expected relocation section #%u (%s) to link to symbol table: sh_link=%#u -> sh_type=%#x\n", + i, pszShNm, (unsigned)paShdrs[i].sh_link, (unsigned)paShdrs[paShdrs[i].sh_link].sh_type); + uint32_t cSymbols = paShdrs[paShdrs[i].sh_link].sh_size / paShdrs[paShdrs[i].sh_link].sh_entsize; + + Elf64_Rela const *paRelocs = (Elf64_Rela *)&pbFile[paShdrs[i].sh_offset]; + for (uint32_t j = 0; j < cRelocs; j++) + { + uint8_t const bType = ELF64_R_TYPE(paRelocs[j].r_info); + if (RT_UNLIKELY(bType >= R_X86_64_COUNT)) + fRet = error(pszFile, + "%#018" ELF_FMT_X64 " %#018" ELF_FMT_X64 ": unknown fix up %#x (%+" ELF_FMT_D64 ")\n", + paRelocs[j].r_offset, paRelocs[j].r_info, bType, paRelocs[j].r_addend); + if (RT_UNLIKELY( j > 1 + && paRelocs[j].r_offset <= paRelocs[j - 1].r_offset + && paRelocs[j].r_offset + ELF_AMD64_RELOC_SIZE(ELF64_R_TYPE(paRelocs[j].r_info)) + < paRelocs[j - 1].r_offset )) + fRet = error(pszFile, + "%#018" ELF_FMT_X64 " %#018" ELF_FMT_X64 ": out of offset order (prev %" ELF_FMT_X64 ")\n", + paRelocs[j].r_offset, paRelocs[j].r_info, paRelocs[j - 1].r_offset); + uint32_t const iSymbol = ELF64_R_SYM(paRelocs[j].r_info); + if (RT_UNLIKELY(iSymbol >= cSymbols)) + fRet = error(pszFile, + "%#018" ELF_FMT_X64 " %#018" ELF_FMT_X64 ": symbol index (%#x) out of bounds (%#x)\n", + paRelocs[j].r_offset, paRelocs[j].r_info, iSymbol, cSymbols); + } + if (RT_UNLIKELY( cRelocs > 0 + && fRet + && ( paRelocs[cRelocs - 1].r_offset > paShdrs[i - 1].sh_size + || paRelocs[cRelocs - 1].r_offset + ELF_AMD64_RELOC_SIZE(ELF64_R_TYPE(paRelocs[cRelocs-1].r_info)) + > paShdrs[i - 1].sh_size ))) + fRet = error(pszFile, + "%#018" ELF_FMT_X64 " %#018" ELF_FMT_X64 ": out of bounds (sh_size %" ELF_FMT_X64 ")\n", + paRelocs[cRelocs - 1].r_offset, paRelocs[cRelocs - 1].r_info, paShdrs[i - 1].sh_size); + + } + else if (paShdrs[i].sh_type == SHT_REL) + fRet = error(pszFile, "Section #%u '%s': Unexpected SHT_REL section\n", i, pszShNm); + else if (paShdrs[i].sh_type == SHT_SYMTAB) + { + if (paShdrs[i].sh_entsize != sizeof(Elf64_Sym)) + fRet = error(pszFile, "Section #%u '%s': Unsupported symbol table entry size in : #%u (expected #%u)\n", + i, pszShNm, paShdrs[i].sh_entsize, sizeof(Elf64_Sym)); + Elf64_Xword const cSymbols = paShdrs[i].sh_size / paShdrs[i].sh_entsize; + if (cSymbols * paShdrs[i].sh_entsize != paShdrs[i].sh_size) + fRet = error(pszFile, "Section #%u '%s': Size not a multiple of entry size: %#" ELF_FMT_X64 " %% %#" ELF_FMT_X64 " = %#" ELF_FMT_X64 "\n", + i, pszShNm, paShdrs[i].sh_size, paShdrs[i].sh_entsize, paShdrs[i].sh_size % paShdrs[i].sh_entsize); + if (cSymbols > UINT32_MAX) + fRet = error(pszFile, "Section #%u '%s': too many symbols: %" ELF_FMT_X64 "\n", + i, pszShNm, paShdrs[i].sh_size, cSymbols); + + if (pMachOStuff->iSymSh == UINT16_MAX) + { + pMachOStuff->iSymSh = (uint16_t)i; + pMachOStuff->paSymbols = (Elf64_Sym const *)&pbFile[paShdrs[i].sh_offset]; + pMachOStuff->cSymbols = cSymbols; + + if (paShdrs[i].sh_link != 0) + { + /* Note! The symbol string table section header may not have been validated yet! */ + Elf64_Shdr const *pStrTabShdr = &paShdrs[paShdrs[i].sh_link]; + pMachOStuff->iStrSh = paShdrs[i].sh_link; + pMachOStuff->pchStrTab = (const char *)&pbFile[pStrTabShdr->sh_offset]; + pMachOStuff->cbStrTab = (size_t)pStrTabShdr->sh_size; + } + else + fRet = error(pszFile, "Section #%u '%s': String table link is out of bounds (%#x)\n", + i, pszShNm, paShdrs[i].sh_link); + } + else + fRet = error(pszFile, "Section #%u '%s': Found additonal symbol table, previous in #%u\n", + i, pszShNm, pMachOStuff->iSymSh); + } + } + return fRet; +} + +static bool convertMachoSectionsToSegDefsAndGrpDefs(POMFWRITER pThis, PCMACHODETAILS pMachOStuff) +{ + /* + * Do the list of names pass. + */ + uint16_t idxGrpFlat, idxGrpData; + uint16_t idxClassCode, idxClassData, idxClassDwarf; + if ( !omfWriter_LNamesBegin(pThis, true /*fAddZeroEntry*/) + || !omfWriter_LNamesAddN(pThis, RT_STR_TUPLE("FLAT"), &idxGrpFlat) + || !omfWriter_LNamesAddN(pThis, RT_STR_TUPLE("BS3DATA64_GROUP"), &idxGrpData) + || !omfWriter_LNamesAddN(pThis, RT_STR_TUPLE("BS3CLASS64CODE"), &idxClassCode) + || !omfWriter_LNamesAddN(pThis, RT_STR_TUPLE("FAR_DATA"), &idxClassData) + || !omfWriter_LNamesAddN(pThis, RT_STR_TUPLE("DWARF"), &idxClassDwarf) + ) + return false; + + bool fHaveData = false; + Elf64_Shdr const *pShdr = &pMachOStuff->paShdrs[1]; + Elf64_Half const cSections = pMachOStuff->pEhdr->e_shnum; + for (Elf64_Half i = 1; i < cSections; i++, pShdr++) + { + const char *pszName = &pMachOStuff->pchShStrTab[pShdr->sh_name]; + if (*pszName == '\0') + return error(pThis->pszSrc, "Section #%u has an empty name!\n", i); + + switch (pShdr->sh_type) + { + case SHT_PROGBITS: + case SHT_NOBITS: + /* We drop a few sections we don't want:. */ + if ( strcmp(pszName, ".comment") != 0 /* compiler info */ + && strcmp(pszName, ".note.GNU-stack") != 0 /* some empty section for hinting the linker/whatever */ + && strcmp(pszName, ".eh_frame") != 0 /* unwind / exception info */ + ) + { + pThis->paSegments[i].iSegDef = UINT16_MAX; + pThis->paSegments[i].iGrpDef = UINT16_MAX; + + /* Translate the name and determine group and class. + Note! We currently strip sub-sections. */ + if ( strcmp(pszName, ".text") == 0 + || strncmp(pszName, RT_STR_TUPLE(".text.")) == 0) + { + pszName = "BS3TEXT64"; + pThis->paSegments[i].iGrpNm = idxGrpFlat; + pThis->paSegments[i].iClassNm = idxClassCode; + } + else if ( strcmp(pszName, ".data") == 0 + || strncmp(pszName, RT_STR_TUPLE(".data.")) == 0) + { + pszName = "BS3DATA64"; + pThis->paSegments[i].iGrpNm = idxGrpData; + pThis->paSegments[i].iClassNm = idxClassData; + } + else if (strcmp(pszName, ".bss") == 0) + { + pszName = "BS3BSS64"; + pThis->paSegments[i].iGrpNm = idxGrpData; + pThis->paSegments[i].iClassNm = idxClassData; + } + else if ( strcmp(pszName, ".rodata") == 0 + || strncmp(pszName, RT_STR_TUPLE(".rodata.")) == 0) + { + pszName = "BS3DATA64CONST"; + pThis->paSegments[i].iGrpNm = idxGrpData; + pThis->paSegments[i].iClassNm = idxClassData; + } + else if (strncmp(pszName, RT_STR_TUPLE(".debug_")) == 0) + { + pThis->paSegments[i].iGrpNm = UINT16_MAX; + pThis->paSegments[i].iClassNm = idxClassDwarf; + } + else + { + pThis->paSegments[i].iGrpNm = idxGrpData; + pThis->paSegments[i].iClassNm = idxClassData; + error(pThis->pszSrc, "Unknown data (?) segment: '%s'\n", pszName); + } + + /* Save the name. */ + pThis->paSegments[i].pszName = strdup(pszName); + if (!pThis->paSegments[i].pszName) + return error(pThis->pszSrc, "Out of memory!\n"); + + /* Add the section name. */ + if (!omfWriter_LNamesAdd(pThis, pThis->paSegments[i].pszName, &pThis->paSegments[i].iSegNm)) + return false; + + fHaveData |= pThis->paSegments[i].iGrpDef == idxGrpData; + break; + } + RT_FALL_THRU(); + + default: + pThis->paSegments[i].iSegDef = UINT16_MAX; + pThis->paSegments[i].iGrpDef = UINT16_MAX; + pThis->paSegments[i].iSegNm = UINT16_MAX; + pThis->paSegments[i].iGrpNm = UINT16_MAX; + pThis->paSegments[i].iClassNm = UINT16_MAX; + pThis->paSegments[i].pszName = NULL; + break; + } + } + + if (!omfWriter_LNamesEnd(pThis)) + return false; + + /* + * Emit segment definitions. + */ + uint16_t iSegDef = 1; /* Start counting at 1. */ + pShdr = &pMachOStuff->paShdrs[1]; + for (Elf64_Half i = 1; i < cSections; i++, pShdr++) + { + if (pThis->paSegments[i].iSegNm == UINT16_MAX) + continue; + + uint8_t bSegAttr = 0; + + /* The A field. */ + switch (pShdr->sh_addralign) + { + case 0: + case 1: + bSegAttr |= 1 << 5; + break; + case 2: + bSegAttr |= 2 << 5; + break; + case 4: + bSegAttr |= 5 << 5; + break; + case 8: + case 16: + bSegAttr |= 3 << 5; + break; + case 32: + case 64: + case 128: + case 256: + bSegAttr |= 4 << 5; + break; + default: + bSegAttr |= 6 << 5; /* page aligned, pharlabs extension. */ + break; + } + + /* The C field. */ + bSegAttr |= 2 << 2; /* public */ + + /* The B field. We don't have 4GB segments, so leave it as zero. */ + + /* The D field shall be set as we're doing USE32. */ + bSegAttr |= 1; + + + /* Done. */ + if (!omfWriter_SegDef(pThis, bSegAttr, (uint32_t)pShdr->sh_size, + pThis->paSegments[i].iSegNm, + pThis->paSegments[i].iClassNm)) + return false; + pThis->paSegments[i].iSegDef = iSegDef++; + } + + /* + * Flat group definition (#1) - special, no members. + */ + uint16_t iGrpDef = 1; + if ( !omfWriter_GrpDefBegin(pThis, idxGrpFlat) + || !omfWriter_GrpDefEnd(pThis)) + return false; + for (uint16_t i = 0; i < cSections; i++) + if (pThis->paSegments[i].iGrpNm == idxGrpFlat) + pThis->paSegments[i].iGrpDef = iGrpDef; + pThis->idxGrpFlat = iGrpDef++; + + /* + * Data group definition (#2). + */ + /** @todo do we need to consider missing segments and ordering? */ + uint16_t cGrpNms = 0; + uint16_t aiGrpNms[2] = { 0, 0 }; /* Shut up, GCC. */ + if (fHaveData) + aiGrpNms[cGrpNms++] = idxGrpData; + for (uint32_t iGrpNm = 0; iGrpNm < cGrpNms; iGrpNm++) + { + if (!omfWriter_GrpDefBegin(pThis, aiGrpNms[iGrpNm])) + return false; + for (uint16_t i = 0; i < cSections; i++) + if (pThis->paSegments[i].iGrpNm == aiGrpNms[iGrpNm]) + { + pThis->paSegments[i].iGrpDef = iGrpDef; + if (!omfWriter_GrpDefAddSegDef(pThis, pThis->paSegments[i].iSegDef)) + return false; + } + if (!omfWriter_GrpDefEnd(pThis)) + return false; + iGrpDef++; + } + + return true; +} + +static bool convertMachOSymbolsToPubDefsAndExtDefs(POMFWRITER pThis, PCMACHODETAILS pMachOStuff) +{ + if (!pMachOStuff->cSymbols) + return true; + + /* + * Process the symbols the first. + */ + uint32_t cAbsSyms = 0; + uint32_t cExtSyms = 0; + uint32_t cPubSyms = 0; + for (uint32_t iSeg = 0; iSeg < pThis->cSegments; iSeg++) + pThis->paSegments[iSeg].cPubDefs = 0; + + uint32_t const cSections = pMachOStuff->pEhdr->e_shnum; + uint32_t const cSymbols = pMachOStuff->cSymbols; + Elf64_Sym const * const paSymbols = pMachOStuff->paSymbols; + for (uint32_t iSym = 0; iSym < cSymbols; iSym++) + { + const uint8_t bBind = ELF64_ST_BIND(paSymbols[iSym].st_info); + const uint8_t bType = ELF64_ST_TYPE(paSymbols[iSym].st_info); + const char *pszSymName = &pMachOStuff->pchStrTab[paSymbols[iSym].st_name]; + if ( *pszSymName == '\0' + && bType == STT_SECTION + && paSymbols[iSym].st_shndx < cSections) + pszSymName = &pMachOStuff->pchShStrTab[pMachOStuff->paShdrs[paSymbols[iSym].st_shndx].sh_name]; + + pThis->paSymbols[iSym].enmType = OMFSYMTYPE_IGNORED; + pThis->paSymbols[iSym].idx = UINT16_MAX; + pThis->paSymbols[iSym].idxSegDef = UINT16_MAX; + pThis->paSymbols[iSym].idxGrpDef = UINT16_MAX; + + uint32_t const idxSection = paSymbols[iSym].st_shndx; + if (idxSection == SHN_UNDEF) + { + if (bBind == STB_GLOBAL) + { + pThis->paSymbols[iSym].enmType = OMFSYMTYPE_EXTDEF; + cExtSyms++; + if (*pszSymName == '\0') + return error(pThis->pszSrc, "External symbol #%u (%s) has an empty name.\n", iSym, pszSymName); + } + else if (bBind != STB_LOCAL || iSym != 0) /* Entry zero is usually a dummy. */ + return error(pThis->pszSrc, "Unsupported or invalid bind type %#x for undefined symbol #%u (%s)\n", + bBind, iSym, pszSymName); + } + else if (idxSection < cSections) + { + pThis->paSymbols[iSym].idxSegDef = pThis->paSegments[idxSection].iSegDef; + pThis->paSymbols[iSym].idxGrpDef = pThis->paSegments[idxSection].iGrpDef; + if (bBind == STB_GLOBAL) + { + pThis->paSymbols[iSym].enmType = OMFSYMTYPE_PUBDEF; + pThis->paSegments[idxSection].cPubDefs++; + cPubSyms++; + if (bType == STT_SECTION) + return error(pThis->pszSrc, "Don't know how to export STT_SECTION symbol #%u (%s)\n", iSym, pszSymName); + if (*pszSymName == '\0') + return error(pThis->pszSrc, "Public symbol #%u (%s) has an empty name.\n", iSym, pszSymName); + } + else if (bType == STT_SECTION) + pThis->paSymbols[iSym].enmType = OMFSYMTYPE_SEGDEF; + else + pThis->paSymbols[iSym].enmType = OMFSYMTYPE_INTERNAL; + } + else if (idxSection == SHN_ABS) + { + if (bType != STT_FILE) + { + if (bBind == STB_GLOBAL) + { + pThis->paSymbols[iSym].enmType = OMFSYMTYPE_PUBDEF; + pThis->paSymbols[iSym].idxSegDef = 0; + pThis->paSymbols[iSym].idxGrpDef = 0; + cAbsSyms++; + if (*pszSymName == '\0') + return error(pThis->pszSrc, "Public absolute symbol #%u (%s) has an empty name.\n", iSym, pszSymName); + } + else + return error(pThis->pszSrc, "Unsupported or invalid bind type %#x for absolute symbol #%u (%s)\n", + bBind, iSym, pszSymName); + } + } + else + return error(pThis->pszSrc, "Unsupported or invalid section number %#x for symbol #%u (%s)\n", + idxSection, iSym, pszSymName); + } + + /* + * Emit the PUBDEFs the first time around (see order of records in TIS spec). + * Note! We expect the os x compiler to always underscore symbols, so unlike the + * other 64-bit converters we don't need to check for underscores and add them. + */ + uint16_t idxPubDef = 1; + if (cPubSyms) + { + for (uint32_t iSeg = 0; iSeg < pThis->cSegments; iSeg++) + if (pThis->paSegments[iSeg].cPubDefs > 0) + { + uint16_t const idxSegDef = pThis->paSegments[iSeg].iSegDef; + if (!omfWriter_PubDefBegin(pThis, pThis->paSegments[iSeg].iGrpDef, idxSegDef)) + return false; + for (uint16_t iSym = 0; iSym < cSymbols; iSym++) + if ( pThis->paSymbols[iSym].idxSegDef == idxSegDef + && pThis->paSymbols[iSym].enmType == OMFSYMTYPE_PUBDEF) + { + const char *pszName = &pMachOStuff->pchStrTab[paSymbols[iSym].st_name]; + if (!omfWriter_PubDefAdd(pThis, paSymbols[iSym].st_value, pszName, false /*fPrependUnderscore*/)) + return false; + pThis->paSymbols[iSym].idx = idxPubDef++; + } + if (!omfWriter_PubDefEnd(pThis)) + return false; + } + } + + if (cAbsSyms > 0) + { + if (!omfWriter_PubDefBegin(pThis, 0, 0)) + return false; + for (uint16_t iSym = 0; iSym < cSymbols; iSym++) + if ( pThis->paSymbols[iSym].idxSegDef == 0 + && pThis->paSymbols[iSym].enmType == OMFSYMTYPE_PUBDEF) + { + const char *pszName = &pMachOStuff->pchStrTab[paSymbols[iSym].st_name]; + if (!omfWriter_PubDefAdd(pThis, paSymbols[iSym].st_value, pszName, false /*fPrependUnderscore*/)) + return false; + pThis->paSymbols[iSym].idx = idxPubDef++; + } + if (!omfWriter_PubDefEnd(pThis)) + return false; + } + + /* + * Go over the symbol table and emit external definition records. + */ + if (!omfWriter_ExtDefBegin(pThis)) + return false; + uint16_t idxExtDef = 1; + for (uint16_t iSym = 0; iSym < cSymbols; iSym++) + if (pThis->paSymbols[iSym].enmType == OMFSYMTYPE_EXTDEF) + { + const char *pszName = &pMachOStuff->pchStrTab[paSymbols[iSym].st_name]; + if (!omfWriter_ExtDefAdd(pThis, pszName, false /*fPrependUnderscore*/)) + return false; + pThis->paSymbols[iSym].idx = idxExtDef++; + } + + if (!omfWriter_ExtDefEnd(pThis)) + return false; + + return true; +} + +static bool convertMachOSectionsToLeDataAndFixupps(POMFWRITER pThis, PCMACHODETAILS pMachOStuff, + uint8_t const *pbFile, size_t cbFile) +{ + Elf64_Sym const *paSymbols = pMachOStuff->paSymbols; + Elf64_Shdr const *paShdrs = pMachOStuff->paShdrs; + bool fRet = true; + for (uint32_t i = 1; i < pThis->cSegments; i++) + { + if (pThis->paSegments[i].iSegDef == UINT16_MAX) + continue; + + const char *pszSegNm = &pMachOStuff->pchShStrTab[paShdrs[i].sh_name]; + bool const fRelocs = i + 1 < pThis->cSegments && paShdrs[i + 1].sh_type == SHT_RELA; + uint32_t cRelocs = fRelocs ? paShdrs[i + 1].sh_size / sizeof(Elf64_Rela) : 0; + Elf64_Rela const *paRelocs = fRelocs ? (Elf64_Rela *)&pbFile[paShdrs[i + 1].sh_offset] : NULL; + Elf64_Xword cbVirtData = paShdrs[i].sh_size; + Elf64_Xword cbData = paShdrs[i].sh_type == SHT_NOBITS ? 0 : cbVirtData; + uint8_t const *pbData = &pbFile[paShdrs[i].sh_offset]; + uint32_t off = 0; + + /* The OMF record size requires us to split larger sections up. To make + life simple, we fill zeros for unitialized (BSS) stuff. */ + const uint32_t cbMaxData = RT_MIN(OMF_MAX_RECORD_PAYLOAD - 1 - (pThis->paSegments[i].iSegDef >= 128) - 4 - 1, _1K); + while (cbVirtData > 0) + { + /* Figure out how many bytes to put out in this chunk. Must make sure + fixups doesn't cross chunk boundraries. ASSUMES sorted relocs. */ + uint32_t cChunkRelocs = cRelocs; + uint32_t cbChunk = cbVirtData; + uint32_t offEnd = off + cbChunk; + if (cbChunk > cbMaxData) + { + cbChunk = cbMaxData; + offEnd = off + cbChunk; + cChunkRelocs = 0; + + /* Quickly determin the reloc range. */ + while ( cChunkRelocs < cRelocs + && paRelocs[cChunkRelocs].r_offset < offEnd) + cChunkRelocs++; + + /* Ensure final reloc doesn't go beyond chunk. */ + while ( cChunkRelocs > 0 + && paRelocs[cChunkRelocs - 1].r_offset + + ELF_AMD64_RELOC_SIZE(ELF64_R_TYPE(paRelocs[cChunkRelocs - 1].r_info)) + > offEnd) + { + uint32_t cbDrop = offEnd - paRelocs[cChunkRelocs - 1].r_offset; + cbChunk -= cbDrop; + offEnd -= cbDrop; + cChunkRelocs--; + } + + if (!cbVirtData) + return error(pThis->pszSrc, "Wtf? cbVirtData is zero!\n"); + } + + /* + * We stash the bytes into the OMF writer record buffer, receiving a + * pointer to the start of it so we can make adjustments if necessary. + */ + uint8_t *pbCopy; + if (!omfWriter_LEDataBeginEx(pThis, pThis->paSegments[i].iSegDef, off, cbChunk, cbData, pbData, &pbCopy)) + return false; + + /* + * Convert fiuxps. + */ + for (uint32_t iReloc = 0; iReloc < cChunkRelocs; iReloc++) + { + /* Get the OMF and ELF data for the symbol the reloc references. */ + uint32_t const uType = ELF64_R_TYPE(paRelocs[iReloc].r_info); + uint32_t const iSymbol = ELF64_R_SYM(paRelocs[iReloc].r_info); + Elf64_Sym const * const pElfSym = &paSymbols[iSymbol]; + POMFSYMBOL const pOmfSym = &pThis->paSymbols[iSymbol]; + const char * const pszSymName = &pMachOStuff->pchStrTab[pElfSym->st_name]; + + /* Calc fixup location in the pending chunk and setup a flexible pointer to it. */ + uint16_t offDataRec = (uint16_t)(paRelocs[iReloc].r_offset - off); + RTPTRUNION uLoc; + uLoc.pu8 = &pbCopy[offDataRec]; + + /* OMF fixup data initialized with typical defaults. */ + bool fSelfRel = true; + uint8_t bLocation = OMF_FIX_LOC_32BIT_OFFSET; + uint8_t bFrame = OMF_FIX_F_GRPDEF; + uint16_t idxFrame = pThis->idxGrpFlat; + uint8_t bTarget; + uint16_t idxTarget; + bool fTargetDisp; + uint32_t offTargetDisp; + switch (pOmfSym->enmType) + { + case OMFSYMTYPE_INTERNAL: + case OMFSYMTYPE_PUBDEF: + bTarget = OMF_FIX_T_SEGDEF; + idxTarget = pOmfSym->idxSegDef; + fTargetDisp = true; + offTargetDisp = pElfSym->st_value; + break; + + case OMFSYMTYPE_SEGDEF: + bTarget = OMF_FIX_T_SEGDEF_NO_DISP; + idxTarget = pOmfSym->idxSegDef; + fTargetDisp = false; + offTargetDisp = 0; + break; + + case OMFSYMTYPE_EXTDEF: + bTarget = OMF_FIX_T_EXTDEF_NO_DISP; + idxTarget = pOmfSym->idx; + fTargetDisp = false; + offTargetDisp = 0; + break; + + default: + return error(pThis->pszSrc, "Relocation in segment #%u '%s' references ignored or invalid symbol (%s)\n", + i, pszSegNm, pszSymName); + } + + /* Do COFF relocation type conversion. */ + switch (uType) + { + case R_X86_64_64: + { + int64_t iAddend = paRelocs[iReloc].r_addend; + if (iAddend > _1G || iAddend < -_1G) + fRet = error(pThis->pszSrc, "R_X86_64_64 with large addend (%" ELF_FMT_D64 ") at %#x in segment #%u '%s'\n", + iAddend, paRelocs[iReloc].r_offset, i, pszSegNm); + *uLoc.pu64 = iAddend; + fSelfRel = false; + break; + } + + case R_X86_64_32: + case R_X86_64_32S: /* signed, unsigned, whatever. */ + fSelfRel = false; + RT_FALL_THRU(); + case R_X86_64_PC32: + { + /* defaults are ok, just handle the addend. */ + int32_t iAddend = paRelocs[iReloc].r_addend; + if (iAddend != paRelocs[iReloc].r_addend) + fRet = error(pThis->pszSrc, "R_X86_64_PC32 with large addend (%d) at %#x in segment #%u '%s'\n", + iAddend, paRelocs[iReloc].r_offset, i, pszSegNm); + *uLoc.pu32 = iAddend; + break; + } + + case R_X86_64_NONE: + continue; /* Ignore this one */ + + case R_X86_64_GOT32: + case R_X86_64_PLT32: + case R_X86_64_COPY: + case R_X86_64_GLOB_DAT: + case R_X86_64_JMP_SLOT: + case R_X86_64_RELATIVE: + case R_X86_64_GOTPCREL: + case R_X86_64_16: + case R_X86_64_PC16: + case R_X86_64_8: + case R_X86_64_PC8: + case R_X86_64_DTPMOD64: + case R_X86_64_DTPOFF64: + case R_X86_64_TPOFF64: + case R_X86_64_TLSGD: + case R_X86_64_TLSLD: + case R_X86_64_DTPOFF32: + case R_X86_64_GOTTPOFF: + case R_X86_64_TPOFF32: + default: + return error(pThis->pszSrc, "Unsupported fixup type %#x (%s) at rva=%#x in section #%u '%s' against '%s'\n", + uType, g_apszElfAmd64RelTypes[uType], paRelocs[iReloc].r_offset, i, pszSegNm, pszSymName); + } + + /* Add the fixup. */ + if (idxFrame == UINT16_MAX) + error(pThis->pszSrc, "idxFrame=UINT16_MAX for %s type=%s\n", pszSymName, g_apszElfAmd64RelTypes[uType]); + fRet = omfWriter_LEDataAddFixup(pThis, offDataRec, fSelfRel, bLocation, bFrame, idxFrame, + bTarget, idxTarget, fTargetDisp, offTargetDisp) && fRet; + } + + /* + * Write the LEDATA and associated FIXUPPs. + */ + if (!omfWriter_LEDataEnd(pThis)) + return false; + + /* + * Advance. + */ + paRelocs += cChunkRelocs; + cRelocs -= cChunkRelocs; + if (cbData > cbChunk) + { + cbData -= cbChunk; + pbData += cbChunk; + } + else + cbData = 0; + off += cbChunk; + cbVirtData -= cbChunk; + } + } + + return fRet; +} + + +static bool convertMachoToOmf(const char *pszFile, uint8_t const *pbFile, size_t cbFile, FILE *pDst) +{ + /* + * Validate the source file a little. + */ + MACHODETAILS MachOStuff; + if (!validateMachO(pszFile, pbFile, cbFile, &MachOStuff)) + return false; + + /* + * Instantiate the OMF writer. + */ + POMFWRITER pThis = omfWriter_Create(pszFile, MachOStuff.pEhdr->e_shnum, MachOStuff.cSymbols, pDst); + if (!pThis) + return false; + + /* + * Write the OMF object file. + */ + if (omfWriter_BeginModule(pThis, pszFile)) + { + Elf64_Ehdr const *pEhdr = (Elf64_Ehdr const *)pbFile; + + if ( convertMachOSectionsToSegDefsAndGrpDefs(pThis, &MachOStuff) + && convertMachOSymbolsToPubDefsAndExtDefs(pThis, &MachOStuff) + && omfWriter_LinkPassSeparator(pThis) + && convertMachOSectionsToLeDataAndFixupps(pThis, &MachOStuff, pbFile, cbFile) + && omfWriter_EndModule(pThis) ) + { + + omfWriter_Destroy(pThis); + return true; + } + } + + omfWriter_Destroy(pThis); + return false; +} + +#endif /* !MACHO_TO_OMF_CONVERSION */ + + +/********************************************************************************************************************************* +* OMF Converter/Tweaker * +*********************************************************************************************************************************/ + +/** Watcom intrinsics we need to modify so we can mix 32-bit and 16-bit + * code, since the 16 and 32 bit compilers share several names. + * The names are length prefixed. + */ +static const char * const g_apszExtDefRenames[] = +{ + "\x05" "__I4D", + "\x05" "__I4M", + "\x05" "__I8D", + "\x06" "__I8DQ", + "\x07" "__I8DQE", + "\x06" "__I8DR", + "\x07" "__I8DRE", + "\x06" "__I8LS", + "\x05" "__I8M", + "\x06" "__I8ME", + "\x06" "__I8RS", + "\x05" "__PIA", + "\x05" "__PIS", + "\x05" "__PTC", + "\x05" "__PTS", + "\x05" "__U4D", + "\x05" "__U4M", + "\x05" "__U8D", + "\x06" "__U8DQ", + "\x07" "__U8DQE", + "\x06" "__U8DR", + "\x07" "__U8DRE", + "\x06" "__U8LS", + "\x05" "__U8M", + "\x06" "__U8ME", + "\x06" "__U8RS", +}; + +/** + * Segment definition. + */ +typedef struct OMFSEGDEF +{ + uint32_t cbSeg; + uint8_t bSegAttr; + uint16_t idxName; + uint16_t idxClass; + uint16_t idxOverlay; + uint8_t cchName; + uint8_t cchClass; + uint8_t cchOverlay; + const char *pchName; + const char *pchClass; + const char *pchOverlay; + bool fUse32; + bool f32bitRec; +} OMFSEGDEF; +typedef OMFSEGDEF *POMFSEGDEF; + +/** + * Group definition. + */ +typedef struct OMFGRPDEF +{ + const char *pchName; + uint16_t idxName; + uint8_t cchName; + uint16_t cSegDefs; + uint16_t *paidxSegDefs; +} OMFGRPDEF; +typedef OMFGRPDEF *POMFGRPDEF; + +/** + * Records line number information for a file in a segment (for CV8 debug info). + */ +typedef struct OMFFILELINES +{ + /** The source info offset. */ + uint32_t offSrcInfo; + /** Number of line/offset pairs. */ + uint32_t cPairs; + /** Number of pairs allocated. */ + uint32_t cPairsAlloc; + /** Table with line number and offset pairs, ordered by offset. */ + PRTCV8LINEPAIR paPairs; +} OMFFILEINES; +typedef OMFFILEINES *POMFFILEINES; + +/** + * Records line number information for a segment (for CV8 debug info). + */ +typedef struct OMFSEGLINES +{ + /** Number of files. */ + uint32_t cFiles; + /** Number of bytes we need. */ + uint32_t cb; + /** The segment index. */ + uint16_t idxSeg; + /** The group index for this segment. Initially OMF_REPLACE_GRP_XXX values, + * later convertOmfWriteDebugGrpDefs replaces them with actual values. */ + uint16_t idxGrp; + /** File table. */ + POMFFILEINES paFiles; +} OMFSEGLINES; +typedef OMFSEGLINES *POMFSEGLINES; + +/** @name OMF_REPLACE_GRP_XXX - Special OMFSEGLINES::idxGrp values. + * @{ */ +#define OMF_REPLACE_GRP_CGROUP16 UINT16_C(0xffe0) +#define OMF_REPLACE_GRP_RMCODE UINT16_C(0xffe1) +#define OMF_REPLACE_GRP_X0CODE UINT16_C(0xffe2) +#define OMF_REPLACE_GRP_X1CODE UINT16_C(0xffe3) +/** @} */ + + +/** + * OMF details allocation that needs to be freed when done. + */ +typedef struct OMFDETAILSALLOC +{ + /** Pointer to the next allocation. */ + struct OMFDETAILSALLOC *pNext; + /** The allocated bytes. */ + uint8_t abData[RT_FLEXIBLE_ARRAY]; +} OMFDETAILSALLOC; +typedef OMFDETAILSALLOC *POMFDETAILSALLOC; + +/** + * OMF conversion details. + * + * Keeps information relevant to the conversion and CV8 debug info. + */ +typedef struct OMFDETAILS +{ + /** The input file name. */ + const char *pszFile; + + /** Set if it has line numbers. */ + bool fLineNumbers; + /** Set if we think this may be a 32-bit OMF file. */ + bool fProbably32bit; + /** Set if this module may need mangling. */ + bool fMayNeedMangling; + /** The LNAME index of '$$SYMBOLS' or UINT16_MAX it not found. */ + uint16_t iSymbolsNm; + /** The LNAME index of 'DEBSYM' or UINT16_MAX it not found. */ + uint16_t iDebSymNm; + /** The '$$SYMBOLS' segment index. */ + uint16_t iSymbolsSeg; + + /** Number of SEGDEFs records. */ + uint16_t cSegDefs; + /** Number of GRPDEFs records. */ + uint16_t cGrpDefs; + /** Number of listed names. */ + uint16_t cLNames; + + /** Segment defintions. */ + POMFSEGDEF paSegDefs; + /** Group defintions. */ + POMFGRPDEF paGrpDefs; + /** Name list. Points to the size repfix. */ + char **papchLNames; + + /** Code groups we need to keep an eye on for line number fixup purposes. */ + struct OMFLINEGROUPS + { + /** The name. */ + const char *pszName; + /** The primary class name. */ + const char *pszClass1; + /** The secondary class name. */ + const char *pszClass2; + /** The main segment name, NULL if not applicable (CGROUP16). */ + const char *pszSeg; + /** The name length. */ + uint8_t cchName; + /** The primary class name length. */ + uint8_t cchClass1; + /** The secondary class name length. */ + uint8_t cchClass2; + /** Whether this group is needed. */ + bool fNeeded; + /** The group index (UINT16_MAX if not found). */ + uint16_t idxGroup; + /** The group name. */ + uint16_t idxName; + /** The OMF_REPLACE_GRP_XXX value. */ + uint16_t idxReplaceGrp; + } aGroups[4]; + + /** CV8: Filename string table size. */ + uint32_t cbStrTab; + /** CV8: Filename string table allocation size (always multiple of dword, + * zero initialized). */ + uint32_t cbStrTabAlloc; + /** CV8: Filename String table. */ + char *pchStrTab; + /** CV8: Elements in the source info table. */ + uint16_t cSrcInfo; + /** CV8: Source info table. */ + PRTCV8SRCINFO paSrcInfo; + + /** Number of entries in the paSegLines table. */ + uint32_t cSegLines; + /** Segment line numbers, indexed by segment number. */ + POMFSEGLINES paSegLines; + + /** List of allocations that needs freeing. */ + POMFDETAILSALLOC pAllocHead; +} OMFDETAILS; +typedef OMFDETAILS *POMFDETAILS; +typedef OMFDETAILS const *PCOMFDETAILS; + + +/** Grows a table to a given size (a_cNewEntries). */ +#define OMF_GROW_TABLE_EX_RET_ERR(a_EntryType, a_paTable, a_cEntries, a_cNewEntries) \ + do\ + { \ + size_t cbOld = (a_cEntries) * sizeof(a_EntryType); \ + size_t cbNew = (a_cNewEntries) * sizeof(a_EntryType); \ + void *pvNew = realloc(a_paTable, cbNew); \ + if (pvNew) \ + { \ + memset((uint8_t *)pvNew + cbOld, 0, cbNew - cbOld); \ + (a_paTable) = (a_EntryType *)pvNew; \ + } \ + else return error("???", "Out of memory!\n"); \ + } while (0) + +/** Grows a table. */ +#define OMF_GROW_TABLE_RET_ERR(a_EntryType, a_paTable, a_cEntries, a_cEvery) \ + if ((a_cEntries) % (a_cEvery) != 0) { /* likely */ } \ + else do\ + { \ + size_t cbOld = (a_cEntries) * sizeof(a_EntryType); \ + size_t cbNew = cbOld + (a_cEvery) * sizeof(a_EntryType); \ + void *pvNew = realloc(a_paTable, cbNew); \ + if (pvNew) \ + { \ + memset((uint8_t *)pvNew + cbOld, 0, (a_cEvery) * sizeof(a_EntryType)); \ + (a_paTable) = (a_EntryType *)pvNew; \ + } \ + else return error("???", "Out of memory!\n"); \ + } while (0) + +#define OMF_EXPLODE_LNAME(a_pOmfStuff, a_idxName, a_pchName, a_cchName, a_Name) \ + do { \ + if ((a_idxName) < (a_pOmfStuff)->cLNames) \ + { \ + a_cchName = (uint8_t)*(a_pOmfStuff)->papchLNames[(a_idxName)]; \ + a_pchName = (a_pOmfStuff)->papchLNames[(a_idxName)] + 1; \ + } \ + else return error((a_pOmfStuff)->pszFile, "Invalid LNAME reference %#x in " #a_Name "!\n", a_idxName); \ + } while (0) + + +/** + * Allocates memory that will be freed when we're done converting. + * + * @returns Pointer tot he memory. + * @param pOmfStuff The OMF details data. + * @param cbNeeded The amount of memory required. + */ +static void *omfDetails_Alloc(POMFDETAILS pOmfStuff, size_t cbNeeded) +{ + POMFDETAILSALLOC pAlloc = (POMFDETAILSALLOC)malloc(RT_UOFFSETOF_DYN(OMFDETAILSALLOC, abData[cbNeeded])); + if (pAlloc) + { + pAlloc->pNext = pOmfStuff->pAllocHead; + pOmfStuff->pAllocHead = pAlloc; + return &pAlloc->abData[0]; + } + return NULL; +} + +/** + * Adds a line number to the CV8 debug info. + * + * @returns success indicator. + * @param pOmfStuff Where to collect CV8 debug info. + * @param cchSrcFile The length of the source file name. + * @param pchSrcFile The source file name, not terminated. + * @param poffFile Where to return the source file information table + * offset (for use in the line number tables). + */ +static bool collectOmfAddFile(POMFDETAILS pOmfStuff, uint8_t cchSrcFile, const char *pchSrcFile, uint32_t *poffFile) +{ + /* + * Do lookup first. + */ + uint32_t i = pOmfStuff->cSrcInfo; + while (i-- > 0) + { + const char *pszCur = &pOmfStuff->pchStrTab[pOmfStuff->paSrcInfo[i].offSourceName]; + if ( strncmp(pszCur, pchSrcFile, cchSrcFile) == 0 + && pszCur[cchSrcFile] == '\0') + { + *poffFile = i * sizeof(pOmfStuff->paSrcInfo[0]); + return true; + } + } + + /* + * Add it to the string table (dword aligned and zero padded). + */ + uint32_t offSrcTab = pOmfStuff->cbStrTab; + if (offSrcTab + cchSrcFile + 1 > pOmfStuff->cbStrTabAlloc) + { + uint32_t cbNew = (offSrcTab == 0) + offSrcTab + cchSrcFile + 1; + cbNew = RT_ALIGN(cbNew, 256); + void *pvNew = realloc(pOmfStuff->pchStrTab, cbNew); + if (!pvNew) + return error("???", "out of memory"); + pOmfStuff->pchStrTab = (char *)pvNew; + pOmfStuff->cbStrTabAlloc = cbNew; + memset(&pOmfStuff->pchStrTab[offSrcTab], 0, cbNew - offSrcTab); + + if (!offSrcTab) + offSrcTab++; + } + + memcpy(&pOmfStuff->pchStrTab[offSrcTab], pchSrcFile, cchSrcFile); + pOmfStuff->pchStrTab[offSrcTab + cchSrcFile] = '\0'; + pOmfStuff->cbStrTab = offSrcTab + cchSrcFile + 1; + + /* + * Add it to the filename info table. + */ + if ((pOmfStuff->cSrcInfo % 8) == 0) + { + void *pvNew = realloc(pOmfStuff->paSrcInfo, sizeof(pOmfStuff->paSrcInfo[0]) * (pOmfStuff->cSrcInfo + 8)); + if (!pvNew) + return error("???", "out of memory"); + pOmfStuff->paSrcInfo = (PRTCV8SRCINFO)pvNew; + } + + PRTCV8SRCINFO pSrcInfo = &pOmfStuff->paSrcInfo[pOmfStuff->cSrcInfo++]; + pSrcInfo->offSourceName = offSrcTab; + pSrcInfo->uDigestType = RTCV8SRCINFO_DIGEST_TYPE_MD5; + memset(&pSrcInfo->Digest, 0, sizeof(pSrcInfo->Digest)); + + *poffFile = (uint32_t)((uintptr_t)pSrcInfo - (uintptr_t)pOmfStuff->paSrcInfo); + return true; +} + + +/** + * Adds a line number to the CV8 debug info. + * + * @returns success indicator. + * @param pOmfStuff Where to collect CV8 debug info. + * @param idxSeg The segment index. + * @param off The segment offset. + * @param uLine The line number. + * @param offSrcInfo The source file info table offset. + */ +static bool collectOmfAddLine(POMFDETAILS pOmfStuff, uint16_t idxSeg, uint32_t off, uint16_t uLine, uint32_t offSrcInfo) +{ + /* + * Get/add the segment line structure. + */ + if (idxSeg >= pOmfStuff->cSegLines) + { + OMF_GROW_TABLE_EX_RET_ERR(OMFSEGLINES, pOmfStuff->paSegLines, pOmfStuff->cSegLines, idxSeg + 1); + for (uint32_t i = pOmfStuff->cSegLines; i <= idxSeg; i++) + { + pOmfStuff->paSegLines[i].idxSeg = i; + pOmfStuff->paSegLines[i].idxGrp = UINT16_MAX; + pOmfStuff->paSegLines[i].cb = sizeof(RTCV8LINESHDR); + } + pOmfStuff->cSegLines = idxSeg + 1; + } + POMFSEGLINES pSegLines = &pOmfStuff->paSegLines[idxSeg]; + + /* + * Get/add the file structure with the segment. + */ + POMFFILEINES pFileLines = NULL; + uint32_t i = pSegLines->cFiles; + while (i-- > 0) + if (pSegLines->paFiles[i].offSrcInfo == offSrcInfo) + { + pFileLines = &pSegLines->paFiles[i]; + break; + } + if (!pFileLines) + { + i = pSegLines->cFiles; + OMF_GROW_TABLE_RET_ERR(OMFFILEINES, pSegLines->paFiles, pSegLines->cFiles, 4); + pSegLines->cFiles = i + 1; + pSegLines->cb += sizeof(RTCV8LINESSRCMAP); + + pFileLines = &pSegLines->paFiles[i]; + pFileLines->offSrcInfo = offSrcInfo; + pFileLines->cPairs = 0; + pFileLines->cPairsAlloc = 0; + pFileLines->paPairs = NULL; + + /* + * Check for segment group requirements the first time a segment is used. + */ + if (i == 0) + { + if (idxSeg >= pOmfStuff->cSegDefs) + return error("???", "collectOmfAddLine: idxSeg=%#x is out of bounds (%#x)!\n", idxSeg, pOmfStuff->cSegDefs); + POMFSEGDEF pSegDef = &pOmfStuff->paSegDefs[idxSeg]; + unsigned j = RT_ELEMENTS(pOmfStuff->aGroups); + while (j-- > 0) + if ( ( pSegDef->cchClass == pOmfStuff->aGroups[j].cchClass1 + && memcmp(pSegDef->pchClass, pOmfStuff->aGroups[j].pszClass1, pSegDef->cchClass) == 0) + || ( pSegDef->cchClass == pOmfStuff->aGroups[j].cchClass2 + && memcmp(pSegDef->pchClass, pOmfStuff->aGroups[j].pszClass2, pSegDef->cchClass) == 0)) + { + pOmfStuff->aGroups[j].fNeeded = true; + pSegLines->idxGrp = pOmfStuff->aGroups[j].idxReplaceGrp; + break; + } + } + } + + /* + * Add the line number (sorted, duplicates removed). + */ + if (pFileLines->cPairs + 1 > pFileLines->cPairsAlloc) + { + void *pvNew = realloc(pFileLines->paPairs, (pFileLines->cPairsAlloc + 16) * sizeof(pFileLines->paPairs[0])); + if (!pvNew) + return error("???", "out of memory"); + pFileLines->paPairs = (PRTCV8LINEPAIR)pvNew; + pFileLines->cPairsAlloc += 16; + } + + i = pFileLines->cPairs; + while (i > 0 && ( off < pFileLines->paPairs[i - 1].offSection + || ( off == pFileLines->paPairs[i - 1].offSection + && uLine < pFileLines->paPairs[i - 1].uLineNumber)) ) + i--; + if ( i == pFileLines->cPairs + || off != pFileLines->paPairs[i].offSection + || uLine != pFileLines->paPairs[i].uLineNumber) + { + if (i < pFileLines->cPairs) + memmove(&pFileLines->paPairs[i + 1], &pFileLines->paPairs[i], + (pFileLines->cPairs - i) * sizeof(pFileLines->paPairs)); + pFileLines->paPairs[i].offSection = off; + pFileLines->paPairs[i].uLineNumber = uLine; + pFileLines->paPairs[i].fEndOfStatement = true; + pFileLines->cPairs++; + pSegLines->cb += sizeof(pFileLines->paPairs[0]); + } + + return true; +} + + +/** + * Parses OMF file gathering line numbers (for CV8 debug info) and checking out + * external defintions for mangling work (compiler instrinsics). + * + * @returns success indicator. + * @param pszFile The name of the OMF file. + * @param pbFile The file content. + * @param cbFile The size of the file content. + * @param pOmfStuff Where to collect CV8 debug info and anything else we + * find out about the OMF file. + */ +static bool collectOmfDetails(const char *pszFile, uint8_t const *pbFile, size_t cbFile, POMFDETAILS pOmfStuff) +{ + uint32_t cExtDefs = 0; + uint32_t cPubDefs = 0; + uint32_t off = 0; + uint8_t cchSrcFile = 0; + const char *pchSrcFile = NULL; + uint32_t offSrcInfo = UINT32_MAX; + + memset(pOmfStuff, 0, sizeof(*pOmfStuff)); + pOmfStuff->pszFile = pszFile; + pOmfStuff->iDebSymNm = UINT16_MAX; + pOmfStuff->iSymbolsNm = UINT16_MAX; + pOmfStuff->iSymbolsSeg = UINT16_MAX; + + /* Dummy entries. */ + OMF_GROW_TABLE_RET_ERR(char *, pOmfStuff->papchLNames, pOmfStuff->cLNames, 16); + pOmfStuff->papchLNames[0] = (char *)""; + pOmfStuff->cLNames = 1; + + OMF_GROW_TABLE_RET_ERR(OMFSEGDEF, pOmfStuff->paSegDefs, pOmfStuff->cSegDefs, 16); + pOmfStuff->cSegDefs = 1; + + OMF_GROW_TABLE_RET_ERR(OMFGRPDEF, pOmfStuff->paGrpDefs, pOmfStuff->cGrpDefs, 16); + pOmfStuff->cGrpDefs = 1; + + /* Groups we seek. */ +#define OMF_INIT_WANTED_GROUP(a_idx, a_szName, a_szClass1, a_szClass2, a_pszSeg, a_idxReplace) \ + pOmfStuff->aGroups[a_idx].pszName = a_szName; \ + pOmfStuff->aGroups[a_idx].cchName = sizeof(a_szName) - 1; \ + pOmfStuff->aGroups[a_idx].pszClass1 = a_szClass1; \ + pOmfStuff->aGroups[a_idx].cchClass1 = sizeof(a_szClass1) - 1; \ + pOmfStuff->aGroups[a_idx].pszClass2 = a_szClass2; \ + pOmfStuff->aGroups[a_idx].cchClass2 = sizeof(a_szClass2) - 1; \ + pOmfStuff->aGroups[a_idx].pszSeg = a_pszSeg; \ + pOmfStuff->aGroups[a_idx].fNeeded = false; \ + pOmfStuff->aGroups[a_idx].idxGroup = UINT16_MAX; \ + pOmfStuff->aGroups[a_idx].idxName = UINT16_MAX; \ + pOmfStuff->aGroups[a_idx].idxReplaceGrp = a_idxReplace + OMF_INIT_WANTED_GROUP(0, "CGROUP16", "BS3CLASS16CODE", "CODE", NULL, OMF_REPLACE_GRP_CGROUP16); + OMF_INIT_WANTED_GROUP(1, "BS3GROUPRMTEXT16", "BS3CLASS16RMCODE", "", "BS3RMTEXT16", OMF_REPLACE_GRP_RMCODE); + OMF_INIT_WANTED_GROUP(2, "BS3GROUPX0TEXT16", "BS3CLASS16X0CODE", "", "BS3X0TEXT16", OMF_REPLACE_GRP_X0CODE); + OMF_INIT_WANTED_GROUP(3, "BS3GROUPX1TEXT16", "BS3CLASS16X1CODE", "", "BS3X1TEXT16", OMF_REPLACE_GRP_X1CODE); + + /* + * Process the OMF records. + */ + while (off + 3 < cbFile) + { + uint8_t bRecType = pbFile[off]; + uint16_t cbRec = RT_MAKE_U16(pbFile[off + 1], pbFile[off + 2]); + if (g_cVerbose > 2) + printf( "%#07x: type=%#04x len=%#06x\n", off, bRecType, cbRec); + if (off + cbRec > cbFile) + return error(pszFile, "Invalid record length at %#x: %#x (cbFile=%#lx)\n", off, cbRec, (unsigned long)cbFile); + + uint32_t offRec = 0; + uint8_t const *pbRec = &pbFile[off + 3]; +#define OMF_CHECK_RET(a_cbReq, a_Name) /* Not taking the checksum into account, so we're good with 1 or 2 byte fields. */ \ + if (offRec + (a_cbReq) <= cbRec) {/*likely*/} \ + else return error(pszFile, "Malformed " #a_Name "! off=%#x offRec=%#x cbRec=%#x cbNeeded=%#x line=%d\n", \ + off, offRec, cbRec, (a_cbReq), __LINE__) +#define OMF_READ_IDX(a_idx, a_Name) \ + do { \ + OMF_CHECK_RET(2, a_Name); \ + a_idx = pbRec[offRec++]; \ + if ((a_idx) & 0x80) \ + a_idx = (((a_idx) & 0x7f) << 8) | pbRec[offRec++]; \ + } while (0) + +#define OMF_READ_U16(a_u16, a_Name) \ + do { \ + OMF_CHECK_RET(4, a_Name); \ + a_u16 = RT_MAKE_U16(pbRec[offRec], pbRec[offRec + 1]); \ + offRec += 2; \ + } while (0) +#define OMF_READ_U32(a_u32, a_Name) \ + do { \ + OMF_CHECK_RET(4, a_Name); \ + a_u32 = RT_MAKE_U32_FROM_U8(pbRec[offRec], pbRec[offRec + 1], pbRec[offRec + 2], pbRec[offRec + 3]); \ + offRec += 4; \ + } while (0) + + switch (bRecType) + { + /* + * Record LNAME records, scanning for FLAT. + */ + case OMF_LNAMES: + while (offRec + 1 < cbRec) + { + uint8_t cch = pbRec[offRec]; + if (offRec + 1 + cch >= cbRec) + return error(pszFile, "Invalid LNAME string length at %#x+3+%#x: %#x (cbFile=%#lx)\n", + off, offRec, cch, (unsigned long)cbFile); + + if (g_cVerbose > 2) + printf(" LNAME[%u]: %-*.*s\n", pOmfStuff->cLNames, cch, cch, &pbRec[offRec + 1]); + + OMF_GROW_TABLE_RET_ERR(char *, pOmfStuff->papchLNames, pOmfStuff->cLNames, 16); + pOmfStuff->papchLNames[pOmfStuff->cLNames] = (char *)&pbRec[offRec]; + + if (IS_OMF_STR_EQUAL_EX(cch, &pbRec[offRec + 1], "FLAT")) + pOmfStuff->fProbably32bit = true; + + if (IS_OMF_STR_EQUAL_EX(cch, &pbRec[offRec + 1], "DEBSYM")) + pOmfStuff->iDebSymNm = pOmfStuff->cLNames; + if (IS_OMF_STR_EQUAL_EX(cch, &pbRec[offRec + 1], "$$SYMBOLS")) + pOmfStuff->iSymbolsNm = pOmfStuff->cLNames; + + unsigned j = RT_ELEMENTS(pOmfStuff->aGroups); + while (j-- > 0) + if ( cch == pOmfStuff->aGroups[j].cchName + && memcmp(&pbRec[offRec + 1], pOmfStuff->aGroups[j].pszName, pOmfStuff->aGroups[j].cchName) == 0) + { + pOmfStuff->aGroups[j].idxName = pOmfStuff->cLNames; + break; + } + + pOmfStuff->cLNames++; + offRec += cch + 1; + } + break; + + /* + * Display external definitions if -v is specified, also check if anything needs mangling. + */ + case OMF_EXTDEF: + while (offRec + 1 < cbRec) + { + uint8_t cch = pbRec[offRec++]; + OMF_CHECK_RET(cch, EXTDEF); + char *pchName = (char *)&pbRec[offRec]; + offRec += cch; + + uint16_t idxType; + OMF_READ_IDX(idxType, EXTDEF); + + if (g_cVerbose > 2) + printf(" EXTDEF [%u]: %-*.*s type=%#x\n", cExtDefs, cch, cch, pchName, idxType); + else if (g_cVerbose > 0) + printf(" U %-*.*s\n", cch, cch, pchName); + + /* Look for g_apszExtDefRenames entries that requires changing. */ + if ( !pOmfStuff->fMayNeedMangling + && cch >= 5 + && cch <= 7 + && pchName[0] == '_' + && pchName[1] == '_' + && ( pchName[2] == 'U' + || pchName[2] == 'I' + || pchName[2] == 'P') + && ( pchName[3] == '4' + || pchName[3] == '8' + || pchName[3] == 'I' + || pchName[3] == 'T') ) + { + pOmfStuff->fMayNeedMangling = true; + } + } + break; + + /* + * Display public names if -v is specified. + */ + case OMF_PUBDEF32: + case OMF_LPUBDEF32: + pOmfStuff->fProbably32bit = true; + RT_FALL_THRU(); + case OMF_PUBDEF16: + case OMF_LPUBDEF16: + if (g_cVerbose > 0) + { + char const chType = bRecType == OMF_PUBDEF16 || bRecType == OMF_PUBDEF32 ? 'T' : 't'; + const char *pszRec = "LPUBDEF"; + if (chType == 'T') + pszRec++; + + uint16_t idxGrp; + OMF_READ_IDX(idxGrp, [L]PUBDEF); + + uint16_t idxSeg; + OMF_READ_IDX(idxSeg, [L]PUBDEF); + + uint16_t uFrameBase = 0; + if (idxSeg == 0) + { + OMF_CHECK_RET(2, [L]PUBDEF); + uFrameBase = RT_MAKE_U16(pbRec[offRec], pbRec[offRec + 1]); + offRec += 2; + } + if (g_cVerbose > 2) + printf(" %s: idxGrp=%#x idxSeg=%#x uFrameBase=%#x\n", pszRec, idxGrp, idxSeg, uFrameBase); + uint16_t const uSeg = idxSeg ? idxSeg : uFrameBase; + + while (offRec + 1 < cbRec) + { + uint8_t cch = pbRec[offRec++]; + OMF_CHECK_RET(cch, [L]PUBDEF); + const char *pchName = (const char *)&pbRec[offRec]; + offRec += cch; + + uint32_t offSeg; + if (bRecType & OMF_REC32) + { + OMF_CHECK_RET(4, [L]PUBDEF); + offSeg = RT_MAKE_U32_FROM_U8(pbRec[offRec], pbRec[offRec + 1], pbRec[offRec + 2], pbRec[offRec + 3]); + offRec += 4; + } + else + { + OMF_CHECK_RET(2, [L]PUBDEF); + offSeg = RT_MAKE_U16(pbRec[offRec], pbRec[offRec + 1]); + offRec += 2; + } + + uint16_t idxType; + OMF_READ_IDX(idxType, [L]PUBDEF); + + if (g_cVerbose > 2) + printf(" %s[%u]: off=%#010x type=%#x %-*.*s\n", pszRec, cPubDefs, offSeg, idxType, cch, cch, pchName); + else if (g_cVerbose > 0) + printf("%04x:%08x %c %-*.*s\n", uSeg, offSeg, chType, cch, cch, pchName); + } + } + break; + + /* + * Must count segment definitions to figure the index of our segment. + */ + case OMF_SEGDEF16: + case OMF_SEGDEF32: + { + OMF_GROW_TABLE_RET_ERR(OMFSEGDEF, pOmfStuff->paSegDefs, pOmfStuff->cSegDefs, 16); + POMFSEGDEF pSegDef = &pOmfStuff->paSegDefs[pOmfStuff->cSegDefs++]; + + OMF_CHECK_RET(1 + (bRecType == OMF_SEGDEF16 ? 2 : 4) + 1 + 1 + 1, SEGDEF); + pSegDef->f32bitRec = bRecType == OMF_SEGDEF32; + pSegDef->bSegAttr = pbRec[offRec++]; + pSegDef->fUse32 = pSegDef->bSegAttr & 1; + if ((pSegDef->bSegAttr >> 5) == 0) + { + /* A=0: skip frame number of offset. */ + OMF_CHECK_RET(3, SEGDEF); + offRec += 3; + } + if (bRecType == OMF_SEGDEF16) + OMF_READ_U16(pSegDef->cbSeg, SEGDEF16); + else + OMF_READ_U32(pSegDef->cbSeg, SEGDEF32); + OMF_READ_IDX(pSegDef->idxName, SEGDEF); + OMF_READ_IDX(pSegDef->idxClass, SEGDEF); + OMF_READ_IDX(pSegDef->idxOverlay, SEGDEF); + OMF_EXPLODE_LNAME(pOmfStuff, pSegDef->idxName, pSegDef->pchName, pSegDef->cchName, SEGDEF); + OMF_EXPLODE_LNAME(pOmfStuff, pSegDef->idxClass, pSegDef->pchClass, pSegDef->cchClass, SEGDEF); + OMF_EXPLODE_LNAME(pOmfStuff, pSegDef->idxOverlay, pSegDef->pchOverlay, pSegDef->cchOverlay, SEGDEF); + break; + } + + /* + * Must count segment definitions to figure the index of our group. + */ + case OMF_GRPDEF: + { + OMF_GROW_TABLE_RET_ERR(OMFGRPDEF, pOmfStuff->paGrpDefs, pOmfStuff->cGrpDefs, 8); + POMFGRPDEF pGrpDef = &pOmfStuff->paGrpDefs[pOmfStuff->cGrpDefs]; + + OMF_READ_IDX(pGrpDef->idxName, GRPDEF); + OMF_EXPLODE_LNAME(pOmfStuff, pGrpDef->idxName, pGrpDef->pchName, pGrpDef->cchName, GRPDEF); + + unsigned j = RT_ELEMENTS(pOmfStuff->aGroups); + while (j-- > 0) + if (pGrpDef->idxName == pOmfStuff->aGroups[j].idxName) + { + pOmfStuff->aGroups[j].idxGroup = pOmfStuff->cGrpDefs; + break; + } + + pGrpDef->cSegDefs = 0; + pGrpDef->paidxSegDefs = NULL; + while (offRec + 2 + 1 <= cbRec) + { + if (pbRec[offRec] != 0xff) + return error(pszFile, "Unsupported GRPDEF member type: %#x\n", pbRec[offRec]); + offRec++; + OMF_GROW_TABLE_RET_ERR(uint16_t, pGrpDef->paidxSegDefs, pGrpDef->cSegDefs, 16); + OMF_READ_IDX(pGrpDef->paidxSegDefs[pGrpDef->cSegDefs], GRPDEF); + pGrpDef->cSegDefs++; + } + pOmfStuff->cGrpDefs++; + break; + } + + /* + * Gather file names. + */ + case OMF_THEADR: /* watcom */ + cchSrcFile = pbRec[offRec++]; + OMF_CHECK_RET(cchSrcFile, OMF_THEADR); + pchSrcFile = (const char *)&pbRec[offRec]; + if (!collectOmfAddFile(pOmfStuff, cchSrcFile, pchSrcFile, &offSrcInfo)) + return false; + break; + + case OMF_COMENT: + { + OMF_CHECK_RET(2, COMENT); + offRec++; /* skip the type (flags) */ + uint8_t bClass = pbRec[offRec++]; + if (bClass == OMF_CCLS_BORLAND_SRC_FILE) /* nasm */ + { + OMF_CHECK_RET(1+1+4, BORLAND_SRC_FILE); + offRec++; /* skip unknown byte */ + cchSrcFile = pbRec[offRec++]; + OMF_CHECK_RET(cchSrcFile + 4, BORLAND_SRC_FILE); + pchSrcFile = (const char *)&pbRec[offRec]; + offRec += cchSrcFile; + if (offRec + 4 + 1 != cbRec) + return error(pszFile, "BAD BORLAND_SRC_FILE record at %#x: %d bytes left\n", + off, cbRec - offRec - 4 - 1); + if (!collectOmfAddFile(pOmfStuff, cchSrcFile, pchSrcFile, &offSrcInfo)) + return false; + break; + } + break; + } + + /* + * Line number conversion. + */ + case OMF_LINNUM16: + case OMF_LINNUM32: + { + uint16_t idxGrp; + OMF_READ_IDX(idxGrp, LINNUM); + uint16_t idxSeg; + OMF_READ_IDX(idxSeg, LINNUM); + + uint16_t iLine; + uint32_t offSeg; + if (bRecType == OMF_LINNUM16) + while (offRec + 4 < cbRec) + { + iLine = RT_MAKE_U16(pbRec[offRec + 0], pbRec[offRec + 1]); + offSeg = RT_MAKE_U16(pbRec[offRec + 2], pbRec[offRec + 3]); + if (!collectOmfAddLine(pOmfStuff, idxSeg, offSeg, iLine, offSrcInfo)) + return false; + offRec += 4; + } + else + while (offRec + 6 < cbRec) + { + iLine = RT_MAKE_U16(pbRec[offRec + 0], pbRec[offRec + 1]); + offSeg = RT_MAKE_U32_FROM_U8(pbRec[offRec + 2], pbRec[offRec + 3], pbRec[offRec + 4], pbRec[offRec + 5]); + if (!collectOmfAddLine(pOmfStuff, idxSeg, offSeg, iLine, offSrcInfo)) + return false; + offRec += 6; + } + if (offRec + 1 != cbRec) + return error(pszFile, "BAD LINNUM record at %#x: %d bytes left\n", off, cbRec - offRec - 1); + break; + } + } + + /* advance */ + off += cbRec + 3; + } + + return true; +#undef OMF_READ_IDX +#undef OMF_CHECK_RET +} + + +/** + * Adds a LNAMES entry (returns existing). + * + * @returns success indicator. + * @param pOmfStuff The OMF stuff. + * @param pszName The name to add. + * @param pidxName Where to return the name index. + */ +static bool omfDetails_AddLName(POMFDETAILS pOmfStuff, const char *pszName, uint16_t *pidxName) +{ + size_t const cchName = strlen(pszName); + + /* + * Check if we've already got the name. + */ + for (unsigned iName = 1; iName < pOmfStuff->cLNames; iName++) + if ( (unsigned char)pOmfStuff->papchLNames[iName][0] == cchName + && memcmp(pOmfStuff->papchLNames[iName] + 1, pszName, cchName) == 0) + { + *pidxName = iName; + return true; + } + + /* + * Not found, append it. + */ + char *pszCopy = (char *)omfDetails_Alloc(pOmfStuff, cchName + 2); + if (!pszCopy) + return false; + *(unsigned char *)&pszCopy[0] = (unsigned char)cchName; + memcpy(pszCopy + 1, pszName, cchName + 1); + + OMF_GROW_TABLE_RET_ERR(char *, pOmfStuff->papchLNames, pOmfStuff->cLNames, 16); + pOmfStuff->papchLNames[pOmfStuff->cLNames] = (char *)pszCopy; + *pidxName = pOmfStuff->cLNames; + pOmfStuff->cLNames++; + return true; +} + + +/** + * Adds a SEGDEF (always adds a new one). + * + * @returns success indicator. + * @param pOmfStuff The OMF stuff. + * @param bSegAttr The OMF segment attributes. + * @param cbSeg The segment size. + * @param idxSegName The LNAMES index of the segment name. + * @param idxSegClas The LNAMES index of the segment class. + * @param idxOverlay The LNAMES index of the overlay name; pass 1. + * @param fRec32 Set if SEGDEF32 should be emitted, clear for SEGDEF16. + * @param pidxSeg Where to return the segment index. + */ +static bool omfDetails_AddSegDef(POMFDETAILS pOmfStuff, uint8_t bSegAttr, uint32_t cbSeg, uint16_t idxSegName, + uint16_t idxSegClass, uint16_t idxOverlay, bool fRec32, uint16_t *pidxSeg) +{ + Assert(cbSeg <= UINT16_MAX || fRec32); + Assert(idxSegName < pOmfStuff->cLNames); + Assert(idxSegClass < pOmfStuff->cLNames); + + OMF_GROW_TABLE_RET_ERR(OMFSEGDEF, pOmfStuff->paSegDefs, pOmfStuff->cSegDefs, 16); + POMFSEGDEF pSegDef = &pOmfStuff->paSegDefs[pOmfStuff->cSegDefs]; + + pSegDef->bSegAttr = bSegAttr; + pSegDef->fUse32 = bSegAttr & 1; + pSegDef->f32bitRec = fRec32; + pSegDef->cbSeg = cbSeg; + pSegDef->idxName = idxSegName; + pSegDef->idxClass = idxSegClass; + pSegDef->idxOverlay = idxOverlay; + + OMF_EXPLODE_LNAME(pOmfStuff, pSegDef->idxName, pSegDef->pchName, pSegDef->cchName, SEGDEF); + OMF_EXPLODE_LNAME(pOmfStuff, pSegDef->idxClass, pSegDef->pchClass, pSegDef->cchClass, SEGDEF); + OMF_EXPLODE_LNAME(pOmfStuff, pSegDef->idxOverlay, pSegDef->pchOverlay, pSegDef->cchOverlay, SEGDEF); + + *pidxSeg = pOmfStuff->cSegDefs; + pOmfStuff->cSegDefs++; + return true; +} + + +/** + * Adds a SEGDEF if not found. + * + * @returns success indicator. + * @param pOmfStuff The OMF stuff. + * @param bSegAttr The OMF segment attributes. + * @param cbSeg The segment size. + * @param idxSegName The LNAMES index of the segment name. + * @param idxSegClas The LNAMES index of the segment class. + * @param idxOverlay The LNAMES index of the overlay name; pass 1. + * @param fRec32 Set if SEGDEF32 should be emitted, clear for SEGDEF16. + * @param pidxSeg Where to return the segment index. + */ +static bool omfDetails_AddSegDefIfNeeded(POMFDETAILS pOmfStuff, uint8_t bSegAttr, uint32_t cbSeg, uint16_t idxSegName, + uint16_t idxSegClass, uint16_t idxOverlay, bool fRec32, uint16_t *pidxSeg) +{ + /* Search for name */ + for (unsigned iSegDef = 1; iSegDef < pOmfStuff->cSegDefs; iSegDef++) + { + POMFSEGDEF pSegDef = &pOmfStuff->paSegDefs[iSegDef]; + if (pSegDef->idxName == idxSegName) + { + if ( pSegDef->bSegAttr != bSegAttr + || pSegDef->f32bitRec != fRec32 + || pSegDef->idxName != idxSegName + || pSegDef->idxClass != idxSegClass + || pSegDef->idxOverlay != idxOverlay) + return error(pOmfStuff->pszFile, + "Existing SEGDEF differs: bSegAttr=%#x vs %#x, f32bitRec=%d vs %d, idxName=%#x vs %#x, idxClass=%#x vs %#x, idxOverlay=%#x vs %#x\n", + pSegDef->bSegAttr, bSegAttr, + pSegDef->f32bitRec, fRec32, + pSegDef->idxName, idxSegName, + pSegDef->idxClass, idxSegClass, + pSegDef->idxOverlay, idxOverlay); + *pidxSeg = iSegDef; + return true; + } + } + return omfDetails_AddSegDef(pOmfStuff, bSegAttr, cbSeg, idxSegName, idxSegClass, idxOverlay, fRec32, pidxSeg); +} + + +#if 0 /* unused */ +/** + * Looks up a GRPDEF in the . + * + * @returns Index (0..32K) if found, UINT16_MAX if not found. + * @param pOmfStuff The OMF stuff. + * @param pchName The name to look up. + * @param cchName The length of the name. + */ +static uint16_t omfDetails_GrpDefLookupN(POMFDETAILS pOmfStuff, const char *pchName, size_t cchName) +{ + unsigned iGrpDef = pOmfStuff->cGrpDefs; + while (iGrpDef-- > 0) + { + if ( pOmfStuff->paGrpDefs[iGrpDef].cchName == cchName + && memcmp(pOmfStuff->paGrpDefs[iGrpDef].pchName, pchName, cchName) == 0) + return iGrpDef; + } + return UINT16_MAX; +} +#endif + + +/** + * Adds an empty GRPDEF (always adds a new one). + * + * @returns success indicator. + * @param pOmfStuff The OMF stuff. + * @param idxGrpName The LNAMES index of the group name. + * @param pidxGrp Where to return the group index. + */ +static bool omfDetails_AddGrpDef(POMFDETAILS pOmfStuff, uint16_t idxGrpName, uint16_t *pidxGrp) +{ + Assert(idxGrpName < pOmfStuff->cLNames); + + OMF_GROW_TABLE_RET_ERR(OMFGRPDEF, pOmfStuff->paGrpDefs, pOmfStuff->cGrpDefs, 8); + POMFGRPDEF pGrpDef = &pOmfStuff->paGrpDefs[pOmfStuff->cGrpDefs]; + + pGrpDef->idxName = idxGrpName; + pGrpDef->cSegDefs = 0; + pGrpDef->paidxSegDefs = NULL; + + *pidxGrp = pOmfStuff->cGrpDefs; + pOmfStuff->cGrpDefs++; + return true; +} + + +/** + * Adds a segment to an existing GRPDEF. + * + * @returns success indicator. + * @param pOmfStuff The OMF stuff. + * @param idxGrp The GRPDEF index of the group to append a member to. + * @param idxSeg The SEGDEF index of the segment name. + */ +static bool omfDetails_AddSegToGrpDef(POMFDETAILS pOmfStuff, uint16_t idxGrp, uint16_t idxSeg) +{ + Assert(idxGrp < pOmfStuff->cGrpDefs && idxGrp > 0); + Assert(idxSeg < pOmfStuff->cSegDefs && idxSeg > 0); + + POMFGRPDEF pGrpDef = &pOmfStuff->paGrpDefs[idxGrp]; + OMF_GROW_TABLE_RET_ERR(uint16_t, pGrpDef->paidxSegDefs, pGrpDef->cSegDefs, 16); + pGrpDef->paidxSegDefs[pGrpDef->cSegDefs] = idxSeg; + pGrpDef->cSegDefs++; + + return true; +} + + +/** + * Marks 16-bit code segment groups that is used in the object file as needed. + * + * @param pOmfStuff The OMF stuff. + */ +static void convertOmfLookForNeededGroups(POMFDETAILS pOmfStuff) +{ + /* + * Consult the groups in question. We mark the groups which segments are + * included in the segment definitions as needed. + */ + unsigned i = RT_ELEMENTS(pOmfStuff->aGroups); + while (i-- > 0) + if (pOmfStuff->aGroups[i].pszSeg) + { + const char * const pszSegNm = pOmfStuff->aGroups[i].pszSeg; + size_t const cchSegNm = strlen(pszSegNm); + for (unsigned iSegDef = 0; iSegDef < pOmfStuff->cSegDefs; iSegDef++) + if ( pOmfStuff->paSegDefs[iSegDef].cchName == cchSegNm + && memcmp(pOmfStuff->paSegDefs[iSegDef].pchName, pszSegNm, cchSegNm) == 0) + { + pOmfStuff->aGroups[i].fNeeded = true; + break; + } + } +} + + +/** + * Adds necessary group and segment definitions. + * + * @returns success indicator. + * @param pOmfStuff The OMF stuff. + */ +static bool convertOmfAddNeededGrpDefs(POMFDETAILS pOmfStuff) +{ + /* + * Process the groups. + */ + unsigned j = RT_ELEMENTS(pOmfStuff->aGroups); + while (j-- > 0) + if (pOmfStuff->aGroups[j].fNeeded) + { + if (pOmfStuff->aGroups[j].idxName == UINT16_MAX) + { + Assert(pOmfStuff->aGroups[j].idxGroup == UINT16_MAX); + if (!omfDetails_AddLName(pOmfStuff, pOmfStuff->aGroups[j].pszName, &pOmfStuff->aGroups[j].idxName)) + return false; + } + if (pOmfStuff->aGroups[j].idxGroup == UINT16_MAX) + { + if (!omfDetails_AddGrpDef(pOmfStuff, pOmfStuff->aGroups[j].idxName, &pOmfStuff->aGroups[j].idxGroup)) + return false; + + if (pOmfStuff->aGroups[j].pszSeg) + { + /* We need the segment class name. */ + uint16_t idxSegClass; + if (!omfDetails_AddLName(pOmfStuff, pOmfStuff->aGroups[j].pszClass1, &idxSegClass)) + return false; + + /* Prep segment name buffer. */ + size_t cchSegNm = strlen(pOmfStuff->aGroups[j].pszSeg); + char szSegNm[256+16]; + Assert(cchSegNm < 256); + memcpy(szSegNm, pOmfStuff->aGroups[j].pszSeg, cchSegNm); + + /* Add the three segments. */ + static RTSTRTUPLE const s_aSuffixes[3] = { {RT_STR_TUPLE("_START")}, {RT_STR_TUPLE("")}, {RT_STR_TUPLE("_END")}, }; + for (unsigned iSuffix = 0; iSuffix < RT_ELEMENTS(s_aSuffixes); iSuffix++) + { + uint16_t idxSegNm; + memcpy(&szSegNm[cchSegNm], s_aSuffixes[iSuffix].psz, s_aSuffixes[iSuffix].cch + 1); + if (!omfDetails_AddLName(pOmfStuff, szSegNm, &idxSegNm)) + return false; + uint8_t const fAlign = iSuffix == 1 ? OMF_SEG_ATTR_ALIGN_BYTE : OMF_SEG_ATTR_ALIGN_PARA; + uint16_t idxSeg; + if (!omfDetails_AddSegDefIfNeeded(pOmfStuff, fAlign | OMF_SEG_ATTR_COMB_PUBLIC | OMF_SEG_ATTR_USE16, + 0, idxSegNm, idxSegClass, 1, false /*fRec*/, &idxSeg)) + return false; + if (!omfDetails_AddSegToGrpDef(pOmfStuff, pOmfStuff->aGroups[j].idxGroup, idxSeg)) + return false; + } + } + } + } + + /* + * Replace group references in the segment lines table. + */ + j = RT_ELEMENTS(pOmfStuff->aGroups); + while (j-- > 0) + if (pOmfStuff->aGroups[j].fNeeded) + for (unsigned i = 0; i < pOmfStuff->cSegLines; i++) + if (pOmfStuff->paSegLines[i].idxGrp == pOmfStuff->aGroups[j].idxReplaceGrp) + pOmfStuff->paSegLines[i].idxGrp = pOmfStuff->aGroups[j].idxGroup; + return true; +} + + +/** + * Adds the debug segment definitions (names too) to the OMF state. + * + * @returns success indicator. + * @param pOmfStuff The OMF stuff with CV8 line number info. + */ +static bool convertOmfAddDebugSegDefs(POMFDETAILS pOmfStuff) +{ + if ( pOmfStuff->cSegLines == 0 + || pOmfStuff->iSymbolsSeg != UINT16_MAX) + return true; + + /* + * Add the names we need. + */ + if ( pOmfStuff->iSymbolsNm == UINT16_MAX + && !omfDetails_AddLName(pOmfStuff, "$$SYMBOLS", &pOmfStuff->iSymbolsNm)) + return false; + if ( pOmfStuff->iDebSymNm == UINT16_MAX + && !omfDetails_AddLName(pOmfStuff, "DEBSYM", &pOmfStuff->iDebSymNm)) + return false; + + /* + * Add the segment definition. + */ + uint8_t bSegAttr = 0; + bSegAttr |= 5 << 5; /* A: dword alignment */ + bSegAttr |= 0 << 2; /* C: private */ + bSegAttr |= 0 << 1; /* B: not big */ + bSegAttr |= 1; /* D: use32 */ + + /* calc the segment size. */ + uint32_t cbSeg = 4; /* dword 4 */ + cbSeg += 4 + 4 + RT_ALIGN_32(pOmfStuff->cbStrTab, 4); + cbSeg += 4 + 4 + pOmfStuff->cSrcInfo * sizeof(pOmfStuff->paSrcInfo[0]); + uint32_t i = pOmfStuff->cSegLines; + while (i-- > 0) + if (pOmfStuff->paSegLines[i].cFiles > 0) + cbSeg += 4 + 4 + pOmfStuff->paSegLines[i].cb; + return omfDetails_AddSegDef(pOmfStuff, bSegAttr, cbSeg, pOmfStuff->iSymbolsNm, pOmfStuff->iDebSymNm, 1 /*idxOverlay*/, + true /*fRec32*/, &pOmfStuff->iSymbolsSeg); +} + + +/** + * Writes the debug segment data. + * + * @returns success indicator. + * @param pThis The OMF writer. + * @param pOmfStuff The OMF stuff with CV8 line number info. + */ +static bool convertOmfWriteDebugData(POMFWRITER pThis, POMFDETAILS pOmfStuff) +{ + if (pOmfStuff->cSegLines == 0) + return true; + Assert(pOmfStuff->iSymbolsSeg != UINT16_MAX); + + /* Begin and write the CV version signature. */ + if ( !omfWriter_LEDataBegin(pThis, pOmfStuff->iSymbolsSeg, 0) + || !omfWriter_LEDataAddU32(pThis, RTCVSYMBOLS_SIGNATURE_CV8)) + return false; + + /* + * Emit the string table (no fixups). + */ + uint32_t cbLeft = pOmfStuff->cbStrTab; + if ( !omfWriter_LEDataAddU32(pThis, RTCV8SYMBLOCK_TYPE_SRC_STR) + || !omfWriter_LEDataAddU32(pThis, cbLeft) + || !omfWriter_LEDataAddBytes(pThis, pOmfStuff->pchStrTab, RT_ALIGN_32(cbLeft, 4)) ) /* table is zero padded to nearest dword */ + return false; + + /* + * Emit the source file info table (no fixups). + */ + cbLeft = pOmfStuff->cSrcInfo * sizeof(pOmfStuff->paSrcInfo[0]); + if ( !omfWriter_LEDataAddU32(pThis, RTCV8SYMBLOCK_TYPE_SRC_INFO) + || !omfWriter_LEDataAddU32(pThis, cbLeft) + || !omfWriter_LEDataAddBytes(pThis, pOmfStuff->paSrcInfo, cbLeft) ) + return false; + + /* + * Emit the segment line numbers. There are two fixups here at the start + * of each chunk. + */ + POMFSEGLINES pSegLines = pOmfStuff->paSegLines; + uint32_t i = pOmfStuff->cSegLines; + while (i-- > 0) + { + if (pSegLines->cFiles) + { + /* Calc covered area. */ + uint32_t cbSectionCovered = 0; + uint32_t j = pSegLines->cFiles; + while (j-- > 0) + { + uint32_t offLast = pSegLines->paFiles[j].paPairs[pSegLines->paFiles[j].cPairs - 1].offSection; + if (offLast > cbSectionCovered) + offLast = cbSectionCovered; + } + + /* For simplicity and debuggability, just split the LEDATA here. */ + if ( !omfWriter_LEDataSplit(pThis) + || !omfWriter_LEDataAddU32(pThis, RTCV8SYMBLOCK_TYPE_SECT_LINES) + || !omfWriter_LEDataAddU32(pThis, pSegLines->cb) + || !omfWriter_LEDataAddU32(pThis, 0) /*RTCV8LINESHDR::offSection*/ + || !omfWriter_LEDataAddU16(pThis, 0) /*RTCV8LINESHDR::iSection*/ + || !omfWriter_LEDataAddU16(pThis, 0) /*RTCV8LINESHDR::u16Padding*/ + || !omfWriter_LEDataAddU32(pThis, cbSectionCovered) /*RTCV8LINESHDR::cbSectionCovered*/ ) + return false; + + /* Default to the segment (BS3TEXT32, BS3TEXT64) or the group (CGROUP16, + RMGROUP16, etc). The important thing is that we're framing the fixups + using a segment or group which ends up in the codeview segment map. */ + uint16_t idxFrame = pSegLines->idxSeg; + uint8_t bFrame = OMF_FIX_F_SEGDEF; + if (pSegLines->idxGrp != UINT16_MAX) + { + idxFrame = pSegLines->idxGrp; + bFrame = OMF_FIX_F_GRPDEF; + } + + /* Fixup #1: segment offset - IMAGE_REL_AMD64_SECREL. */ + if (!omfWriter_LEDataAddFixupNoDisp(pThis, 4 + 4 + RT_UOFFSETOF(RTCV8LINESHDR, offSection), OMF_FIX_LOC_32BIT_OFFSET, + bFrame, idxFrame, OMF_FIX_T_SEGDEF_NO_DISP, pSegLines->idxSeg)) + return false; + + + /* Fixup #2: segment number - IMAGE_REL_AMD64_SECTION. */ + if (!omfWriter_LEDataAddFixupNoDisp(pThis, 4 + 4 + RT_UOFFSETOF(RTCV8LINESHDR, iSection), OMF_FIX_LOC_16BIT_SEGMENT, + bFrame, idxFrame, OMF_FIX_T_SEGDEF_NO_DISP, pSegLines->idxSeg)) + return false; + + /* Emit data for each source file. */ + for (j = 0; j < pSegLines->cFiles; j++) + { + uint32_t const cbPairs = pSegLines->paFiles[j].cPairs * sizeof(RTCV8LINEPAIR); + if ( !omfWriter_LEDataAddU32(pThis, pSegLines->paFiles[j].offSrcInfo) /*RTCV8LINESSRCMAP::offSourceInfo*/ + || !omfWriter_LEDataAddU32(pThis, pSegLines->paFiles[j].cPairs) /*RTCV8LINESSRCMAP::cLines*/ + || !omfWriter_LEDataAddU32(pThis, cbPairs + sizeof(RTCV8LINESSRCMAP)) /*RTCV8LINESSRCMAP::cb*/ + || !omfWriter_LEDataAddBytes(pThis, pSegLines->paFiles[j].paPairs, cbPairs)) + return false; + } + } + pSegLines++; + } + + return omfWriter_LEDataEnd(pThis); +} + + +/** + * Writes out all the segment group definitions. + * + * @returns success indicator. + * @param pThis The OMF writer. + * @param pOmfStuff The OMF stuff containing the segment defs. + * @param pfFlushState Pointer to the flush state variable. + */ +static bool convertOmfWriteAllSegDefs(POMFWRITER pThis, POMFDETAILS pOmfStuff, int *pfFlushState) +{ + if (*pfFlushState > 0) + { + for (unsigned iSegDef = 1; iSegDef < pOmfStuff->cSegDefs; iSegDef++) + { + if (!(pOmfStuff->paSegDefs[iSegDef].f32bitRec + ? omfWriter_SegDef : omfWriter_SegDef16)(pThis, pOmfStuff->paSegDefs[iSegDef].bSegAttr, + pOmfStuff->paSegDefs[iSegDef].cbSeg, + pOmfStuff->paSegDefs[iSegDef].idxName, + pOmfStuff->paSegDefs[iSegDef].idxClass, + pOmfStuff->paSegDefs[iSegDef].idxOverlay)) + return false; + } + *pfFlushState = -1; + } + return true; +} + + +/** + * Writes out all the segment group definitions. + * + * @returns success indicator. + * @param pThis The OMF writer. + * @param pOmfStuff The OMF stuff containing the group defs. + * @param pfFlushState Pointer to the flush state variable. + */ +static bool convertOmfWriteAllGrpDefs(POMFWRITER pThis, POMFDETAILS pOmfStuff, int *pfFlushState) +{ + if (*pfFlushState > 0) + { + for (unsigned iGrpDef = 1; iGrpDef < pOmfStuff->cGrpDefs; iGrpDef++) + { + if (!omfWriter_GrpDefBegin(pThis, pOmfStuff->paGrpDefs[iGrpDef].idxName)) + return false; + for (unsigned iSegDef = 0; iSegDef < pOmfStuff->paGrpDefs[iGrpDef].cSegDefs; iSegDef++) + if (!omfWriter_GrpDefAddSegDef(pThis, pOmfStuff->paGrpDefs[iGrpDef].paidxSegDefs[iSegDef])) + return false; + if (!omfWriter_GrpDefEnd(pThis)) + return false; + } + *pfFlushState = -1; + } + return true; +} + + +/** + * This does the actual converting, passthru style. + * + * It only modifies, removes and inserts stuff it care about, the rest is passed + * thru as-is. + * + * @returns success indicator. + * @param pThis The OMF writer. + * @param pbFile The original file content. + * @param cbFile The size of the original file. + * @param pOmfStuff The OMF stuff we've gathered during the first pass, + * contains CV8 line number info if we converted anything. + * @param fConvertLineNumbers Whether we're converting line numbers and stuff. + */ +static bool convertOmfPassthru(POMFWRITER pThis, uint8_t const *pbFile, size_t cbFile, POMFDETAILS pOmfStuff, + bool fConvertLineNumbers) +{ + int fFlushLNames = 1; + int fFlushSegDefs = 1; + int fFlushGrpDefs = 1; + bool fSeenTheAdr = false; + bool fConvertFixupp = false; + + uint32_t off = 0; + while (off + 3 < cbFile) + { + uint8_t bRecType = pbFile[off]; + uint16_t cbRec = RT_MAKE_U16(pbFile[off + 1], pbFile[off + 2]); + uint32_t offRec = 0; + uint8_t const *pbRec = &pbFile[off + 3]; + +#define OMF_READ_IDX(a_idx, a_Name) \ + do { \ + a_idx = pbRec[offRec++]; \ + if ((a_idx) & 0x80) \ + a_idx = (((a_idx) & 0x7f) << 8) | pbRec[offRec++]; \ + } while (0) + +#define OMF_PEEK_IDX(a_idx, a_offRec) \ + do { \ + a_idx = pbRec[a_offRec]; \ + if ((a_idx) & 0x80) \ + a_idx = (((a_idx) & 0x7f) << 8) | pbRec[(a_offRec) + 1]; \ + } while (0) + + /* + * Remove/insert switch. will + */ + bool fSkip = false; + switch (bRecType) + { + /* + * Mangle watcom intrinsics if necessary. + */ + case OMF_EXTDEF: + if (pOmfStuff->fMayNeedMangling) + { + if (!omfWriter_ExtDefBegin(pThis)) + return false; + while (offRec + 1 < cbRec) + { + uint8_t cchName = pbRec[offRec++]; + char *pchName = (char *)&pbRec[offRec]; + offRec += cchName; + + uint16_t idxType; + OMF_READ_IDX(idxType, EXTDEF); + + /* Look for g_apszExtDefRenames entries that requires changing. */ + if ( cchName >= 5 + && cchName <= 7 + && pchName[0] == '_' + && pchName[1] == '_' + && ( pchName[2] == 'U' + || pchName[2] == 'I' + || pchName[2] == 'P') + && ( pchName[3] == '4' + || pchName[3] == '8' + || pchName[3] == 'I' + || pchName[3] == 'T') ) + { + char szName[12]; + memcpy(szName, pchName, cchName); + szName[cchName] = '\0'; + + uint32_t i = RT_ELEMENTS(g_apszExtDefRenames); + while (i-- > 0) + if ( cchName == (uint8_t)g_apszExtDefRenames[i][0] + && memcmp(&g_apszExtDefRenames[i][1], szName, cchName) == 0) + { + szName[0] = pOmfStuff->fProbably32bit ? '?' : '_'; + szName[1] = '?'; + break; + } + + if (!omfWriter_ExtDefAddN(pThis, szName, cchName, idxType, false /*fPrependUnderscore*/)) + return false; + } + else if (!omfWriter_ExtDefAddN(pThis, pchName, cchName, idxType, false /*fPrependUnderscore*/)) + return false; + } + if (!omfWriter_ExtDefEnd(pThis)) + return false; + fSkip = true; + } + break; + + /* + * Remove line number records. + */ + case OMF_LINNUM16: + case OMF_LINNUM32: + fSkip = fConvertLineNumbers; + break; + + /* + * Remove all but the first OMF_THEADR. + */ + case OMF_THEADR: + fSkip = fSeenTheAdr && fConvertLineNumbers; + fSeenTheAdr = true; + break; + + /* + * Remove borland source file changes. Also, make sure the group + * definitions are written out. + */ + case OMF_COMENT: + if (pbRec[1] == OMF_CCLS_LINK_PASS_SEP) + { + Assert(fFlushSegDefs <= 0); + if ( fFlushGrpDefs > 0 + && !convertOmfWriteAllGrpDefs(pThis, pOmfStuff, &fFlushGrpDefs)) + return false; + } + if (fConvertLineNumbers) + fSkip = pbRec[1] == OMF_CCLS_BORLAND_SRC_FILE; + break; + + /* + * Redo these so the OMF writer is on top of the index thing. + */ + case OMF_LNAMES: + if (fFlushLNames >= 0) + { + if (!omfWriter_LNamesBegin(pThis, false /*fAddZeroEntry*/)) + return false; + if (!fFlushLNames) + { + while (offRec + 1 < cbRec) + { + uint8_t cch = pbRec[offRec]; + const char *pch = (const char *)&pbRec[offRec + 1]; + if (!omfWriter_LNamesAddN(pThis, pch, cch, NULL)) + return false; + offRec += cch + 1; + } + } + else + { + /* Flush all LNAMES in one go. */ + for (unsigned i = 1; i < pOmfStuff->cLNames; i++) + if (!omfWriter_LNamesAddN(pThis, pOmfStuff->papchLNames[i] + 1, *pOmfStuff->papchLNames[i], NULL)) + return false; + fFlushLNames = -1; + } + if (!omfWriter_LNamesEnd(pThis)) + return false; + } + fSkip = true; + break; + + /* + * We may want to flush all the segments when we see the first one. + */ + case OMF_SEGDEF16: + case OMF_SEGDEF32: + fSkip = fFlushSegDefs != 0; + if (!convertOmfWriteAllSegDefs(pThis, pOmfStuff, &fFlushSegDefs)) + return false; + break; + + /* + * We may want to flush all the groups when we see the first one. + */ + case OMF_GRPDEF: + fSkip = fFlushGrpDefs != 0; + if (!convertOmfWriteAllGrpDefs(pThis, pOmfStuff, &fFlushGrpDefs)) + return false; + break; + + /* + * Hook LEDATA to flush groups and figure out when to convert FIXUPP records. + */ + case OMF_LEDATA16: + case OMF_LEDATA32: + if ( fFlushGrpDefs > 0 + && !convertOmfWriteAllGrpDefs(pThis, pOmfStuff, &fFlushGrpDefs)) + return false; + fConvertFixupp = false; +#if 0 + if ( g_f16BitWatcomC + && bRecType == OMF_LEDATA16) + { + /* Check if this is a code segment. */ + uint16_t idxSeg; + OMF_PEEK_IDX(idxSeg, offRec); + + } +#endif + break; + + + /* + * Convert fixups for 16-bit code segments to groups. + * Deals with switch table trouble. + */ + case OMF_FIXUPP16: + if (fConvertFixupp) + { + /* Gave up on this for now, easier to drop the eyecatcher in the _START segments. */ + } + break; + + /* + * Upon seeing MODEND we write out the debug info. + */ + case OMF_MODEND16: + case OMF_MODEND32: + if (fConvertLineNumbers) + if (!convertOmfWriteDebugData(pThis, pOmfStuff)) + return false; + break; + } + + /* + * Pass the record thru, if so was decided. + */ + if (!fSkip) + { + if ( omfWriter_RecBegin(pThis, bRecType) + && omfWriter_RecAddBytes(pThis, pbRec, cbRec) + && omfWriter_RecEnd(pThis, false)) + { /* likely */ } + else return false; + } + + /* advance */ + off += cbRec + 3; + } + + return true; +} + + +/** + * Converts LINNUMs and compiler intrinsics in an OMF object file. + * + * Wlink does a cheesy (to use their own term) job of generating the + * sstSrcModule subsection. It is limited to one file and cannot deal with line + * numbers in different segment. The latter is very annoying in assembly files + * that jumps between segments, these a frequent on crash stacks. + * + * The solution is to convert to the same line number tables that cl.exe /Z7 + * generates for our 64-bit C code, we named that format codeview v8, or CV8. + * Our code codeview debug info reader can deal with this already because of the + * 64-bit code, so Bob's your uncle. + * + * @returns success indicator. + * @param pszFile The name of the file being converted. + * @param pbFile The file content. + * @param cbFile The size of the file content. + * @param pDst The destiation (output) file. + */ +static bool convertOmfToOmf(const char *pszFile, uint8_t const *pbFile, size_t cbFile, FILE *pDst) +{ + bool const fConvertLineNumbers = true; + + /* + * Collect line number information, names, segment defintions, groups definitions and such. + */ + OMFDETAILS OmfStuff; + if (!collectOmfDetails(pszFile, pbFile, cbFile, &OmfStuff)) + return false; + + /* Mark groups for 16-bit code segments used by this object file as needed + so we can reframe fixups to these segments correctly. */ + convertOmfLookForNeededGroups(&OmfStuff); + + /* Add debug segments definitions. */ + bool fRc = true; + if (fConvertLineNumbers) + fRc = convertOmfAddDebugSegDefs(&OmfStuff); + + /* Add any additional group defintions we may need (for 16-bit code segs). */ + if (fRc) + fRc = convertOmfAddNeededGrpDefs(&OmfStuff); + if (fRc) + { + /* + * Instantiate the OMF writer and do pass-thru modifications. + */ + POMFWRITER pThis = omfWriter_Create(pszFile, 0, 0, pDst); + if (pThis) + { + fRc = convertOmfPassthru(pThis, pbFile, cbFile, &OmfStuff, fConvertLineNumbers); + omfWriter_Destroy(pThis); + } + else + fRc = false; + } + + /* + * Cleanup OmfStuff. + */ + uint32_t i = OmfStuff.cSegLines; + while (i-- >0) + { + uint32_t j = OmfStuff.paSegLines[i].cFiles; + while (j-- > 0) + free(OmfStuff.paSegLines[i].paFiles[j].paPairs); + free(OmfStuff.paSegLines[i].paFiles); + } + free(OmfStuff.paSegLines); + free(OmfStuff.paSrcInfo); + free(OmfStuff.pchStrTab); + + while (OmfStuff.pAllocHead) + { + POMFDETAILSALLOC pFreeMe = OmfStuff.pAllocHead; + OmfStuff.pAllocHead = OmfStuff.pAllocHead->pNext; + free(pFreeMe); + } + + return fRc; +} + + +/** + * Does the convertion using convertelf and convertcoff. + * + * @returns exit code (0 on success, non-zero on failure) + * @param pszFile The file to convert. + */ +static int convertit(const char *pszFile) +{ + /* Construct the filename for saving the unmodified file. */ + char szOrgFile[_4K]; + size_t cchFile = strlen(pszFile); + if (cchFile + sizeof(".original") > sizeof(szOrgFile)) + { + error(pszFile, "Filename too long!\n"); + return RTEXITCODE_FAILURE; + } + memcpy(szOrgFile, pszFile, cchFile); + memcpy(&szOrgFile[cchFile], ".original", sizeof(".original")); + + /* Read the whole file. */ + void *pvFile; + size_t cbFile; + if (readfile(pszFile, &pvFile, &cbFile)) + { + /* + * Do format conversions / adjustments. + */ + bool fRc = false; + uint8_t *pbFile = (uint8_t *)pvFile; + if ( cbFile > sizeof(Elf64_Ehdr) + && pbFile[0] == ELFMAG0 + && pbFile[1] == ELFMAG1 + && pbFile[2] == ELFMAG2 + && pbFile[3] == ELFMAG3) + { + if (writefile(szOrgFile, pvFile, cbFile)) + { + FILE *pDst = openfile(pszFile, true /*fWrite*/); + if (pDst) + { + fRc = convertElfToOmf(pszFile, pbFile, cbFile, pDst); + fRc = fclose(pDst) == 0 && fRc; + } + } + } + else if ( cbFile > sizeof(IMAGE_FILE_HEADER) + && RT_MAKE_U16(pbFile[0], pbFile[1]) == IMAGE_FILE_MACHINE_AMD64 + && RT_MAKE_U16(pbFile[2], pbFile[3]) * sizeof(IMAGE_SECTION_HEADER) + sizeof(IMAGE_FILE_HEADER) + < cbFile + && RT_MAKE_U16(pbFile[2], pbFile[3]) > 0) + { + if (writefile(szOrgFile, pvFile, cbFile)) + { + FILE *pDst = openfile(pszFile, true /*fWrite*/); + if (pDst) + { + fRc = convertCoffToOmf(pszFile, pbFile, cbFile, pDst); + fRc = fclose(pDst) == 0 && fRc; + } + } + } + else if ( cbFile >= 8 + && pbFile[0] == OMF_THEADR + && RT_MAKE_U16(pbFile[1], pbFile[2]) < cbFile) + { + if (writefile(szOrgFile, pvFile, cbFile)) + { + FILE *pDst = openfile(pszFile, true /*fWrite*/); + if (pDst) + { + fRc = convertOmfToOmf(pszFile, pbFile, cbFile, pDst); + fRc = fclose(pDst) == 0 && fRc; + } + } + } + else + fprintf(stderr, "error: Don't recognize format of '%s' (%#x %#x %#x %#x, cbFile=%lu)\n", + pszFile, pbFile[0], pbFile[1], pbFile[2], pbFile[3], (unsigned long)cbFile); + free(pvFile); + if (fRc) + return 0; + } + return 1; +} + + +int main(int argc, char **argv) +{ + int rcExit = 0; + + /* + * Scan the arguments. + */ + for (int i = 1; i < argc; i++) + { + if (argv[i][0] == '-') + { + const char *pszOpt = &argv[i][1]; + if (*pszOpt == '-') + { + /* Convert long options to short ones. */ + pszOpt--; + if (!strcmp(pszOpt, "--wcc")) + pszOpt = "w"; + else if (!strcmp(pszOpt, "--verbose")) + pszOpt = "v"; + else if (!strcmp(pszOpt, "--version")) + pszOpt = "V"; + else if (!strcmp(pszOpt, "--help")) + pszOpt = "h"; + else + { + fprintf(stderr, "syntax errro: Unknown options '%s'\n", pszOpt); + return 2; + } + } + + /* Process the list of short options. */ + while (*pszOpt) + { + switch (*pszOpt++) + { + case 'w': + g_f16BitWatcomC = true; + break; + + case 'v': + g_cVerbose++; + break; + + case 'V': + printf("%s\n", "$Revision: 127855 $"); + return 0; + + case '?': + case 'h': + printf("usage: %s [options] -o <output> <input1> [input2 ... [inputN]]\n", + argv[0]); + return 0; + } + } + } + else + { + /* + * File to convert. Do the job right away. + */ + rcExit = convertit(argv[i]); + if (rcExit != 0) + break; + } + } + + return rcExit; +} + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/asmdefs-first.mac b/src/VBox/ValidationKit/bootsectors/bs3kit/asmdefs-first.mac new file mode 100644 index 00000000..a0092701 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/asmdefs-first.mac @@ -0,0 +1,52 @@ +; $Id: asmdefs-first.mac $ +;; @file +; BS3Kit - Included by asmdefs.mac when assembling IPRT code. +; +; This will only be included if asmdefs.mac is included before bs3kit.mac, so +; it will not be used for bs3*.asm files, only IPRT ones. +; + +; +; Copyright (C) 2006-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + + +%ifndef ___asmdefs_first_mac +%define ___asmdefs_first_mac + +%include "bs3kit-template-header.mac" + +; +; Redefine some macros to suite us. +; +; We do near 16-bit code and produce far stubs separately as needed. +; +%define BEGINCODE TMPL_BEGIN_TEXT +%define BEGINPROC_EXPORTED BS3_BEGINPROC_EXPORTED_WRAPPER +%define ENDPROC BS3_PROC_END_CMN +%undef NAME +%define NAME(a) BS3_CMN_NM(a) + +%macro BS3_BEGINPROC_EXPORTED_WRAPPER 1 +BS3_PROC_BEGIN_CMN %1, BS3_PBC_NEAR +%endmacro + +%endif + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-bootsector.asm b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-bootsector.asm new file mode 100644 index 00000000..fd208ca6 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-bootsector.asm @@ -0,0 +1,396 @@ +; $Id: bs3-bootsector.asm $ +;; @file +; Generic bootsector for BS3. +; +; This sets up stack at %fff0 and loads the next sectors from the floppy at +; %10000 (1000:0000 in real mode), then starts executing at cs:ip=1000:0000. +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + + + +;********************************************************************************************************************************* +;* Header Files * +;********************************************************************************************************************************* +%include "bs3kit.mac" +%include "iprt/asmdefs.mac" +%include "iprt/x86.mac" + + +%ifdef __YASM__ +[map all] +%endif + +; +; Start with a jump just to follow the convention. +; Also declare all segments/sections to establish them and their order. +; + ORG 07c00h + +BITS 16 +CPU 8086 +start: + jmp short bs3InitCode + db 0ah ; Should be nop, but this looks better. +g_OemId: ; 003h + db 'BS3Kit', 0ah, 0ah + +; +; DOS 4.0 Extended Bios Parameter Block: +; +g_cBytesPerSector: ; 00bh + dw 512 +g_cSectorsPerCluster: ; 00dh + db 1 +g_cReservedSectors: ; 00eh + dw 1 +g_cFATs: ; 010h + db 0 +g_cRootDirEntries: ; 011h + dw 0 +g_cTotalSectors: ; 013h + dw 0 +g_bMediaDescriptor: ; 015h + db 0 +g_cSectorsPerFAT: ; 016h + dw 0 +g_cPhysSectorsPerTrack: ; 018h + dw 18 +g_cHeads: ; 01ah + dw 2 +g_cHiddentSectors: ; 01ch + dd 1 +g_cLargeTotalSectors: ; 020h - We (ab)use this to indicate the number of sectors to load. + dd 0 +g_bBootDrv: ; 024h + db 80h +g_bFlagsEtc: ; 025h + db 0 +g_bExtendedSignature: ; 026h + db 0x29 +g_dwSerialNumber: ; 027h + dd 0x0a458634 +g_abLabel: ; 02bh + db 'VirtualBox', 0ah +g_abFSType: ; 036h + db 'RawCode', 0ah +g_BpbEnd: ; 03ch + + +; +; Where to real init code starts. +; +bs3InitCode: + cli + + ; save the registers. + mov [cs:BS3_ADDR_REG_SAVE + BS3REGCTX.rax], ax + mov [cs:BS3_ADDR_REG_SAVE + BS3REGCTX.rsp], sp + mov [cs:BS3_ADDR_REG_SAVE + BS3REGCTX.ss], ss + mov [cs:BS3_ADDR_REG_SAVE + BS3REGCTX.ds], ds + + ; set up the segment reisters and stack. + mov ax, 0 + mov ds, ax + mov ss, ax + mov sp, BS3_ADDR_STACK + + ; Save more registers, without needing cs prefix. + mov [BS3_ADDR_REG_SAVE + BS3REGCTX.rcx], cx + mov [BS3_ADDR_REG_SAVE + BS3REGCTX.rdi], di + mov [BS3_ADDR_REG_SAVE + BS3REGCTX.es], es + mov [BS3_ADDR_REG_SAVE + BS3REGCTX.rbp], bp + + ; Load es and setup bp frame. + mov es, ax + mov bp, sp + mov [bp], ax ; clear the first 8 bytes (terminates the ebp chain) + mov [bp + 02h], ax + mov [bp + 04h], ax + mov [bp + 06h], ax + + ; Save flags now that we know that there's a valid stack. + pushf + + ; + ; Clear the register area. + ; + mov di, BS3_ADDR_REG_SAVE + mov cx, BS3REGCTX_size/2 + cld + rep stosw + + ; + ; Do basic CPU detection. + ; + + ; 1. bit 15-bit was fixed to 1 in pre-286 CPUs, and fixed to 0 in 286+. + mov ax, [bp - 2] + test ah, 080h ; always set on pre 286, clear on 286 and later + jnz .pre_80286 + + ; 2. On a 286 you cannot popf IOPL and NT from real mode. +.detect_286_or_386plus: +CPU 286 + mov ah, (X86_EFL_IOPL | X86_EFL_NT) >> 8 + push ax + popf + pushf + cmp ah, [bp - 3] + pop ax + je .is_386plus +.is_80286: +CPU 286 + smsw [BS3_ADDR_REG_SAVE + BS3REGCTX.cr0] +.pre_80286: +CPU 8086 + mov [BS3_ADDR_REG_SAVE + BS3REGCTX.rbx], bx + mov [BS3_ADDR_REG_SAVE + BS3REGCTX.rdx], dx + mov [BS3_ADDR_REG_SAVE + BS3REGCTX.rsi], si + jmp .do_load + + ; Save 386 registers. We can now skip the CS prefix as DS is flat. +CPU 386 +.is_386plus: + shr eax, 16 + mov [BS3_ADDR_REG_SAVE + BS3REGCTX.rax+2], ax + mov eax, esp + shr eax, 16 + mov [BS3_ADDR_REG_SAVE + BS3REGCTX.rsp+2], ax + mov eax, ebp + shr eax, 16 + mov [BS3_ADDR_REG_SAVE + BS3REGCTX.rbp+2], ax + shr edi, 16 + mov [BS3_ADDR_REG_SAVE + BS3REGCTX.rdi+2], di + shr ecx, 16 + mov [BS3_ADDR_REG_SAVE + BS3REGCTX.rcx+2], cx + mov [BS3_ADDR_REG_SAVE + BS3REGCTX.fs], fs + mov [BS3_ADDR_REG_SAVE + BS3REGCTX.gs], gs + mov [BS3_ADDR_REG_SAVE + BS3REGCTX.rbx], ebx + mov [BS3_ADDR_REG_SAVE + BS3REGCTX.rdx], edx + mov [BS3_ADDR_REG_SAVE + BS3REGCTX.rsi], esi + mov eax, cr2 + mov [BS3_ADDR_REG_SAVE + BS3REGCTX.cr2], eax + mov eax, cr3 + mov [BS3_ADDR_REG_SAVE + BS3REGCTX.cr3], eax + mov byte [BS3_ADDR_REG_SAVE + BS3REGCTX.bMode], BS3_MODE_RM + mov [cs:BS3_ADDR_REG_SAVE + BS3REGCTX.cs], cs + xor eax, eax + mov ax, start + mov [cs:BS3_ADDR_REG_SAVE + BS3REGCTX.rip], eax + + ; Pentium/486+: CR4 requires VME/CPUID, so we need to detect that before accessing it. + mov [cs:BS3_ADDR_REG_SAVE + BS3REGCTX.cr4], eax + popf ; (restores IOPL+NT) + pushfd + pop eax + mov [BS3_ADDR_REG_SAVE + BS3REGCTX.rflags], eax + xor eax, X86_EFL_ID + push eax + popfd + pushfd + pop ebx + cmp ebx, eax + jne .no_cr4 + mov eax, cr4 + mov [BS3_ADDR_REG_SAVE + BS3REGCTX.cr4], eax +.no_cr4: + ; Make sure caching is enabled and alignment is off. + mov eax, cr0 + mov [BS3_ADDR_REG_SAVE + BS3REGCTX.cr0], eax + and eax, ~(X86_CR0_NW | X86_CR0_CD | X86_CR0_AM) + mov cr0, eax + + ; Load all the code. +.do_load + mov [g_bBootDrv], dl + call NAME(bs3InitLoadImage) +%if 0 + mov al, '=' + call NAME(bs3PrintChrInAl) +%endif + + ; + ; Call the user 'main' procedure (shouldn't return). + ; + cld + call BS3_SEL_TEXT16:0000h + + ; Panic/hang. +Bs3Panic: + cli + jmp Bs3Panic + + +;; For debug and error handling. +; @uses ax +bs3PrintHexInAl: +CPU 286 + push ax + shr al, 4 + call bs3PrintHexDigitInAl + pop ax +bs3PrintHexDigitInAl: + and al, 0fh + cmp al, 10 + jb .decimal + add al, 'a' - '0' - 10 +.decimal: + add al, '0' +bs3PrintChrInAl: + push bx + mov ah, 0eh + mov bx, 0ff00h + int 10h + pop bx + ret + + +;; +; Loads the image off the floppy. +; +; This uses g_cLargeTotalSectors to figure out how much to load. +; +; Clobbers everything except ebp and esp. Panics on failure. +; +; @param dl The boot drive number (from BIOS). +; @uses ax, cx, bx, esi, di +; +BEGINPROC bs3InitLoadImage + push bp + mov bp, sp + push es +%define bSavedDiskNo byte [bp - 04h] + push dx +%define bMaxSector byte [bp - 06h] + xor ax, ax + push ax +%define bMaxHead byte [bp - 08h] + push ax +%define bMaxCylinder byte [bp - 0ah] + push ax + + ; + ; Try figure the geometry. + ; + mov ah, 08h + int 13h + jc .failure + mov bMaxSector, cl + mov bMaxHead, dh + mov bMaxCylinder, ch + mov dl, bSavedDiskNo + + ; + ; Reload all the sectors one at a time (avoids problems). + ; + mov si, [g_cLargeTotalSectors] ; 16-bit sector count ==> max 512 * 65 535 = 33 553 920 bytes. + dec si + mov di, BS3_ADDR_LOAD / 16 ; The current load segment. + mov cx, 0002h ; ch/cylinder=0 (0-based); cl/sector=2 (1-based) + xor dh, dh ; dh/head=0 +.the_load_loop: +%if 0 + mov al, 'c' + call bs3PrintChrInAl + mov al, ch + call bs3PrintHexInAl + mov al, 's' + call bs3PrintChrInAl + mov al, cl + call bs3PrintHexInAl + mov al, 'h' + call bs3PrintChrInAl + mov al, dh + call bs3PrintHexInAl + mov al, ';' + call bs3PrintChrInAl +%endif + xor bx, bx + mov es, di ; es:bx -> buffer + mov ax, 0201h ; al=1 sector; ah=read function + int 13h + jc .failure + + ; advance to the next sector/head/cylinder. + inc cl + cmp cl, bMaxSector + jbe .adv_addr + + mov cl, 1 + inc dh + cmp dh, bMaxHead + jbe .adv_addr + + mov dh, 0 + inc ch + +.adv_addr: + add di, 512 / 16 + dec si + jnz .the_load_loop +%if 0 + mov al, 'D' + call bs3PrintChrInAl +%endif + + add sp, 3*2 + pop dx + pop es + pop bp + ret + + ; + ; Something went wrong, display a message. + ; +.failure: + push ax + + ; print message + mov si, .s_szErrMsg +.failure_next_char: + lodsb + call bs3PrintChrInAl + cmp si, .s_szErrMsgEnd + jb .failure_next_char + + ; panic + pop ax +%if 1 + mov al, ah + push bs3PrintHexInAl +%endif + call Bs3Panic +.s_szErrMsg: + db 13, 10, 'rd err! ' +.s_szErrMsgEnd: +;ENDPROC bs3InitLoadImage - don't want the padding. + + +; +; Pad the remainder of the sector with int3's and end it with the DOS signature. +; +bs3Padding: + times ( 510 - ( (bs3Padding - start) % 512 ) ) db 0cch + db 055h, 0aah + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-c16-CreateHybridFarRet.asm b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-c16-CreateHybridFarRet.asm new file mode 100644 index 00000000..ef48576f --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-c16-CreateHybridFarRet.asm @@ -0,0 +1,53 @@ +; $Id: bs3-c16-CreateHybridFarRet.asm $ +;; @file +; BS3Kit - Bs3A20Disable. +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + + +%include "bs3kit.mac" + + +;; +; Worker for BS3_PROC_BEGIN_CMN +; @uses nothing +BS3_PROC_BEGIN Bs3CreateHybridFarRet_c16 + push ax ; reserve space + push bp + mov bp, sp + push ax ; save it + + ; Move the return address up a word. + mov ax, [bp + 4] + mov [bp + 2], ax + ; Move the caller's return address up a word. + mov ax, [bp + 6] + mov [bp + 4], ax + ; Add CS to the caller's far return address. + mov [bp + 6], cs + + pop ax + pop bp + ret +BS3_PROC_END Bs3CreateHybridFarRet_c16 + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-c16-SwitchFromV86To16BitAndCallC.asm b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-c16-SwitchFromV86To16BitAndCallC.asm new file mode 100644 index 00000000..b723178e --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-c16-SwitchFromV86To16BitAndCallC.asm @@ -0,0 +1,99 @@ +; $Id: bs3-c16-SwitchFromV86To16BitAndCallC.asm $ +;; @file +; BS3Kit - Bs3SwitchFromV86To16BitAndCallC +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + +;********************************************************************************************************************************* +;* Header Files * +;********************************************************************************************************************************* +%include "bs3kit-template-header.mac" +%if TMPL_BITS != 16 + %error "16-bit only" +%endif + + +;********************************************************************************************************************************* +;* External Symbols * +;********************************************************************************************************************************* +%ifdef BS3_STRICT +BS3_EXTERN_DATA16 g_bBs3CurrentMode +TMPL_BEGIN_TEXT +BS3_EXTERN_CMN Bs3Panic +%endif +BS3_EXTERN_CMN Bs3SwitchTo16Bit +BS3_EXTERN_CMN Bs3SwitchTo16BitV86 +BS3_EXTERN_CMN Bs3SelRealModeCodeToProtMode + + +;; +; @cproto BS3_CMN_PROTO_STUB(int, Bs3SwitchFromV86To16BitAndCallC,(FPFNBS3FAR fpfnCall, unsigned cbParams, ...)); +; +BS3_PROC_BEGIN_CMN Bs3SwitchFromV86To16BitAndCallC, BS3_PBC_HYBRID + inc bp + push bp + mov bp, sp + + ; + ; Push the arguments first. + ; + mov ax, si ; save si + mov si, [bp + 2 + cbCurRetAddr + 4] +%ifdef BS3_STRICT + test si, 1 + jz .cbParams_ok + call Bs3Panic +.cbParams_ok: + test byte [g_bBs3CurrentMode], BS3_MODE_CODE_V86 + jnz .mode_ok + call Bs3Panic +.mode_ok: +%endif + +.push_more: + push word [bp + 2 + cbCurRetAddr + 4 + 2 + si - 2] + sub si, 2 + jnz .push_more + mov si, ax ; restore si + + ; + ; Convert the code segment to a 16-bit prot mode selector + ; + push word [bp + 2 + cbCurRetAddr + 2] + call Bs3SelRealModeCodeToProtMode + mov [bp + 2 + cbCurRetAddr + 2], ax + add sp, 2 + + ; + ; Switch mode. + ; + call Bs3SwitchTo16Bit + call far [bp + 2 + cbCurRetAddr] + call Bs3SwitchTo16BitV86 + + mov sp, bp + pop bp + dec bp + BS3_HYBRID_RET +BS3_PROC_END_CMN Bs3SwitchFromV86To16BitAndCallC + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-c16-Trap16Generic.asm b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-c16-Trap16Generic.asm new file mode 100644 index 00000000..577c0138 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-c16-Trap16Generic.asm @@ -0,0 +1,710 @@ +; $Id: bs3-c16-Trap16Generic.asm $ +;; @file +; BS3Kit - Trap, 16-bit assembly handlers. +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + +;********************************************************************************************************************************* +;* Header Files * +;********************************************************************************************************************************* +%include "bs3kit-template-header.mac" + +%ifndef TMPL_16BIT + %error "16-bit only template" +%endif + + +;********************************************************************************************************************************* +;* External Symbols * +;********************************************************************************************************************************* +BS3_EXTERN_DATA16 g_bBs3CurrentMode +BS3_EXTERN_DATA16 g_uBs3TrapEipHint +BS3_EXTERN_DATA16 g_uBs3CpuDetected +BS3_EXTERN_DATA16 g_apfnBs3TrapHandlers_c16 +BS3_EXTERN_SYSTEM16 Bs3Gdt +TMPL_BEGIN_TEXT +BS3_EXTERN_CMN Bs3TrapDefaultHandler +BS3_EXTERN_CMN Bs3RegCtxRestore +TMPL_BEGIN_TEXT + + +;; +; Generic entry points for IDT handlers, 8 byte spacing. +; +BS3_PROC_BEGIN _Bs3Trap16GenericEntries +BS3_PROC_BEGIN Bs3Trap16GenericEntries +%macro Bs3Trap16GenericEntryNoErr 1 + push byte 0 ; 2 byte: fake error code + db 06ah, i ; 2 byte: push imm8 - note that this is a signextended value. + jmp %1 ; 3 byte + ALIGNCODE(8) +%assign i i+1 +%endmacro + +%macro Bs3Trap16GenericEntryErrCd 1 + db 06ah, i ; 2 byte: push imm8 - note that this is a signextended value. + jmp %1 ; 3 byte + ALIGNCODE(8) +%assign i i+1 +%endmacro + +%assign i 0 ; start counter. + Bs3Trap16GenericEntryNoErr bs3Trap16GenericTrapOrInt ; 0 + Bs3Trap16GenericEntryNoErr bs3Trap16GenericTrapOrInt ; 1 + Bs3Trap16GenericEntryNoErr bs3Trap16GenericTrapOrInt ; 2 + Bs3Trap16GenericEntryNoErr bs3Trap16GenericTrapOrInt ; 3 + Bs3Trap16GenericEntryNoErr bs3Trap16GenericTrapOrInt ; 4 + Bs3Trap16GenericEntryNoErr bs3Trap16GenericTrapOrInt ; 5 + Bs3Trap16GenericEntryNoErr bs3Trap16GenericTrapOrInt ; 6 + Bs3Trap16GenericEntryNoErr bs3Trap16GenericTrapOrInt ; 7 + Bs3Trap16GenericEntryErrCd bs3Trap16GenericTrapOrInt ; 8 + Bs3Trap16GenericEntryNoErr bs3Trap16GenericTrapOrInt ; 9 + Bs3Trap16GenericEntryErrCd bs3Trap16GenericTrapOrInt ; a + Bs3Trap16GenericEntryErrCd bs3Trap16GenericTrapOrInt ; b + Bs3Trap16GenericEntryErrCd bs3Trap16GenericTrapOrInt ; c + Bs3Trap16GenericEntryErrCd bs3Trap16GenericTrapOrInt ; d + Bs3Trap16GenericEntryErrCd bs3Trap16GenericTrapOrInt ; e + Bs3Trap16GenericEntryNoErr bs3Trap16GenericTrapOrInt ; f (reserved) + Bs3Trap16GenericEntryNoErr bs3Trap16GenericTrapOrInt ; 10 + Bs3Trap16GenericEntryErrCd bs3Trap16GenericTrapOrInt ; 11 + Bs3Trap16GenericEntryNoErr bs3Trap16GenericTrapOrInt ; 12 + Bs3Trap16GenericEntryNoErr bs3Trap16GenericTrapOrInt ; 13 + Bs3Trap16GenericEntryNoErr bs3Trap16GenericTrapOrInt ; 14 + Bs3Trap16GenericEntryNoErr bs3Trap16GenericTrapOrInt ; 15 (reserved) + Bs3Trap16GenericEntryNoErr bs3Trap16GenericTrapOrInt ; 16 (reserved) + Bs3Trap16GenericEntryNoErr bs3Trap16GenericTrapOrInt ; 17 (reserved) + Bs3Trap16GenericEntryNoErr bs3Trap16GenericTrapOrInt ; 18 (reserved) + Bs3Trap16GenericEntryNoErr bs3Trap16GenericTrapOrInt ; 19 (reserved) + Bs3Trap16GenericEntryNoErr bs3Trap16GenericTrapOrInt ; 1a (reserved) + Bs3Trap16GenericEntryNoErr bs3Trap16GenericTrapOrInt ; 1b (reserved) + Bs3Trap16GenericEntryNoErr bs3Trap16GenericTrapOrInt ; 1c (reserved) + Bs3Trap16GenericEntryNoErr bs3Trap16GenericTrapOrInt ; 1d (reserved) + Bs3Trap16GenericEntryErrCd bs3Trap16GenericTrapOrInt ; 1e + Bs3Trap16GenericEntryNoErr bs3Trap16GenericTrapOrInt ; 1f (reserved) +%rep 224 + Bs3Trap16GenericEntryNoErr bs3Trap16GenericTrapOrInt +%endrep +BS3_PROC_END Bs3Trap16GenericEntries +AssertCompile(Bs3Trap16GenericEntries_EndProc - Bs3Trap16GenericEntries == 8*256) + + +;; +; Trap or interrupt with error code, faked if necessary. +; +; Note! This code is going to "misbehave" if the high word of ESP is not cleared. +; +BS3_PROC_BEGIN _bs3Trap16GenericTrapOrInt +BS3_PROC_BEGIN bs3Trap16GenericTrapOrInt +CPU 386 + jmp near bs3Trap16GenericTrapErrCode80286 ; Bs3Trap16Init adjusts this on 80386+ + push ebp + movzx ebp, sp + push ebx ; BP - 04h + pushfd ; BP - 08h + cld + push edx ; BP - 0ch + push ss ; BP - 0eh + push esp ; BP - 12h + + ; + ; We may be comming from 32-bit code where SS is flat and ESP has a non- + ; zero high word. We need to thunk it for C code to work correctly with + ; [BP+xx] and [SS:BX+xx] style addressing that leaves out the high word. + ; + ; Note! Require ring-0 handler for non-standard stacks (SS.DPL must equal CPL). + ; + mov bx, ss + lar ebx, bx + test ebx, X86LAR_F_D + jz .stack_fine + test esp, 0ffff0000h + jnz .stack_thunk +.stack_load_r0_ss16: + mov bx, ss + and bl, 3 + AssertCompile(BS3_SEL_RING_SHIFT == 8) + mov bh, bl + add bx, BS3_SEL_R0_SS16 + jmp .stack_load_bx_into_ss +.stack_thunk: + mov ebx, esp + shr ebx, 16 + shl ebx, X86_SEL_SHIFT + add ebx, BS3_SEL_TILED_R0 + cmp ebx, BS3_SEL_TILED_R0_LAST + ja .stack_esp_out_of_bounds +.stack_load_bx_into_ss: + mov ss, bx +.stack_fine: + movzx esp, sp + + ; Reserve space for the register and trap frame. + mov bx, (BS3TRAPFRAME_size + 7) / 8 +.more_zeroed_space: + push 0 + push 0 + push 0 + push 0 + dec bx + jnz .more_zeroed_space + movzx ebx, sp + + mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.rax], eax + mov edx, [bp - 12h] ; This isn't quite right for wrap arounds, but close enough for now + mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.rsp], edx ; high bits + mov [ss:bx + BS3TRAPFRAME.uHandlerRsp], edx ; high bits + mov dx, [bp - 0eh] + mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.ss], dx + mov [ss:bx + BS3TRAPFRAME.uHandlerSs], dx + mov edx, [bp - 0ch] + mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.rdx], edx + mov edx, [bp - 8] + mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.rflags], edx ; high bits + mov [ss:bx + BS3TRAPFRAME.fHandlerRfl], edx + mov edx, [bp - 4] + mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.rbx], edx + mov edx, [bp] + mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.rbp], edx + + mov dl, [bp + 4] + mov [ss:bx + BS3TRAPFRAME.bXcpt], dl + + mov dx, [bp + 6] +;; @todo Do voodoo checks for 'int xx' or misguided hardware interrupts. + mov [ss:bx + BS3TRAPFRAME.uErrCd], dx + + add bp, 6 ; adjust so it points to the word before the iret frame. + xor dx, dx + jmp bs3Trap16GenericCommon + +.stack_esp_out_of_bounds: +%ifdef BS3_STRICT + int3 +%endif + jmp .stack_esp_out_of_bounds +BS3_PROC_END bs3Trap16GenericTrapErrCode + +;; +; Trap with error code - 80286 code variant. +; +BS3_PROC_BEGIN bs3Trap16GenericTrapErrCode80286 +CPU 286 + push bp + mov bp, sp + push bx + pushf + cld + + ; Reserve space for the register and trap frame. + mov bx, (BS3TRAPFRAME_size + 7) / 8 +.more_zeroed_space: + push 0 + push 0 + push 0 + push 0 + dec bx + jnz .more_zeroed_space + mov bx, sp + + mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.rax], ax + mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.ss], ss + mov [ss:bx + BS3TRAPFRAME.uHandlerSs], ss + mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.rdx], dx + mov dx, [bp - 4] + mov [ss:bx + BS3TRAPFRAME.fHandlerRfl], dx + mov dx, [bp - 2] + mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.rbx], dx + mov dx, [bp] + mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.rbp], dx + + mov dl, [bp + 2] + mov [ss:bx + BS3TRAPFRAME.bXcpt], dl + + mov dx, [bp + 4] +;; @todo Do voodoo checks for 'int xx' or misguided hardware interrupts. + mov [ss:bx + BS3TRAPFRAME.uErrCd], dx + + add bp, 4 ; adjust so it points to the word before the iret frame. + mov dl, 1 + jmp bs3Trap16GenericCommon +BS3_PROC_END bs3Trap16GenericTrapErrCode80286 + + +;; +; Common context saving code and dispatching. +; +; @param bx Pointer to the trap frame, zero filled. The following members +; have been filled in by the previous code: +; - bXcpt +; - uErrCd +; - fHandlerRFL +; - Ctx.eax +; - Ctx.edx +; - Ctx.ebx +; - Ctx.ebp +; - Ctx.rflags - high bits only. +; - Ctx.esp - high bits only. +; - Ctx.ss - for same cpl frames +; - All other bytes are zeroed. +; +; @param bp Pointer to the word before the iret frame, i.e. where bp +; would be saved if this was a normal near call. +; @param dx One (1) if 286, zero (0) if 386+. +; +BS3_PROC_BEGIN bs3Trap16GenericCommon +CPU 286 + ; + ; Fake EBP frame. + ; + mov ax, [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.rbp] + mov [bp], ax + + ; + ; Save the remaining GPRs and segment registers. + ; + test dx, dx + jnz .save_word_grps +CPU 386 + mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.rcx], ecx + mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.rdi], edi + mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.rsi], esi + mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.fs], fs + mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.gs], gs + jmp .save_segment_registers +.save_word_grps: +CPU 286 + mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.rcx], cx + mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.rdi], di + mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.rsi], si +.save_segment_registers: + mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.ds], ds + mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.es], es + mov [ss:bx + BS3TRAPFRAME.uHandlerCs], cs + + ; + ; Load 16-bit data selector for the DPL we're executing at into DS and ES. + ; + mov ax, ss + and ax, 3 + mov cx, ax + shl ax, BS3_SEL_RING_SHIFT + or ax, cx + add ax, BS3_SEL_R0_DS16 + mov ds, ax + mov es, ax + + ; + ; Copy and update the mode now that we've got a flat DS. + ; + mov al, [BS3_DATA16_WRT(g_bBs3CurrentMode)] + mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.bMode], al + mov cl, al + and cl, ~BS3_MODE_CODE_MASK + or cl, BS3_MODE_CODE_16 + mov [BS3_DATA16_WRT(g_bBs3CurrentMode)], cl + + ; + ; Copy iret info. + ; + lea cx, [bp + 2] + mov [ss:bx + BS3TRAPFRAME.uHandlerRsp], cx + mov cx, [bp + 2] + mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.rip], cx + mov cx, [bp + 6] + mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.rflags], cx + mov cx, [bp + 4] + mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.cs], cx + + test al, BS3_MODE_CODE_V86 + jnz .iret_frame_v8086 + + mov ax, ss + and al, 3 + and cl, 3 + mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.bCpl], cl + cmp cl, al + je .iret_frame_same_cpl + +.ret_frame_different_cpl: + mov cx, [bp + 10] + mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.ss], cx + mov cx, [bp + 8] + mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.rsp], cx + mov byte [ss:bx + BS3TRAPFRAME.cbIretFrame], 5*2 + test dx, dx + jnz .iret_frame_done + jmp .iret_frame_seed_high_eip_word + +.iret_frame_same_cpl: ; (ss and high bits was saved by CPU specific part) + lea cx, [bp + 8] + mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.rsp], cx + mov byte [ss:bx + BS3TRAPFRAME.cbIretFrame], 3*2 + test dx, dx + jnz .iret_frame_done + jmp .iret_frame_seed_high_eip_word + +.iret_frame_v8086: +CPU 386 + or dword [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.rflags], X86_EFL_VM + mov byte [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.bCpl], 3 + or byte [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.bMode], BS3_MODE_CODE_V86 ; paranoia ^ 2 +%if 0 ;; @todo testcase: high ESP word from V86 mode, 16-bit TSS. + movzx ecx, word [bp + 8] + mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.rsp], ecx +%else + mov cx, word [bp + 8] + mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.rsp], cx +%endif + mov cx, [bp + 10] + mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.ss], cx + mov cx, [bp + 12] + mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.es], cx + mov cx, [bp + 14] + mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.ds], cx + mov cx, [bp + 16] + mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.fs], cx + mov cx, [bp + 18] + mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.gs], cx + mov byte [ss:bx + BS3TRAPFRAME.cbIretFrame], 9*2 + jmp .iret_frame_done + + ; + ; For 386 we do special tricks to supply the high word of EIP when + ; arriving here from 32-bit code. (ESP was seeded earlier.) + ; +.iret_frame_seed_high_eip_word: + lar eax, [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.cs] + jnz .iret_frame_done + test eax, X86LAR_F_D + jz .iret_frame_done + mov ax, [g_uBs3TrapEipHint+2] + mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.rip + 2], ax + +.iret_frame_done: + ; + ; Control registers. + ; + str [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.tr] + sldt [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.ldtr] + test dx, dx + jnz .save_286_control_registers +.save_386_control_registers: +CPU 386 + mov ax, ss + test al, 3 + jnz .skip_crX_because_cpl_not_0 + mov eax, cr0 + mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.cr0], eax + mov eax, cr2 + mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.cr2], eax + mov eax, cr3 + mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.cr3], eax + + test byte [1 + BS3_DATA16_WRT(g_uBs3CpuDetected)], (BS3CPU_F_CPUID >> 8) ; CR4 first appeared in later 486es. + jz .skip_cr4_because_not_there + mov eax, cr4 + mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.cr4], eax + jmp .set_flags + +.skip_cr4_because_not_there: + mov byte [edi + BS3TRAPFRAME.Ctx + BS3REGCTX.fbFlags], BS3REG_CTX_F_NO_CR4 + jmp .set_flags + +.skip_crX_because_cpl_not_0: + or byte [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.fbFlags], \ + BS3REG_CTX_F_NO_CR2_CR3 | BS3REG_CTX_F_NO_CR4 | BS3REG_CTX_F_NO_CR0_IS_MSW + +CPU 286 +.save_286_control_registers: + smsw [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.cr0] + +.set_flags: ; The double fault code joins us here. + or byte [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.fbFlags], BS3REG_CTX_F_NO_AMD64 + + ; + ; Dispatch it to C code. + ; +.dispatch_to_handler: + mov di, bx + mov bl, byte [ss:bx + BS3TRAPFRAME.bXcpt] + mov bh, 0 + shl bx, 1 + mov bx, [bx + BS3_DATA16_WRT(_g_apfnBs3TrapHandlers_c16)] + or bx, bx + jnz .call_handler + mov bx, Bs3TrapDefaultHandler +.call_handler: + push ss + push di + call bx + + ; + ; Resume execution using trap frame. + ; + push 0 + push ss + add di, BS3TRAPFRAME.Ctx + push di + call Bs3RegCtxRestore +.panic: + hlt + jmp .panic +BS3_PROC_END bs3Trap16GenericCommon + + +;; +; Helper. +; +; @retruns Flat address in es:di. +; @param di +; @uses eax +; +bs3Trap16TssInDiToFar1616InEsDi: +CPU 286 + push ax + + ; ASSUME Bs3Gdt is being used. + push BS3_SEL_SYSTEM16 + pop es + and di, 0fff8h + add di, Bs3Gdt wrt BS3SYSTEM16 + + ; Load the TSS base into ax:di (di is low, ax high) + mov al, [es:di + (X86DESCGENERIC_BIT_OFF_BASE_HIGH1 / 8)] + mov ah, [es:di + (X86DESCGENERIC_BIT_OFF_BASE_HIGH2 / 8)] + mov di, [es:di + (X86DESCGENERIC_BIT_OFF_BASE_LOW / 8)] + + ; Convert ax to tiled selector, if not within the tiling area we read + ; random BS3SYSTEM16 bits as that's preferable to #GP'ing. + shl ax, X86_SEL_SHIFT + cmp ax, BS3_SEL_TILED_LAST - BS3_SEL_TILED +%ifdef BS3_STRICT + jbe .tiled + int3 +%endif + ja .return ; don't crash again. +.tiled: + add ax, BS3_SEL_TILED + mov es, ax +.return: + pop ax + ret + + +;; +; Double fault handler. +; +; We don't have to load any selectors or clear anything in EFLAGS because the +; TSS specified sane values which got loaded during the task switch. +; +; @param dx Zero (0) for indicating 386+ to the common code. +; +BS3_PROC_BEGIN _Bs3Trap16DoubleFaultHandler80386 +BS3_PROC_BEGIN Bs3Trap16DoubleFaultHandler80386 +CPU 386 + push 0 ; We'll copy the rip from the other TSS here later to create a more sensible call chain. + push ebp + mov bp, sp + pushfd ; Handler flags. + + ; Reserve space for the register and trap frame. + mov bx, (BS3TRAPFRAME_size + 15) / 16 +.more_zeroed_space: + push dword 0 + push dword 0 + push dword 0 + push dword 0 + dec bx + jz .more_zeroed_space + mov bx, sp + + ; + ; Fill in the high GRP register words before we mess them up. + ; + mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.rax], eax + mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.rbx], ebx + mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.rcx], ecx + mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.rdx], edx + mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.rsi], esi + mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.rdi], edi + mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.rbp], ebp + mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.rsp], esp + + ; + ; FS and GS are not part of the 16-bit TSS because they are 386+ specfic. + ; + mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.fs], fs + mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.gs], gs + + ; + ; Fill in the non-context trap frame bits. + ; + mov ecx, [bp - 4] + mov [ss:bx + BS3TRAPFRAME.fHandlerRfl], ecx + mov byte [ss:bx + BS3TRAPFRAME.bXcpt], X86_XCPT_DF + mov [ss:bx + BS3TRAPFRAME.uHandlerCs], cs + mov [ss:bx + BS3TRAPFRAME.uHandlerSs], ss + mov ecx, esp + lea cx, [bp + 8] + mov [ss:bx + BS3TRAPFRAME.uHandlerRsp], ecx + mov cx, [bp + 6] + mov [ss:bx + BS3TRAPFRAME.uErrCd], cx + + ; + ; Copy 80386+ control registers. + ; + mov ecx, cr0 + mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.cr0], ecx + mov ecx, cr2 + mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.cr2], ecx + mov ecx, cr3 + mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.cr3], ecx + + test byte [1 + BS3_DATA16_WRT(g_uBs3CpuDetected)], (BS3CPU_F_CPUID >> 8) ; CR4 first appeared in later 486es. + jz .skip_cr4_because_not_there + mov ecx, cr4 + mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.cr4], ecx + jmp .common + +.skip_cr4_because_not_there: + mov byte [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.fbFlags], BS3REG_CTX_F_NO_CR4 + + ; + ; Copy the register state from the previous task segment. + ; The 80286 code with join us here. + ; +.common: +CPU 286 + ; Find our TSS. + str di + call bs3Trap16TssInDiToFar1616InEsDi + + ; Find the previous TSS. + mov di, [es:di + X86TSS32.selPrev] + mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.tr], ax + call bs3Trap16TssInDiToFar1616InEsDi + + ; Do the copying. + mov cx, [es:di + X86TSS16.ax] + mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.rax], cx + mov cx, [es:di + X86TSS16.cx] + mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.rcx], cx + mov cx, [es:di + X86TSS16.dx] + mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.rdx], cx + mov cx, [es:di + X86TSS16.bx] + mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.rbx], cx + mov cx, [es:di + X86TSS16.sp] + mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.rsp], cx + mov cx, [es:di + X86TSS16.bp] + mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.rbp], cx + mov [bp], cx ; For better call stacks. + mov cx, [es:di + X86TSS16.si] + mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.rsi], cx + mov cx, [es:di + X86TSS16.di] + mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.rdi], cx + mov cx, [es:di + X86TSS16.si] + mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.rsi], cx + mov cx, [es:di + X86TSS16.flags] + mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.rflags], cx + mov cx, [es:di + X86TSS16.ip] + mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.rip], cx + mov [bp + 2], cx ; For better call stacks. + mov cx, [es:di + X86TSS16.cs] + mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.cs], cx + mov cx, [es:di + X86TSS16.ds] + mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.ds], cx + mov cx, [es:di + X86TSS16.es] + mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.es], cx + mov cx, [es:di + X86TSS16.ss] + mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.ss], cx + mov cx, [es:di + X86TSS16.selLdt] ; Note! This isn't necessarily the ldtr at the time of the fault. + mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.ldtr], cx + + ; + ; Set CPL; copy and update mode. + ; + mov cl, [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.ss] + and cl, 3 + mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.bCpl], cl + + mov cl, [BS3_DATA16_WRT(g_bBs3CurrentMode)] + mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.bMode], cl + and cl, ~BS3_MODE_CODE_MASK + or cl, BS3_MODE_CODE_16 + mov [BS3_DATA16_WRT(g_bBs3CurrentMode)], cl + + ; + ; Join code paths with the generic handler code. + ; + jmp bs3Trap16GenericCommon.set_flags +BS3_PROC_END Bs3Trap16DoubleFaultHandler + + +;; +; Double fault handler. +; +; We don't have to load any selectors or clear anything in EFLAGS because the +; TSS specified sane values which got loaded during the task switch. +; +; @param dx One (1) for indicating 386+ to the common code. +; +BS3_PROC_BEGIN _Bs3Trap16DoubleFaultHandler80286 +BS3_PROC_BEGIN Bs3Trap16DoubleFaultHandler80286 +CPU 286 + push 0 ; We'll copy the rip from the other TSS here later to create a more sensible call chain. + push bp + mov bp, sp + pushf ; Handler flags. + + ; Reserve space for the register and trap frame. + mov bx, (BS3TRAPFRAME_size + 7) / 8 +.more_zeroed_space: + push 0 + push 0 + push 0 + push 0 + dec bx + jz .more_zeroed_space + mov bx, sp + + ; + ; Fill in the non-context trap frame bits. + ; + mov cx, [bp - 2] + mov [ss:bx + BS3TRAPFRAME.fHandlerRfl], cx + mov byte [ss:bx + BS3TRAPFRAME.bXcpt], X86_XCPT_DF + mov [ss:bx + BS3TRAPFRAME.uHandlerCs], cs + mov [ss:bx + BS3TRAPFRAME.uHandlerSs], ss + lea cx, [bp + 8] + mov [ss:bx + BS3TRAPFRAME.uHandlerRsp], cx + mov cx, [bp + 6] + mov [ss:bx + BS3TRAPFRAME.uErrCd], cx + + ; + ; Copy 80286 specific control register. + ; + smsw [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.cr0] + + jmp Bs3Trap16DoubleFaultHandler80386.common +BS3_PROC_END Bs3Trap16DoubleFaultHandler80286 + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-c16-TrapRmV86Data.c b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-c16-TrapRmV86Data.c new file mode 100644 index 00000000..43e1d21e --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-c16-TrapRmV86Data.c @@ -0,0 +1,43 @@ +/* $Id: bs3-c16-TrapRmV86Data.c $ */ +/** @file + * BS3Kit - Real mode and V86 trap data. + */ + +/* + * Copyright (C) 2007-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include "bs3kit-template-header.h" + + +/********************************************************************************************************************************* +* Global Variables * +*********************************************************************************************************************************/ +#if ARCH_BITS == 16 +/** Copy of the original real-mode interrupt vector table. */ +RTFAR16 g_aBs3RmIvtOriginal[256]; +/** Indicates whether we've copied the real-mode IVT or not. */ +bool g_fBs3RmIvtCopied = false; +#endif + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-c16-TrapRmV86Generic.asm b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-c16-TrapRmV86Generic.asm new file mode 100644 index 00000000..28e4cf7d --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-c16-TrapRmV86Generic.asm @@ -0,0 +1,391 @@ +; $Id: bs3-c16-TrapRmV86Generic.asm $ +;; @file +; BS3Kit - Trap, 16-bit assembly handlers for real mode and v8086. +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + +;********************************************************************************************************************************* +;* Header Files * +;********************************************************************************************************************************* +%include "bs3kit-template-header.mac" + +%ifndef TMPL_16BIT + %error "16-bit only template" +%endif + + +;********************************************************************************************************************************* +;* External Symbols * +;********************************************************************************************************************************* +BS3_EXTERN_DATA16 g_bBs3CurrentMode +BS3_EXTERN_DATA16 g_uBs3TrapEipHint +BS3_EXTERN_DATA16 g_uBs3CpuDetected +BS3_EXTERN_DATA16 g_apfnBs3TrapHandlers_c16 +TMPL_BEGIN_TEXT +BS3_EXTERN_CMN Bs3TrapDefaultHandler +BS3_EXTERN_CMN Bs3RegCtxRestore +TMPL_BEGIN_TEXT + + +;; +; Generic entry points for IDT handlers, 8 byte spacing. +; +BS3_PROC_BEGIN _Bs3TrapRmV86GenericEntries +BS3_PROC_BEGIN Bs3TrapRmV86GenericEntries +%macro Bs3TrapRmV86GenericEntryNoErr 1 + push ax ; 1 byte: Reserve space for fake error cd. (BP(+2) + 4) + push ax ; 1 byte: Save AX (BP(+2) + 2) + mov ax, i | 00000h ; 2 bytes: AL = trap/interrupt number; AH=indicate no error code + jmp %1 ; 3 bytes: Jump to handler code + ALIGNCODE(8) +%assign i i+1 +%endmacro + +%macro Bs3TrapRmV86GenericEntryErrCd 1 + Bs3TrapRmV86GenericEntryNoErr %1 ; No error code pushed in real mode or V86 mode. +%endmacro + +%assign i 0 ; start counter. + Bs3TrapRmV86GenericEntryNoErr bs3TrapRmV86GenericTrapOrInt ; 0 + Bs3TrapRmV86GenericEntryNoErr bs3TrapRmV86GenericTrapOrInt ; 1 + Bs3TrapRmV86GenericEntryNoErr bs3TrapRmV86GenericTrapOrInt ; 2 + Bs3TrapRmV86GenericEntryNoErr bs3TrapRmV86GenericTrapOrInt ; 3 + Bs3TrapRmV86GenericEntryNoErr bs3TrapRmV86GenericTrapOrInt ; 4 + Bs3TrapRmV86GenericEntryNoErr bs3TrapRmV86GenericTrapOrInt ; 5 + Bs3TrapRmV86GenericEntryNoErr bs3TrapRmV86GenericTrapOrInt ; 6 + Bs3TrapRmV86GenericEntryNoErr bs3TrapRmV86GenericTrapOrInt ; 7 + Bs3TrapRmV86GenericEntryErrCd bs3TrapRmV86GenericTrapOrInt ; 8 + Bs3TrapRmV86GenericEntryNoErr bs3TrapRmV86GenericTrapOrInt ; 9 + Bs3TrapRmV86GenericEntryErrCd bs3TrapRmV86GenericTrapOrInt ; a + Bs3TrapRmV86GenericEntryErrCd bs3TrapRmV86GenericTrapOrInt ; b + Bs3TrapRmV86GenericEntryErrCd bs3TrapRmV86GenericTrapOrInt ; c + Bs3TrapRmV86GenericEntryErrCd bs3TrapRmV86GenericTrapOrInt ; d + Bs3TrapRmV86GenericEntryErrCd bs3TrapRmV86GenericTrapOrInt ; e + Bs3TrapRmV86GenericEntryNoErr bs3TrapRmV86GenericTrapOrInt ; f (reserved) + Bs3TrapRmV86GenericEntryNoErr bs3TrapRmV86GenericTrapOrInt ; 10 + Bs3TrapRmV86GenericEntryErrCd bs3TrapRmV86GenericTrapOrInt ; 11 + Bs3TrapRmV86GenericEntryNoErr bs3TrapRmV86GenericTrapOrInt ; 12 + Bs3TrapRmV86GenericEntryNoErr bs3TrapRmV86GenericTrapOrInt ; 13 + Bs3TrapRmV86GenericEntryNoErr bs3TrapRmV86GenericTrapOrInt ; 14 + Bs3TrapRmV86GenericEntryNoErr bs3TrapRmV86GenericTrapOrInt ; 15 (reserved) + Bs3TrapRmV86GenericEntryNoErr bs3TrapRmV86GenericTrapOrInt ; 16 (reserved) + Bs3TrapRmV86GenericEntryNoErr bs3TrapRmV86GenericTrapOrInt ; 17 (reserved) + Bs3TrapRmV86GenericEntryNoErr bs3TrapRmV86GenericTrapOrInt ; 18 (reserved) + Bs3TrapRmV86GenericEntryNoErr bs3TrapRmV86GenericTrapOrInt ; 19 (reserved) + Bs3TrapRmV86GenericEntryNoErr bs3TrapRmV86GenericTrapOrInt ; 1a (reserved) + Bs3TrapRmV86GenericEntryNoErr bs3TrapRmV86GenericTrapOrInt ; 1b (reserved) + Bs3TrapRmV86GenericEntryNoErr bs3TrapRmV86GenericTrapOrInt ; 1c (reserved) + Bs3TrapRmV86GenericEntryNoErr bs3TrapRmV86GenericTrapOrInt ; 1d (reserved) + Bs3TrapRmV86GenericEntryErrCd bs3TrapRmV86GenericTrapOrInt ; 1e + Bs3TrapRmV86GenericEntryNoErr bs3TrapRmV86GenericTrapOrInt ; 1f (reserved) +%rep 224 + Bs3TrapRmV86GenericEntryNoErr bs3TrapRmV86GenericTrapOrInt +%endrep +BS3_PROC_END Bs3TrapRmV86GenericEntries +AssertCompile(Bs3TrapRmV86GenericEntries_EndProc - Bs3TrapRmV86GenericEntries == 8*256) + + +;; +; Trap or interrupt with error code, faked if necessary. +; +; early 386+ stack (movzx ebp, sp): +; [bp + 000h] ebp +; [bp + 004h] ax +; [bp + 006h] errcd [bp'+0] <--- bp at jmp to common code. +; [bp + 008h] cs [bp'+2] +; [bp + 00ah] ip [bp'+4] +; [bp + 00ch] flags [bp'+6] +; ([bp + 00eh] post-iret sp value) [bp'+8] +; +BS3_PROC_BEGIN _bs3TrapRmV86GenericTrapOrInt +BS3_PROC_BEGIN bs3TrapRmV86GenericTrapOrInt +CPU 386 + jmp near bs3TrapRmV86GenericTrapErrCode8086 ; Bs3TrapRmV86Init adjusts this on 80386+ + push ebp + movzx ebp, sp + push ebx ; BP - 04h + pushfd ; BP - 08h + cld + push edx ; BP - 0ch + push ss ; BP - 0eh + push esp ; BP - 12h + + ; Reserve space for the register and trap frame. + mov bx, (BS3TRAPFRAME_size + 7) / 8 +.more_zeroed_space: + push 0 + push 0 + push 0 + push 0 + dec bx + jnz .more_zeroed_space + movzx ebx, sp + + + mov edx, [bp - 12h] + mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.rsp], edx ; high bits + mov [ss:bx + BS3TRAPFRAME.uHandlerRsp], edx ; high bits + mov dx, [bp - 0eh] + mov [ss:bx + BS3TRAPFRAME.uHandlerSs], dx + mov edx, [bp - 0ch] + mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.rdx], edx + mov edx, [bp - 8] + mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.rflags], edx ; high bits + mov [ss:bx + BS3TRAPFRAME.fHandlerRfl], edx + mov edx, [bp - 4] + mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.rbx], edx + mov edx, [bp] + mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.rbp], edx + mov edx, eax ; high bits + mov dx, [bp + 4] + mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.rax], edx + + mov [ss:bx + BS3TRAPFRAME.bXcpt], al + + test ah, 0ffh + jz .no_error_code + mov dx, [bp + 6] + mov [ss:bx + BS3TRAPFRAME.uErrCd], dx +.no_error_code: + + add bp, 6 ; adjust so it points to the word before the iret frame. + xor dx, dx + jmp bs3TrapRmV86GenericCommon +BS3_PROC_END bs3TrapRmV86GenericTrapErrCode + +;; +; Trap with error code - 8086/V20/80186/80286 code variant. +; +BS3_PROC_BEGIN bs3TrapRmV86GenericTrapErrCode8086 +CPU 8086 + push bp + mov bp, sp + push bx ; BP - 2 + pushf ; BP - 4 + push ax ; BP - 6 + cld + + ; Reserve space for the register and trap frame. + mov bx, (BS3TRAPFRAME_size + 7) / 8 + xor ax, ax +.more_zeroed_space: + push ax + push ax + push ax + push ax + dec bx + jnz .more_zeroed_space + mov bx, sp + + mov [ss:bx + BS3TRAPFRAME.uHandlerSs], ss + mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.rdx], dx + mov dx, [bp - 4] + mov [ss:bx + BS3TRAPFRAME.fHandlerRfl], dx + mov dx, [bp - 2] + mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.rbx], dx + mov dx, [bp] + mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.rbp], dx + + mov dx, [bp + 2] + mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.rax], dx + + mov ax, [bp - 6] + mov [ss:bx + BS3TRAPFRAME.bXcpt], al + + test ah, 0ffh + jz .no_error_code + mov dx, [bp + 4] + mov [ss:bx + BS3TRAPFRAME.uErrCd], dx +.no_error_code: + + add bp, 4 ; adjust so it points to the word before the iret frame. + mov dl, 1 + jmp bs3TrapRmV86GenericCommon +BS3_PROC_END bs3TrapRmV86GenericTrapErrCode8086 + + +;; +; Common context saving code and dispatching. +; +; @param ss:bx Pointer to the trap frame, zero filled. The following members +; have been filled in by the previous code: +; - bXcpt +; - uErrCd +; - fHandlerRFL +; - Ctx.eax +; - Ctx.edx +; - Ctx.ebx +; - Ctx.ebp +; - Ctx.rflags - high bits only. +; - Ctx.esp - high bits only. +; - All other bytes are zeroed. +; +; @param bp Pointer to the word before the iret frame, i.e. where bp +; would be saved if this was a normal near call. +; @param dx One (1) if 286, zero (0) if 386+. +; +BS3_PROC_BEGIN bs3TrapRmV86GenericCommon +CPU 8086 + ; + ; Fake EBP frame. + ; + mov ax, [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.rbp] + mov [bp], ax + + ; + ; Save the remaining GPRs and segment registers. + ; + test dx, dx + jnz .save_word_grps +CPU 386 + mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.rcx], ecx + mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.rdi], edi + mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.rsi], esi + mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.fs], fs + mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.gs], gs + jmp .save_segment_registers +.save_word_grps: +CPU 8086 + mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.rcx], cx + mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.rdi], di + mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.rsi], si +.save_segment_registers: + mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.ds], ds + mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.es], es + mov [ss:bx + BS3TRAPFRAME.uHandlerCs], cs + + ; + ; Load 16-bit BS3KIT_GRPNM_DATA16 into DS and ES so we can access globals. + ; + mov ax, BS3KIT_GRPNM_DATA16 + mov ds, ax + mov es, ax + + ; + ; Copy the mode now that we've got a flat DS. We don't need to update + ; it as it didn't change. + ; + mov al, [BS3_DATA16_WRT(g_bBs3CurrentMode)] + mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.bMode], al + + ; + ; Copy iret info. + ; + lea cx, [bp + 2] + mov [ss:bx + BS3TRAPFRAME.uHandlerRsp], cx + mov cx, [bp + 2] + mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.rip], cx + mov cx, [bp + 6] + mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.rflags], cx + mov cx, [bp + 4] + mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.cs], cx + mov cx, ss + mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.ss], cx + lea cx, [bp + 8] + mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.rsp], cx + mov byte [ss:bx + BS3TRAPFRAME.cbIretFrame], 3*2 + + ; The VM flag and CPL. + test al, BS3_MODE_CODE_V86 + jz .dont_set_vm + or byte [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.rflags + 2], X86_EFL_VM >> 16 + mov byte [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.bCpl], 3 +.dont_set_vm: + + + ; + ; Control registers. + ; + ; Since we're in real or v8086 here, we cannot save TR and LDTR. + ; But get MSW (CR0) first since that's always accessible and we + ; need it even on a 386 to check whether we're in v8086 mode or not. + ; + cmp byte [BS3_DATA16_WRT(g_uBs3CpuDetected)], BS3CPU_80286 + jb .skip_control_registers_because_80186_or_older +CPU 286 + smsw ax + mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.cr0], ax + + test dx, dx + jnz .set_flags +.save_386_control_registers: +CPU 386 + ; 386 control registers are not accessible from virtual 8086 mode. + test al, X86_CR0_PE + jnz .skip_crX_because_v8086 + mov eax, cr0 + mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.cr0], eax + mov eax, cr2 + mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.cr2], eax + mov eax, cr3 + mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.cr3], eax + + test byte [1 + BS3_DATA16_WRT(g_uBs3CpuDetected)], (BS3CPU_F_CPUID >> 8) ; CR4 first appeared in later 486es. + jz .skip_cr4_because_not_there + mov eax, cr4 + mov [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.cr4], eax + jmp .set_flags + +.skip_cr4_because_not_there: + mov byte [edi + BS3TRAPFRAME.Ctx + BS3REGCTX.fbFlags], BS3REG_CTX_F_NO_CR4 + jmp .set_flags + +CPU 8086 +.skip_control_registers_because_80186_or_older: +.skip_crX_because_v8086: + or byte [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.fbFlags], \ + BS3REG_CTX_F_NO_CR0_IS_MSW | BS3REG_CTX_F_NO_CR2_CR3 | BS3REG_CTX_F_NO_CR4 +.set_flags: ; The double fault code joins us here. + or byte [ss:bx + BS3TRAPFRAME.Ctx + BS3REGCTX.fbFlags], BS3REG_CTX_F_NO_AMD64 | BS3REG_CTX_F_NO_TR_LDTR + + ; + ; Dispatch it to C code. + ; +.dispatch_to_handler: + mov di, bx + mov bl, byte [ss:bx + BS3TRAPFRAME.bXcpt] + mov bh, 0 + shl bx, 1 + mov bx, [bx + BS3_DATA16_WRT(_g_apfnBs3TrapHandlers_c16)] + or bx, bx + jnz .call_handler + mov bx, Bs3TrapDefaultHandler +.call_handler: + push ss + push di + call bx + + ; + ; Resume execution using trap frame. + ; + xor ax, ax + push ax + push ss + add di, BS3TRAPFRAME.Ctx + push di + call Bs3RegCtxRestore +.panic: + hlt + jmp .panic +BS3_PROC_END bs3TrapRmV86GenericCommon + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-c32-Trap32Generic.asm b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-c32-Trap32Generic.asm new file mode 100644 index 00000000..c3899848 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-c32-Trap32Generic.asm @@ -0,0 +1,536 @@ +; $Id: bs3-c32-Trap32Generic.asm $ +;; @file +; BS3Kit - Trap, 32-bit assembly handlers. +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + +;********************************************************************************************************************************* +;* Header Files * +;********************************************************************************************************************************* +%include "bs3kit-template-header.mac" + +%ifndef TMPL_32BIT + %error "32-bit only template" +%endif + + +;********************************************************************************************************************************* +;* External Symbols * +;********************************************************************************************************************************* +BS3_EXTERN_DATA16 g_bBs3CurrentMode +BS3_EXTERN_DATA16 g_uBs3CpuDetected +BS3_EXTERN_DATA16 g_apfnBs3TrapHandlers_c32 +BS3_EXTERN_SYSTEM16 Bs3Gdt +TMPL_BEGIN_TEXT +BS3_EXTERN_CMN Bs3TrapDefaultHandler +BS3_EXTERN_CMN Bs3RegCtxRestore +TMPL_BEGIN_TEXT + + +;********************************************************************************************************************************* +;* Global Variables * +;********************************************************************************************************************************* +BS3_BEGIN_DATA16 +;; Easy to access flat address of Bs3Trap32GenericEntries. +BS3_GLOBAL_DATA g_Bs3Trap32GenericEntriesFlatAddr, 4 + dd Bs3Trap32GenericEntries wrt FLAT +;; Easy to access flat address of Bs3Trap32DoubleFaultHandler. +BS3_GLOBAL_DATA g_Bs3Trap32DoubleFaultHandlerFlatAddr, 4 + dd Bs3Trap32DoubleFaultHandler wrt FLAT + + +TMPL_BEGIN_TEXT + +;; +; Generic entry points for IDT handlers, 8 byte spacing. +; +BS3_PROC_BEGIN Bs3Trap32GenericEntries +%macro Bs3Trap32GenericEntryNoErr 1 + push byte 0 ; 2 byte: fake error code. + db 06ah, i ; 2 byte: push imm8 - note that this is a signextended value. + jmp near %1 ; 5 byte + ALIGNCODE(2) +%assign i i+1 +%endmacro + +%macro Bs3Trap32GenericEntryErrCd 1 + db 06ah, i ; 2 byte: push imm8 - note that this is a signextended value. + jmp near %1 ; 5 byte + db 0cch, 0cch ; 2 byte: padding. + ALIGNCODE(2) +%assign i i+1 +%endmacro + +%assign i 0 ; start counter. + Bs3Trap32GenericEntryNoErr bs3Trap32GenericTrapOrInt ; 0 + Bs3Trap32GenericEntryNoErr bs3Trap32GenericTrapOrInt ; 1 + Bs3Trap32GenericEntryNoErr bs3Trap32GenericTrapOrInt ; 2 + Bs3Trap32GenericEntryNoErr bs3Trap32GenericTrapOrInt ; 3 + Bs3Trap32GenericEntryNoErr bs3Trap32GenericTrapOrInt ; 4 + Bs3Trap32GenericEntryNoErr bs3Trap32GenericTrapOrInt ; 5 + Bs3Trap32GenericEntryNoErr bs3Trap32GenericTrapOrInt ; 6 + Bs3Trap32GenericEntryNoErr bs3Trap32GenericTrapOrInt ; 7 + Bs3Trap32GenericEntryErrCd bs3Trap32GenericTrapOrInt ; 8 + Bs3Trap32GenericEntryNoErr bs3Trap32GenericTrapOrInt ; 9 + Bs3Trap32GenericEntryErrCd bs3Trap32GenericTrapOrInt ; a + Bs3Trap32GenericEntryErrCd bs3Trap32GenericTrapOrInt ; b + Bs3Trap32GenericEntryErrCd bs3Trap32GenericTrapOrInt ; c + Bs3Trap32GenericEntryErrCd bs3Trap32GenericTrapOrInt ; d + Bs3Trap32GenericEntryErrCd bs3Trap32GenericTrapOrInt ; e + Bs3Trap32GenericEntryNoErr bs3Trap32GenericTrapOrInt ; f (reserved) + Bs3Trap32GenericEntryNoErr bs3Trap32GenericTrapOrInt ; 10 + Bs3Trap32GenericEntryErrCd bs3Trap32GenericTrapOrInt ; 11 + Bs3Trap32GenericEntryNoErr bs3Trap32GenericTrapOrInt ; 12 + Bs3Trap32GenericEntryNoErr bs3Trap32GenericTrapOrInt ; 13 + Bs3Trap32GenericEntryNoErr bs3Trap32GenericTrapOrInt ; 14 + Bs3Trap32GenericEntryNoErr bs3Trap32GenericTrapOrInt ; 15 (reserved) + Bs3Trap32GenericEntryNoErr bs3Trap32GenericTrapOrInt ; 16 (reserved) + Bs3Trap32GenericEntryNoErr bs3Trap32GenericTrapOrInt ; 17 (reserved) + Bs3Trap32GenericEntryNoErr bs3Trap32GenericTrapOrInt ; 18 (reserved) + Bs3Trap32GenericEntryNoErr bs3Trap32GenericTrapOrInt ; 19 (reserved) + Bs3Trap32GenericEntryNoErr bs3Trap32GenericTrapOrInt ; 1a (reserved) + Bs3Trap32GenericEntryNoErr bs3Trap32GenericTrapOrInt ; 1b (reserved) + Bs3Trap32GenericEntryNoErr bs3Trap32GenericTrapOrInt ; 1c (reserved) + Bs3Trap32GenericEntryNoErr bs3Trap32GenericTrapOrInt ; 1d (reserved) + Bs3Trap32GenericEntryErrCd bs3Trap32GenericTrapOrInt ; 1e + Bs3Trap32GenericEntryNoErr bs3Trap32GenericTrapOrInt ; 1f (reserved) +%rep 224 + Bs3Trap32GenericEntryNoErr bs3Trap32GenericTrapOrInt +%endrep +BS3_PROC_END Bs3Trap32GenericEntries +AssertCompile(Bs3Trap32GenericEntries_EndProc - Bs3Trap32GenericEntries == 10*256) + + +;; +; Trap or interrupt with error code, faked if necessary. +; +BS3_PROC_BEGIN bs3Trap32GenericTrapOrInt + push ebp ; 0 + mov ebp, esp + pushfd ; -04h + cld + push eax ; -08h + push edi ; -0ch + lea eax, [esp + (4+1+1)*4] ; 4 pushes above, 1 exception number push, 1 error code. + push eax ; -10h = handler ESP + add eax, 3*4 ; 3 dword iret frame + push eax ; -14h = caller ESP if same CPL + push ss ; -18h + push ds ; -1ch + + ; Make sure we've got a flat DS. It makes everything so much simpler. + mov ax, ss + and al, 3 + AssertCompile(BS3_SEL_RING_SHIFT == 8) + mov ah, al + add ax, BS3_SEL_R0_DS32 + mov ds, ax + + ; + ; We may be comming from 16-bit code with a 16-bit SS. Thunk it as + ; the C code may assume flat SS and we'll mess up by using EBP/ESP/EDI + ; instead of BP/SP/SS:DI. ASSUMES standard GDT selector. + ; + mov ax, ss + lar eax, ax + test eax, X86LAR_F_D + jz .stack_thunk + mov ax, ss + and al, 3 + AssertCompile(BS3_SEL_RING_SHIFT == 8) + mov ah, al + add ax, BS3_SEL_R0_SS32 + mov ss, ax + jmp .stack_flat +.stack_thunk: + mov di, ss + and edi, X86_SEL_MASK_OFF_RPL + mov al, [X86DESCGENERIC_BIT_OFF_BASE_HIGH1 / 8 + edi + Bs3Gdt wrt FLAT] + mov ah, [X86DESCGENERIC_BIT_OFF_BASE_HIGH2 / 8 + edi + Bs3Gdt wrt FLAT] + shl eax, 16 + mov ax, [X86DESCGENERIC_BIT_OFF_BASE_LOW / 8 + edi + Bs3Gdt wrt FLAT] ; eax = SS.base + movzx ebp, bp ; SS:BP -> flat EBP. + add ebp, eax + movzx edi, sp ; SS:SP -> flat ESP in EAX. + add edi, eax + mov ax, ss + and al, 3 + AssertCompile(BS3_SEL_RING_SHIFT == 8) + mov ah, al + add ax, BS3_SEL_R0_SS32 + mov ss, ax + mov esp, edi + sub dword [ebp - 10h], (4+1)*4 ; Recalc handler ESP in case of wraparound. + add word [ebp - 10h], (4+1)*4 + sub dword [ebp - 10h], (4+1+3)*4 ; Recalc caller ESP in case of wraparound. + add word [ebp - 10h], (4+1+3)*4 +.stack_flat: + + ; Reserve space for the register and trap frame. + mov eax, (BS3TRAPFRAME_size + 7) / 8 +AssertCompileSizeAlignment(BS3TRAPFRAME, 8) +.more_zeroed_space: + push dword 0 + push dword 0 + dec eax + jnz .more_zeroed_space + mov edi, esp ; edi points to trapframe structure. + + ; Copy stuff from the stack over. + mov eax, [ebp + 8] +;; @todo Do voodoo checks for 'int xx' or misguided hardware interrupts. + mov [edi + BS3TRAPFRAME.uErrCd], eax + mov al, [ebp + 4] + mov [edi + BS3TRAPFRAME.bXcpt], al + mov eax, [ebp] + mov [edi + BS3TRAPFRAME.Ctx + BS3REGCTX.rbp], eax + mov eax, [ebp - 04h] + mov [edi + BS3TRAPFRAME.fHandlerRfl], eax + mov eax, [ebp - 08h] + mov [edi + BS3TRAPFRAME.Ctx + BS3REGCTX.rax], eax + mov eax, [ebp - 0ch] + mov [edi + BS3TRAPFRAME.Ctx + BS3REGCTX.rdi], eax + mov eax, [ebp - 10h] + mov [edi + BS3TRAPFRAME.uHandlerRsp], eax + mov eax, [ebp - 14h] + mov [edi + BS3TRAPFRAME.Ctx + BS3REGCTX.rsp], eax + mov ax, [ebp - 18h] + mov [edi + BS3TRAPFRAME.Ctx + BS3REGCTX.ss], ax + mov [edi + BS3TRAPFRAME.uHandlerSs], ax + mov ax, [ebp - 1ch] + mov [edi + BS3TRAPFRAME.Ctx + BS3REGCTX.ds], ax + + lea ebp, [ebp + 8] ; iret - 4 (i.e. ebp frame chain location) + jmp bs3Trap32GenericCommon +BS3_PROC_END bs3Trap32GenericTrapErrCode + + +;; +; Common context saving code and dispatching. +; +; @param edi Pointer to the trap frame. The following members have been +; filled in by the previous code: +; - bXcpt +; - uErrCd +; - fHandlerRfl +; - uHandlerRsp +; - uHandlerSs +; - Ctx.rax +; - Ctx.rbp +; - Ctx.rdi +; - Ctx.rsp - assuming same CPL +; - Ctx.ds +; - Ctx.ss +; +; @param ebp Pointer to the dword before the iret frame, i.e. where ebp +; would be saved if this was a normal call. +; +; @remarks This is a separate function for hysterical raisins. +; +BS3_PROC_BEGIN bs3Trap32GenericCommon + ; + ; Fake EBP frame. + ; + mov eax, [edi + BS3TRAPFRAME.Ctx + BS3REGCTX.rbp] + mov [ebp], eax + + ; + ; Save the remaining GPRs and segment registers. + ; + mov [edi + BS3TRAPFRAME.Ctx + BS3REGCTX.rcx], ecx + mov [edi + BS3TRAPFRAME.Ctx + BS3REGCTX.rdx], edx + mov [edi + BS3TRAPFRAME.Ctx + BS3REGCTX.rbx], ebx + mov [edi + BS3TRAPFRAME.Ctx + BS3REGCTX.rsi], esi + mov [edi + BS3TRAPFRAME.Ctx + BS3REGCTX.es], es + mov [edi + BS3TRAPFRAME.Ctx + BS3REGCTX.fs], fs + mov [edi + BS3TRAPFRAME.Ctx + BS3REGCTX.gs], gs + + ; + ; Load 32-bit data selector for the DPL we're executing at into DS and ES. + ; Save the handler CS value first. + ; + mov ax, cs + mov [edi + BS3TRAPFRAME.uHandlerCs], ax + and al, 3 + AssertCompile(BS3_SEL_RING_SHIFT == 8) + mov ah, al + add ax, BS3_SEL_R0_DS32 + mov ds, ax + mov es, ax + + ; + ; Copy and update the mode now that we've got a flat DS. + ; + mov al, [BS3_DATA16_WRT(g_bBs3CurrentMode)] + mov [edi + BS3TRAPFRAME.Ctx + BS3REGCTX.bMode], al + and al, ~BS3_MODE_CODE_MASK + or al, BS3_MODE_CODE_32 + mov [BS3_DATA16_WRT(g_bBs3CurrentMode)], al + + ; + ; Copy iret info. + ; + mov ecx, [ebp + 4] + mov [edi + BS3TRAPFRAME.Ctx + BS3REGCTX.rip], ecx + mov ecx, [ebp + 12] + mov [edi + BS3TRAPFRAME.Ctx + BS3REGCTX.rflags], ecx + mov cx, [ebp + 8] + mov [edi + BS3TRAPFRAME.Ctx + BS3REGCTX.cs], cx + test dword [ebp + 12], X86_EFL_VM + jnz .iret_frame_v8086 + mov ax, ss + and al, 3 + and cl, 3 + mov [edi + BS3TRAPFRAME.Ctx + BS3REGCTX.bCpl], cl + cmp cl, al + je .iret_frame_same_cpl + +.iret_frame_different_cpl: + mov ecx, [ebp + 16] + mov [edi + BS3TRAPFRAME.Ctx + BS3REGCTX.rsp], ecx + mov cx, [ebp + 20] + mov [edi + BS3TRAPFRAME.Ctx + BS3REGCTX.ss], cx + mov byte [edi + BS3TRAPFRAME.cbIretFrame], 5*4 + jmp .iret_frame_done + +.iret_frame_v8086: + mov byte [edi + BS3TRAPFRAME.Ctx + BS3REGCTX.bCpl], 3 + or byte [edi + BS3TRAPFRAME.Ctx + BS3REGCTX.bMode], BS3_MODE_CODE_V86 ; paranoia ^ 2 + movzx ecx, word [ebp + 16] + mov [edi + BS3TRAPFRAME.Ctx + BS3REGCTX.rsp], ecx + mov cx, [ebp + 20] + mov [edi + BS3TRAPFRAME.Ctx + BS3REGCTX.ss], cx + mov cx, [ebp + 24] + mov [edi + BS3TRAPFRAME.Ctx + BS3REGCTX.es], cx + mov cx, [ebp + 28] + mov [edi + BS3TRAPFRAME.Ctx + BS3REGCTX.ds], cx + mov cx, [ebp + 32] + mov [edi + BS3TRAPFRAME.Ctx + BS3REGCTX.fs], cx + mov cx, [ebp + 36] + mov [edi + BS3TRAPFRAME.Ctx + BS3REGCTX.gs], cx + mov byte [edi + BS3TRAPFRAME.cbIretFrame], 9*4 + jmp .iret_frame_done + +.iret_frame_same_cpl: ; (caller already set SS:RSP and uHandlerRsp for same CPL iret frames) + mov byte [edi + BS3TRAPFRAME.cbIretFrame], 3*4 + +.iret_frame_done: + ; + ; Control registers. + ; + str ax + mov [edi + BS3TRAPFRAME.Ctx + BS3REGCTX.tr], ax + sldt ax + mov [edi + BS3TRAPFRAME.Ctx + BS3REGCTX.ldtr], ax + + mov ax, ss + test al, 3 + jnz .skip_crX_because_cpl_not_0 + + mov eax, cr3 + mov [edi + BS3TRAPFRAME.Ctx + BS3REGCTX.cr3], eax +.save_cr0_cr2_cr4: ; The double fault code joins us here. + mov eax, cr0 + mov [edi + BS3TRAPFRAME.Ctx + BS3REGCTX.cr0], eax + mov eax, cr2 + mov [edi + BS3TRAPFRAME.Ctx + BS3REGCTX.cr2], eax + + test byte [1 + BS3_DATA16_WRT(g_uBs3CpuDetected)], (BS3CPU_F_CPUID >> 8) ; CR4 first appeared in later 486es. + jz .skip_cr4_because_not_there + mov eax, cr4 + mov [edi + BS3TRAPFRAME.Ctx + BS3REGCTX.cr4], eax + jmp .set_flags + +.skip_cr4_because_not_there: + mov byte [edi + BS3TRAPFRAME.Ctx + BS3REGCTX.fbFlags], BS3REG_CTX_F_NO_CR4 + jmp .set_flags + +.skip_crX_because_cpl_not_0: + or byte [edi + BS3TRAPFRAME.Ctx + BS3REGCTX.fbFlags], \ + BS3REG_CTX_F_NO_CR0_IS_MSW | BS3REG_CTX_F_NO_CR2_CR3 | BS3REG_CTX_F_NO_CR4 + smsw [edi + BS3TRAPFRAME.Ctx + BS3REGCTX.cr0] +.set_flags: + or byte [edi + BS3TRAPFRAME.Ctx + BS3REGCTX.fbFlags], BS3REG_CTX_F_NO_AMD64 + + ; + ; Dispatch it to C code. + ; +.dispatch_to_handler: + movzx ebx, byte [edi + BS3TRAPFRAME.bXcpt] + mov eax, [ebx * 4 + BS3_DATA16_WRT(_g_apfnBs3TrapHandlers_c32)] + or eax, eax + jnz .call_handler + mov eax, Bs3TrapDefaultHandler +.call_handler: + push edi + call eax + + ; + ; Resume execution using trap frame. + ; + push 0 + add edi, BS3TRAPFRAME.Ctx + push edi + call Bs3RegCtxRestore +.panic: + hlt + jmp .panic +BS3_PROC_END bs3Trap32GenericCommon + + +;; +; Helper. +; +; @retruns Flat address in eax. +; @param ax +; @uses eax +; +bs3Trap32TssInAxToFlatInEax: + ; Get the GDT base address and find the descriptor address (EAX) + sub esp, 8+2 + sgdt [esp] + and eax, 0fff8h + add eax, [esp + 2] ; GDT base address. + add esp, 8+2 + + ; Get the flat TSS address from the descriptor. + mov al, [eax + (X86DESCGENERIC_BIT_OFF_BASE_HIGH1 / 8)] + mov ah, [eax + (X86DESCGENERIC_BIT_OFF_BASE_HIGH2 / 8)] + shl eax, 16 + mov ax, [eax + (X86DESCGENERIC_BIT_OFF_BASE_LOW / 8)] + ret + +;; +; Double fault handler. +; +; We don't have to load any selectors or clear anything in EFLAGS because the +; TSS specified sane values which got loaded during the task switch. +; +BS3_PROC_BEGIN Bs3Trap32DoubleFaultHandler + push 0 ; We'll copy the rip from the other TSS here later to create a more sensible call chain. + push ebp + mov ebp, esp + + pushfd ; Get handler flags. + pop ecx + + xor edx, edx ; NULL register. + + ; + ; Allocate a zero filled trap frame. + ; + mov eax, (BS3TRAPFRAME_size + 7) / 8 +AssertCompileSizeAlignment(BS3TRAPFRAME, 8) +.more_zeroed_space: + push edx + push edx + dec eax + jz .more_zeroed_space + mov edi, esp + + ; + ; Fill in the non-context trap frame bits. + ; + mov [edi + BS3TRAPFRAME.fHandlerRfl], ecx + mov word [edi + BS3TRAPFRAME.bXcpt], X86_XCPT_DF + mov [edi + BS3TRAPFRAME.uHandlerCs], cs + mov [edi + BS3TRAPFRAME.uHandlerSs], ss + lea ecx, [ebp + 3*4] ; two pushes, one error code. + mov [edi + BS3TRAPFRAME.uHandlerRsp], ecx + mov ecx, [ebp + 8] + mov [edi + BS3TRAPFRAME.uErrCd], ecx + + ; + ; Copy the register state from the previous task segment. + ; + + ; Find our TSS. + str ax + call bs3Trap32TssInAxToFlatInEax + + ; Find the previous TSS. + mov ax, [eax + X86TSS32.selPrev] + mov [edi + BS3TRAPFRAME.Ctx + BS3REGCTX.tr], ax + call bs3Trap32TssInAxToFlatInEax + + ; Do the copying. + mov ecx, [eax + X86TSS32.eax] + mov [edi + BS3TRAPFRAME.Ctx + BS3REGCTX.rax], ecx + mov ecx, [eax + X86TSS32.ecx] + mov [edi + BS3TRAPFRAME.Ctx + BS3REGCTX.rcx], ecx + mov ecx, [eax + X86TSS32.edx] + mov [edi + BS3TRAPFRAME.Ctx + BS3REGCTX.rdx], ecx + mov ecx, [eax + X86TSS32.ebx] + mov [edi + BS3TRAPFRAME.Ctx + BS3REGCTX.rbx], ecx + mov ecx, [eax + X86TSS32.esp] + mov [edi + BS3TRAPFRAME.Ctx + BS3REGCTX.rsp], ecx + mov ecx, [eax + X86TSS32.ebp] + mov [edi + BS3TRAPFRAME.Ctx + BS3REGCTX.rbp], ecx + mov [ebp], ecx ; For better call stacks. + mov ecx, [eax + X86TSS32.esi] + mov [edi + BS3TRAPFRAME.Ctx + BS3REGCTX.rsi], ecx + mov ecx, [eax + X86TSS32.edi] + mov [edi + BS3TRAPFRAME.Ctx + BS3REGCTX.rdi], ecx + mov ecx, [eax + X86TSS32.esi] + mov [edi + BS3TRAPFRAME.Ctx + BS3REGCTX.rsi], ecx + mov ecx, [eax + X86TSS32.eflags] + mov [edi + BS3TRAPFRAME.Ctx + BS3REGCTX.rflags], ecx + mov ecx, [eax + X86TSS32.eip] + mov [edi + BS3TRAPFRAME.Ctx + BS3REGCTX.rip], ecx + mov [ebp + 4], ecx ; For better call stacks. + mov cx, [eax + X86TSS32.cs] + mov [edi + BS3TRAPFRAME.Ctx + BS3REGCTX.cs], cx + mov cx, [eax + X86TSS32.ds] + mov [edi + BS3TRAPFRAME.Ctx + BS3REGCTX.ds], cx + mov cx, [eax + X86TSS32.es] + mov [edi + BS3TRAPFRAME.Ctx + BS3REGCTX.es], cx + mov cx, [eax + X86TSS32.fs] + mov [edi + BS3TRAPFRAME.Ctx + BS3REGCTX.fs], cx + mov cx, [eax + X86TSS32.gs] + mov [edi + BS3TRAPFRAME.Ctx + BS3REGCTX.gs], cx + mov cx, [eax + X86TSS32.ss] + mov [edi + BS3TRAPFRAME.Ctx + BS3REGCTX.ss], cx + mov cx, [eax + X86TSS32.selLdt] ; Note! This isn't necessarily the ldtr at the time of the fault. + mov [edi + BS3TRAPFRAME.Ctx + BS3REGCTX.ldtr], cx + mov cx, [eax + X86TSS32.cr3] ; Note! This isn't necessarily the cr3 at the time of the fault. + mov [edi + BS3TRAPFRAME.Ctx + BS3REGCTX.cr3], ecx + + ; + ; Set CPL; copy and update mode. + ; + mov cl, [edi + BS3TRAPFRAME.Ctx + BS3REGCTX.ss] + and cl, 3 + mov [edi + BS3TRAPFRAME.Ctx + BS3REGCTX.bCpl], cl + + mov cl, [BS3_DATA16_WRT(g_bBs3CurrentMode)] + mov [edi + BS3TRAPFRAME.Ctx + BS3REGCTX.bMode], cl + and cl, ~BS3_MODE_CODE_MASK + or cl, BS3_MODE_CODE_32 + mov [BS3_DATA16_WRT(g_bBs3CurrentMode)], cl + + ; + ; Join code paths with the generic handler code. + ; + jmp bs3Trap32GenericCommon.save_cr0_cr2_cr4 +BS3_PROC_END Bs3Trap32DoubleFaultHandler + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-c64-Trap64Generic.asm b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-c64-Trap64Generic.asm new file mode 100644 index 00000000..764e5987 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-c64-Trap64Generic.asm @@ -0,0 +1,327 @@ +; $Id: bs3-c64-Trap64Generic.asm $ +;; @file +; BS3Kit - Trap, 64-bit assembly handlers. +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + +;********************************************************************************************************************************* +;* Header Files * +;********************************************************************************************************************************* +%include "bs3kit-template-header.mac" + +%ifndef TMPL_64BIT + %error "64-bit only template" +%endif + + +;********************************************************************************************************************************* +;* External Symbols * +;********************************************************************************************************************************* +BS3_EXTERN_DATA16 g_bBs3CurrentMode +BS3_EXTERN_DATA16 g_apfnBs3TrapHandlers_c64 +TMPL_BEGIN_TEXT +BS3_EXTERN_CMN Bs3TrapDefaultHandler +BS3_EXTERN_CMN Bs3RegCtxRestore +TMPL_BEGIN_TEXT + + +;********************************************************************************************************************************* +;* Global Variables * +;********************************************************************************************************************************* +BS3_BEGIN_DATA16 +;; Easy to access flat address of Bs3Trap64GenericEntries. +BS3_GLOBAL_DATA g_Bs3Trap64GenericEntriesFlatAddr, 4 + dd Bs3Trap64GenericEntries wrt FLAT + + +TMPL_BEGIN_TEXT + +;; +; Generic entry points for IDT handlers, 8 byte spacing. +; +BS3_PROC_BEGIN Bs3Trap64GenericEntries +%macro Bs3Trap64GenericEntry 1 + db 06ah, i ; push imm8 - note that this is a signextended value. + jmp %1 + ALIGNCODE(8) +%assign i i+1 +%endmacro + +%assign i 0 ; start counter. + Bs3Trap64GenericEntry Bs3Trap64GenericTrapOrInt ; 0 + Bs3Trap64GenericEntry Bs3Trap64GenericTrapOrInt ; 1 + Bs3Trap64GenericEntry Bs3Trap64GenericTrapOrInt ; 2 + Bs3Trap64GenericEntry Bs3Trap64GenericTrapOrInt ; 3 + Bs3Trap64GenericEntry Bs3Trap64GenericTrapOrInt ; 4 + Bs3Trap64GenericEntry Bs3Trap64GenericTrapOrInt ; 5 + Bs3Trap64GenericEntry Bs3Trap64GenericTrapOrInt ; 6 + Bs3Trap64GenericEntry Bs3Trap64GenericTrapOrInt ; 7 + Bs3Trap64GenericEntry Bs3Trap64GenericTrapErrCode ; 8 + Bs3Trap64GenericEntry Bs3Trap64GenericTrapOrInt ; 9 + Bs3Trap64GenericEntry Bs3Trap64GenericTrapErrCode ; a + Bs3Trap64GenericEntry Bs3Trap64GenericTrapErrCode ; b + Bs3Trap64GenericEntry Bs3Trap64GenericTrapErrCode ; c + Bs3Trap64GenericEntry Bs3Trap64GenericTrapErrCode ; d + Bs3Trap64GenericEntry Bs3Trap64GenericTrapErrCode ; e + Bs3Trap64GenericEntry Bs3Trap64GenericTrapOrInt ; f (reserved) + Bs3Trap64GenericEntry Bs3Trap64GenericTrapOrInt ; 10 + Bs3Trap64GenericEntry Bs3Trap64GenericTrapErrCode ; 11 + Bs3Trap64GenericEntry Bs3Trap64GenericTrapOrInt ; 12 + Bs3Trap64GenericEntry Bs3Trap64GenericTrapOrInt ; 13 + Bs3Trap64GenericEntry Bs3Trap64GenericTrapOrInt ; 14 + Bs3Trap64GenericEntry Bs3Trap64GenericTrapOrInt ; 15 (reserved) + Bs3Trap64GenericEntry Bs3Trap64GenericTrapOrInt ; 16 (reserved) + Bs3Trap64GenericEntry Bs3Trap64GenericTrapOrInt ; 17 (reserved) + Bs3Trap64GenericEntry Bs3Trap64GenericTrapOrInt ; 18 (reserved) + Bs3Trap64GenericEntry Bs3Trap64GenericTrapOrInt ; 19 (reserved) + Bs3Trap64GenericEntry Bs3Trap64GenericTrapOrInt ; 1a (reserved) + Bs3Trap64GenericEntry Bs3Trap64GenericTrapOrInt ; 1b (reserved) + Bs3Trap64GenericEntry Bs3Trap64GenericTrapOrInt ; 1c (reserved) + Bs3Trap64GenericEntry Bs3Trap64GenericTrapOrInt ; 1d (reserved) + Bs3Trap64GenericEntry Bs3Trap64GenericTrapErrCode ; 1e + Bs3Trap64GenericEntry Bs3Trap64GenericTrapOrInt ; 1f (reserved) +%rep 224 + Bs3Trap64GenericEntry Bs3Trap64GenericTrapOrInt +%endrep +BS3_PROC_END Bs3Trap64GenericEntries + + + + +;; +; Trap or interrupt (no error code). +; +BS3_PROC_BEGIN Bs3Trap64GenericTrapOrInt + push rbp ; 0 + mov rbp, rsp + pushfq ; -08h + cld + push rdi + + ; Reserve space for the register and trap frame. + mov edi, (BS3TRAPFRAME_size + 15) / 16 +.more_zeroed_space: + push qword 0 + push qword 0 + dec edi + jnz .more_zeroed_space + mov rdi, rsp ; rdi points to trapframe structure. + + ; Free up rax. + mov [edi + BS3TRAPFRAME.Ctx + BS3REGCTX.rax], rax + + ; Copy stuff from the stack over. + mov al, [rbp + 08h] + mov [rdi + BS3TRAPFRAME.bXcpt], al + mov rax, [rbp] + mov [rdi + BS3TRAPFRAME.Ctx + BS3REGCTX.rbp], rax + mov rax, [rbp - 08h] + mov [rdi + BS3TRAPFRAME.fHandlerRfl], rax + mov rax, [rbp - 10h] + mov [rdi + BS3TRAPFRAME.Ctx + BS3REGCTX.rdi], rax + + lea rbp, [rbp + 08h] ; iret - 8 (i.e. rbp frame chain location) + jmp Bs3Trap64GenericCommon +BS3_PROC_END Bs3Trap64GenericTrapOrInt + + +;; +; Trap with error code. +; +BS3_PROC_BEGIN Bs3Trap64GenericTrapErrCode + push rbp ; 0 + mov rbp, rsp + pushfq ; -08h + cld + push rdi + + ; Reserve space for the register and trap frame. + mov edi, (BS3TRAPFRAME_size + 15) / 16 +.more_zeroed_space: + push qword 0 + push qword 0 + dec edi + jnz .more_zeroed_space + mov rdi, rsp ; rdi points to trapframe structure. + + ; Free up rax. + mov [edi + BS3TRAPFRAME.Ctx + BS3REGCTX.rax], rax + + ; Copy stuff from the stack over. + mov rax, [rbp + 10h] + mov [rdi + BS3TRAPFRAME.uErrCd], rax + mov al, [rbp + 08h] + mov [rdi + BS3TRAPFRAME.bXcpt], al + mov rax, [rbp] + mov [rdi + BS3TRAPFRAME.Ctx + BS3REGCTX.rbp], rax + mov rax, [rbp - 08h] + mov [rdi + BS3TRAPFRAME.fHandlerRfl], rax + mov rax, [rbp - 10h] + mov [rdi + BS3TRAPFRAME.Ctx + BS3REGCTX.rdi], rax + + lea rbp, [rbp + 10h] ; iret - 8 (i.e. rbp frame chain location) + jmp Bs3Trap64GenericCommon +BS3_PROC_END Bs3Trap64GenericTrapErrCode + + +;; +; Common context saving code and dispatching. +; +; @param rdi Pointer to the trap frame. The following members have been +; filled in by the previous code: +; - bXcpt +; - uErrCd +; - fHandlerRfl +; - Ctx.rax +; - Ctx.rbp +; - Ctx.rdi +; +; @param rbp Pointer to the dword before the iret frame, i.e. where rbp +; would be saved if this was a normal call. +; +BS3_PROC_BEGIN Bs3Trap64GenericCommon + ; + ; Fake RBP frame. + ; + mov rax, [rdi + BS3TRAPFRAME.Ctx + BS3REGCTX.rbp] + mov [rbp], rax + + ; + ; Save the remaining GPRs and segment registers. + ; + mov [rdi + BS3TRAPFRAME.Ctx + BS3REGCTX.rcx], rcx + mov [rdi + BS3TRAPFRAME.Ctx + BS3REGCTX.rdx], rdx + mov [rdi + BS3TRAPFRAME.Ctx + BS3REGCTX.rbx], rbx + mov [rdi + BS3TRAPFRAME.Ctx + BS3REGCTX.rsi], rsi + mov [rdi + BS3TRAPFRAME.Ctx + BS3REGCTX.r8 ], r8 + mov [rdi + BS3TRAPFRAME.Ctx + BS3REGCTX.r9 ], r9 + mov [rdi + BS3TRAPFRAME.Ctx + BS3REGCTX.r10], r10 + mov [rdi + BS3TRAPFRAME.Ctx + BS3REGCTX.r11], r11 + mov [rdi + BS3TRAPFRAME.Ctx + BS3REGCTX.r12], r12 + mov [rdi + BS3TRAPFRAME.Ctx + BS3REGCTX.r13], r13 + mov [rdi + BS3TRAPFRAME.Ctx + BS3REGCTX.r14], r14 + mov [rdi + BS3TRAPFRAME.Ctx + BS3REGCTX.r15], r15 + mov [rdi + BS3TRAPFRAME.Ctx + BS3REGCTX.ds], ds + mov [rdi + BS3TRAPFRAME.Ctx + BS3REGCTX.es], es + mov [rdi + BS3TRAPFRAME.Ctx + BS3REGCTX.fs], fs + mov [rdi + BS3TRAPFRAME.Ctx + BS3REGCTX.gs], gs + lea rax, [rbp + 8h] + mov [rdi + BS3TRAPFRAME.uHandlerRsp], rax + mov [rdi + BS3TRAPFRAME.uHandlerSs], ss + + ; + ; Load 32-bit data selector for the DPL we're executing at into DS, ES and SS. + ; Save the handler CS value first. + ; + mov ax, cs + mov [rdi + BS3TRAPFRAME.uHandlerCs], ax + AssertCompile(BS3_SEL_RING_SHIFT == 8) + and al, 3 + mov ah, al + add ax, BS3_SEL_R0_DS64 + mov ds, ax + mov es, ax + mov ss, ax + + ; + ; Copy and update the mode. + ; + mov al, [BS3_DATA16_WRT(g_bBs3CurrentMode)] + mov [rdi + BS3TRAPFRAME.Ctx + BS3REGCTX.bMode], al + and al, ~BS3_MODE_CODE_MASK + or al, BS3_MODE_CODE_64 + mov [BS3_DATA16_WRT(g_bBs3CurrentMode)], al + + ; + ; Copy iret info. Bless AMD for only doing one 64-bit iret frame layout. + ; + mov rcx, [rbp + 08] + mov [rdi + BS3TRAPFRAME.Ctx + BS3REGCTX.rip], rcx + mov cx, [rbp + 10h] + mov [rdi + BS3TRAPFRAME.Ctx + BS3REGCTX.cs], cx + and cl, 3 + mov [rdi + BS3TRAPFRAME.Ctx + BS3REGCTX.bCpl], cl + mov rcx, [rbp + 18h] + mov [rdi + BS3TRAPFRAME.Ctx + BS3REGCTX.rflags], rcx + mov rcx, [rbp + 20h] + mov [rdi + BS3TRAPFRAME.Ctx + BS3REGCTX.rsp], rcx + mov cx, [rbp + 28h] + mov [rdi + BS3TRAPFRAME.Ctx + BS3REGCTX.ss], cx + mov byte [rdi + BS3TRAPFRAME.cbIretFrame], 5*8 + + ; + ; Control registers. + ; + str ax + mov [rdi + BS3TRAPFRAME.Ctx + BS3REGCTX.tr], ax + sldt ax + mov [rdi + BS3TRAPFRAME.Ctx + BS3REGCTX.ldtr], ax + + mov ax, ss + test al, 3 + jnz .skip_crX_because_cpl_not_0 + + mov rax, cr0 + mov [rdi + BS3TRAPFRAME.Ctx + BS3REGCTX.cr0], rax + mov rax, cr2 + mov [rdi + BS3TRAPFRAME.Ctx + BS3REGCTX.cr2], rax + mov rax, cr3 + mov [rdi + BS3TRAPFRAME.Ctx + BS3REGCTX.cr3], rax + mov rax, cr4 + mov [rdi + BS3TRAPFRAME.Ctx + BS3REGCTX.cr4], rax + jmp .dispatch_to_handler + +.skip_crX_because_cpl_not_0: + or byte [rdi + BS3TRAPFRAME.Ctx + BS3REGCTX.fbFlags], \ + BS3REG_CTX_F_NO_CR0_IS_MSW | BS3REG_CTX_F_NO_CR2_CR3 | BS3REG_CTX_F_NO_CR4 + smsw [rdi + BS3TRAPFRAME.Ctx + BS3REGCTX.cr0] + + ; + ; Dispatch it to C code. + ; +.dispatch_to_handler: ; The double fault code joins us here. + movzx ebx, byte [rdi + BS3TRAPFRAME.bXcpt] + lea rax, [BS3_DATA16_WRT(_g_apfnBs3TrapHandlers_c64)] + mov rax, [rax + rbx * 8] + or rax, rax + jnz .call_handler + lea rax, [BS3_WRT_RIP(Bs3TrapDefaultHandler)] +.call_handler: + sub rsp, 20h + mov [rsp], rdi + mov rcx, rdi + call rax + + ; + ; Resume execution using trap frame. + ; + xor edx, edx ; fFlags + mov [rsp + 8], rdx + lea rcx, [rdi + BS3TRAPFRAME.Ctx] ; pCtx + mov [rsp], rcx + call Bs3RegCtxRestore +.panic: + hlt + jmp .panic +BS3_PROC_END Bs3Trap64GenericCommon + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-A20Disable.asm b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-A20Disable.asm new file mode 100644 index 00000000..0aa3d1ba --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-A20Disable.asm @@ -0,0 +1,105 @@ +; $Id: bs3-cmn-A20Disable.asm $ +;; @file +; BS3Kit - Bs3A20Disable. +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + +%include "bs3kit-template-header.mac" + + +BS3_EXTERN_CMN Bs3KbdWait +BS3_EXTERN_CMN Bs3KbdRead +BS3_EXTERN_CMN Bs3KbdWrite + + +;; +; Disables the A20 gate. +; +; @uses Nothing. +; +BS3_PROC_BEGIN_CMN Bs3A20Disable, BS3_PBC_HYBRID_0_ARGS + ; Must call both because they may be ORed together on real HW. +BONLY64 sub rsp, 20h + call BS3_CMN_NM(Bs3A20DisableViaKbd) + call BS3_CMN_NM(Bs3A20DisableViaPortA) +BONLY64 add rsp, 20h + BS3_HYBRID_RET +BS3_PROC_END_CMN Bs3A20Disable + + +;; +; Disables the A20 gate via control port A (PS/2 style). +; +; @uses Nothing. +; +BS3_PROC_BEGIN_CMN Bs3A20DisableViaPortA, BS3_PBC_HYBRID_0_ARGS + push xAX + + ; Use Control port A, assuming a PS/2 style system. + in al, 092h + test al, 02h + jz .done ; avoid trouble writing back the same value. + and al, 0fdh ; disable the A20 gate. + out 092h, al + +.done: + pop xAX + BS3_HYBRID_RET +BS3_PROC_END_CMN Bs3A20DisableViaPortA + + +;; +; Disables the A20 gate via the keyboard controller. +; +; @uses Nothing. +; +BS3_PROC_BEGIN_CMN Bs3A20DisableViaKbd, BS3_PBC_HYBRID_0_ARGS + push xBP + mov xBP, xSP + push xAX + pushf + cli +BONLY64 sub rsp, 20h + + call Bs3KbdWait + push 0d0h ; KBD_CCMD_READ_OUTPORT + call Bs3KbdRead + + and al, 0fdh ; ~2 + push xAX + push 0d1h ; KBD_CCMD_WRITE_OUTPORT + call Bs3KbdWrite + + add xSP, xCB*3 ; Clean up both the above calls. + + mov al, 0ffh ; KBD_CMD_RESET + out 64h, al + call Bs3KbdWait + +BONLY64 add rsp, 20h + popf + pop xAX + pop xBP + BS3_HYBRID_RET +BS3_PROC_END_CMN Bs3A20DisableViaKbd + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-A20Enable.asm b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-A20Enable.asm new file mode 100644 index 00000000..437c554f --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-A20Enable.asm @@ -0,0 +1,112 @@ +; $Id: bs3-cmn-A20Enable.asm $ +;; @file +; BS3Kit - Bs3A20Enable. +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + +%include "bs3kit-template-header.mac" + + +BS3_EXTERN_CMN Bs3KbdWait +BS3_EXTERN_CMN Bs3KbdRead +BS3_EXTERN_CMN Bs3KbdWrite + + +;; +; Enables the A20 gate. +; +; @uses Nothing. +; +BS3_PROC_BEGIN_CMN Bs3A20Enable, BS3_PBC_HYBRID_0_ARGS + push xBP + mov xBP, xSP +BONLY64 sub rsp, 20h + + call BS3_CMN_NM(Bs3A20EnableViaPortA) +;; @todo real 286 support +; call BS3_CMN_NM(Bs3A20EnableViaKbd) + + pop xBP + BS3_HYBRID_RET +BS3_PROC_END_CMN Bs3A20Enable + + +;; +; Enables the A20 gate via the keyboard controller. +; +; @uses Nothing. +; +BS3_PROC_BEGIN_CMN Bs3A20EnableViaKbd, BS3_PBC_HYBRID_0_ARGS + push xBP + mov xBP, xSP + push xAX + pushf + cli +BONLY64 sub rsp, 20h + + call Bs3KbdWait + push 0d0h ; KBD_CCMD_READ_OUTPORT + call Bs3KbdRead + + or al, 002h + push xAX + push 0d1h ; KBD_CCMD_WRITE_OUTPORT + call Bs3KbdWrite + + add xSP, xCB*3 ; both the above calls + + mov al, 0ffh ; KBD_CMD_RESET + out 64h, al + call Bs3KbdWait + +BONLY64 add rsp, 20h + popf + pop xAX + pop xBP + BS3_HYBRID_RET +BS3_PROC_END_CMN Bs3A20EnableViaKbd + + +;; +; Enables the A20 gate via control port A (PS/2 style). +; +; @uses Nothing. +; +BS3_PROC_BEGIN_CMN Bs3A20EnableViaPortA, BS3_PBC_HYBRID_0_ARGS + push xBP + mov xBP, xSP + push xAX + + ; Use Control port A, assuming a PS/2 style system. + in al, 092h + test al, 02h + jnz .done ; avoid trouble writing back the same value. + or al, 2 ; enable the A20 gate. + out 092h, al + +.done: + pop xAX + pop xBP + BS3_HYBRID_RET +BS3_PROC_END_CMN Bs3A20EnableViaPortA + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-ConvertRMStackToP16UsingCxReturnToAx.asm b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-ConvertRMStackToP16UsingCxReturnToAx.asm new file mode 100644 index 00000000..547f6191 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-ConvertRMStackToP16UsingCxReturnToAx.asm @@ -0,0 +1,78 @@ +; $Id: bs3-cmn-ConvertRMStackToP16UsingCxReturnToAx.asm $ +;; @file +; BS3Kit - Bs3ConvertRMStackToP16UsingCxReturnToAx. +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + +%include "bs3kit-template-header.mac" + + +%if TMPL_BITS != 16 + %error 16-bit only! +%endif + +;; +; An internal helper for converting a real-mode stack into a 16-bit protected +; mode stack. +; +; This is used by the mode switchers that ends up in 16-bit mode. It is +; assumed that we're in ring-0. +; +; @param ax The return address. +; +; @uses cx, ss, esp +; +BS3_PROC_BEGIN_CMN Bs3ConvertRMStackToP16UsingCxReturnToAx, BS3_PBC_NEAR + + ; + ; Check if it looks like the normal stack, if use BS3_SEL_R0_SS16. + ; + mov cx, ss + cmp cx, 0 + jne .stack_tiled + mov cx, BS3_SEL_R0_SS16 + mov ss, cx + jmp ax + + ; + ; Some custom stack address, just use the 16-bit tiled mappings + ; +.stack_tiled: +int3 ; debug this, shouldn't happen yet. Bs3EnteredMode_xxx isn't prepared. + shl cx, 4 + add sp, cx + mov cx, ss + jc .stack_carry + shr cx, 12 + jmp .stack_join_up_again +.stack_carry: + shr cx, 12 + inc cx +.stack_join_up_again: + shl cx, 3 + adc cx, BS3_SEL_TILED + mov ss, cx + jmp ax + +BS3_PROC_END_CMN Bs3ConvertRMStackToP16UsingCxReturnToAx + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-CpuDetectData.c b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-CpuDetectData.c new file mode 100644 index 00000000..ae2d0a00 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-CpuDetectData.c @@ -0,0 +1,44 @@ +/* $Id: bs3-cmn-CpuDetectData.c $ */ +/** @file + * BS3Kit - Detected CPU data. + */ + +/* + * Copyright (C) 2007-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include "bs3kit-template-header.h" +#include "bs3-cmn-test.h" + + +/********************************************************************************************************************************* +* Global Variables * +*********************************************************************************************************************************/ +#if ARCH_BITS == 16 + +uint16_t g_uBs3CpuDetected = BS3CPU_TYPE_MASK | BS3CPU_F_CPUID | BS3CPU_F_CPUID_EXT_LEAVES + | BS3CPU_F_PAE | BS3CPU_F_PSE | BS3CPU_F_LONG_MODE; + +#endif /* ARCH_BITS == 16 */ + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-ExtCtxAlloc.c b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-ExtCtxAlloc.c new file mode 100644 index 00000000..3017c59a --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-ExtCtxAlloc.c @@ -0,0 +1,44 @@ +/* $Id: bs3-cmn-ExtCtxAlloc.c $ */ +/** @file + * BS3Kit - Bs3ExtCtxAlloc + */ + +/* + * Copyright (C) 2007-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include "bs3kit-template-header.h" + + +#undef Bs3ExtCtxAlloc +BS3_CMN_DEF(PBS3EXTCTX, Bs3ExtCtxAlloc,(BS3MEMKIND enmKind)) +{ + uint64_t fFlags; + uint16_t cbExtCtx = Bs3ExtCtxGetSize(&fFlags); + PBS3EXTCTX pExtCtx = (PBS3EXTCTX)Bs3MemAlloc(enmKind, cbExtCtx); + if (pExtCtx) + return Bs3ExtCtxInit(pExtCtx, cbExtCtx, fFlags); + return NULL; +} + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-ExtCtxCopy.c b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-ExtCtxCopy.c new file mode 100644 index 00000000..39f3cae4 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-ExtCtxCopy.c @@ -0,0 +1,43 @@ +/* $Id: bs3-cmn-ExtCtxCopy.c $ */ +/** @file + * BS3Kit - Bs3ExtCtxCopy + */ + +/* + * Copyright (C) 2007-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include "bs3kit-template-header.h" +#include <iprt/asm-amd64-x86.h> + + +#undef Bs3ExtCtxCopy +BS3_CMN_DEF(PBS3EXTCTX, Bs3ExtCtxCopy,(PBS3EXTCTX pDst, PCBS3EXTCTX pSrc)) +{ + BS3_ASSERT(pDst->cb == pSrc->cb && pDst->enmMethod == pSrc->enmMethod && pDst->fXcr0Nominal == pSrc->fXcr0Nominal); + Bs3MemCpy(&pDst->Ctx, &pSrc->Ctx, pDst->cb - RT_UOFFSETOF(BS3EXTCTX, Ctx)); + pDst->fXcr0Saved = pSrc->fXcr0Saved; + return pDst; +} + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-ExtCtxFree.c b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-ExtCtxFree.c new file mode 100644 index 00000000..19169153 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-ExtCtxFree.c @@ -0,0 +1,46 @@ +/* $Id: bs3-cmn-ExtCtxFree.c $ */ +/** @file + * BS3Kit - Bs3ExtCtxFree + */ + +/* + * Copyright (C) 2007-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include "bs3kit-template-header.h" + + +#undef Bs3ExtCtxFree +BS3_CMN_DEF(void, Bs3ExtCtxFree,(PBS3EXTCTX pExtCtx)) +{ + if (pExtCtx) + { + if (pExtCtx->u16Magic == BS3EXTCTX_MAGIC) + { + pExtCtx->u16Magic = ~BS3EXTCTX_MAGIC; + Bs3MemFree(pExtCtx, pExtCtx->cb); + } + } +} + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-ExtCtxGetSize.c b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-ExtCtxGetSize.c new file mode 100644 index 00000000..d0960a26 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-ExtCtxGetSize.c @@ -0,0 +1,59 @@ +/* $Id: bs3-cmn-ExtCtxGetSize.c $ */ +/** @file + * BS3Kit - Bs3ExtCtxGetSize + */ + +/* + * Copyright (C) 2007-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include "bs3kit-template-header.h" +#include <iprt/asm-amd64-x86.h> + + +#undef Bs3ExtCtxGetSize +BS3_CMN_DEF(uint16_t, Bs3ExtCtxGetSize,(uint64_t BS3_FAR *pfFlags)) +{ + uint32_t fEcx, fEdx; + *pfFlags = 0; + + ASMCpuIdExSlow(1, 0, 0, 0, NULL, NULL, &fEcx, &fEdx); +#if 1 /* To disable xsave/xrstor till IEM groks it... */ + if (fEcx & X86_CPUID_FEATURE_ECX_XSAVE) + { + uint32_t fEax; + ASMCpuIdExSlow(13, 0, 0, 0, &fEax, NULL, &fEcx, &fEdx); + if ( fEcx >= sizeof(X86FXSTATE) + sizeof(X86XSAVEHDR) + && fEcx < _32K) + { + *pfFlags = fEax | ((uint64_t)fEdx << 32); + return RT_UOFFSETOF(BS3EXTCTX, Ctx) + RT_ALIGN(fEcx, 256); + } + } +#endif + if (fEdx & X86_CPUID_FEATURE_EDX_FXSR) + return RT_UOFFSETOF(BS3EXTCTX, Ctx) + sizeof(X86FXSTATE); + return RT_UOFFSETOF(BS3EXTCTX, Ctx) + sizeof(X86FPUSTATE); +} + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-ExtCtxInit.c b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-ExtCtxInit.c new file mode 100644 index 00000000..ea961885 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-ExtCtxInit.c @@ -0,0 +1,62 @@ +/* $Id: bs3-cmn-ExtCtxInit.c $ */ +/** @file + * BS3Kit - Bs3ExtCtxInit + */ + +/* + * Copyright (C) 2007-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include "bs3kit-template-header.h" +#include <iprt/asm-amd64-x86.h> + + +#undef Bs3ExtCtxInit +BS3_CMN_DEF(PBS3EXTCTX, Bs3ExtCtxInit,(PBS3EXTCTX pExtCtx, uint16_t cbExtCtx, uint64_t fFlags)) +{ + Bs3MemSet(pExtCtx, 0, cbExtCtx); + if (cbExtCtx >= RT_UOFFSETOF(BS3EXTCTX, Ctx) + sizeof(X86FXSTATE) + sizeof(X86XSAVEHDR)) + { + BS3_ASSERT(fFlags & XSAVE_C_X87); + pExtCtx->enmMethod = BS3EXTCTXMETHOD_XSAVE; + pExtCtx->Ctx.x.Hdr.bmXState = fFlags; + } + else if (cbExtCtx >= RT_UOFFSETOF(BS3EXTCTX, Ctx) + sizeof(X86FXSTATE)) + { + BS3_ASSERT(fFlags == 0); + pExtCtx->enmMethod = BS3EXTCTXMETHOD_FXSAVE; + } + else + { + BS3_ASSERT(fFlags == 0); + BS3_ASSERT(cbExtCtx >= RT_UOFFSETOF(BS3EXTCTX, Ctx) + sizeof(X86FPUSTATE)); + pExtCtx->enmMethod = BS3EXTCTXMETHOD_ANCIENT; + } + pExtCtx->cb = cbExtCtx; + pExtCtx->u16Magic = BS3EXTCTX_MAGIC; + pExtCtx->fXcr0Nominal = fFlags; + pExtCtx->fXcr0Saved = fFlags; + return pExtCtx; +} + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-ExtCtxRestore.asm b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-ExtCtxRestore.asm new file mode 100644 index 00000000..2a085be3 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-ExtCtxRestore.asm @@ -0,0 +1,124 @@ +; $Id: bs3-cmn-ExtCtxRestore.asm $ +;; @file +; BS3Kit - Bs3ExtCtxRestore. +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + +%include "bs3kit-template-header.mac" + + +;; +; Restores the extended CPU context (FPU, SSE, AVX, ++). +; +; @param pExtCtx +; +BS3_PROC_BEGIN_CMN Bs3ExtCtxRestore, BS3_PBC_NEAR + push xBP + mov xBP, xSP + push sAX + push sCX + push sDX + push xBX +BONLY16 push es + +%if ARCH_BITS == 16 + les bx, [xBP + xCB + cbCurRetAddr] + mov al, [es:bx + BS3EXTCTX.enmMethod] + cmp al, BS3EXTCTXMETHOD_XSAVE + je .do_16_xsave + cmp al, BS3EXTCTXMETHOD_FXSAVE + je .do_16_fxsave + cmp al, BS3EXTCTXMETHOD_ANCIENT + je .do_16_ancient + int3 + +.do_16_ancient: + frstor [es:bx + BS3EXTCTX.Ctx] + jmp .return + +.do_16_fxsave: + fxrstor [es:bx + BS3EXTCTX.Ctx] + jmp .return + +.do_16_xsave: + xor ecx, ecx + mov eax, [es:bx + BS3EXTCTX.fXcr0Nominal] + mov edx, [es:bx + BS3EXTCTX.fXcr0Nominal + 4] + xsetbv + + xrstor [es:bx + BS3EXTCTX.Ctx] + + mov eax, [es:bx + BS3EXTCTX.fXcr0Saved] + mov edx, [es:bx + BS3EXTCTX.fXcr0Saved + 4] + xsetbv + ;jmp .return + +%else +BONLY32 mov ebx, [xBP + xCB + cbCurRetAddr] +BONLY64 mov rbx, rcx + + mov al, [xBX + BS3EXTCTX.enmMethod] + cmp al, BS3EXTCTXMETHOD_XSAVE + je .do_xsave + cmp al, BS3EXTCTXMETHOD_FXSAVE + je .do_fxsave + cmp al, BS3EXTCTXMETHOD_ANCIENT + je .do_ancient + int3 + +.do_ancient: + frstor [xBX + BS3EXTCTX.Ctx] + jmp .return + +.do_fxsave: +BONLY32 fxrstor [xBX + BS3EXTCTX.Ctx] +BONLY64 fxrstor64 [xBX + BS3EXTCTX.Ctx] + jmp .return + +.do_xsave: + xor ecx, ecx + mov eax, [xBX + BS3EXTCTX.fXcr0Nominal] + mov edx, [xBX + BS3EXTCTX.fXcr0Nominal + 4] + xsetbv + +BONLY32 xrstor [xBX + BS3EXTCTX.Ctx] +BONLY64 xrstor64 [xBX + BS3EXTCTX.Ctx] + + mov eax, [xBX + BS3EXTCTX.fXcr0Saved] + mov edx, [xBX + BS3EXTCTX.fXcr0Saved + 4] + xsetbv + ;jmp .return + +%endif + +.return: +BONLY16 pop es + pop xBX + pop sDX + pop sCX + pop sAX + mov xSP, xBP + pop xBP + ret +BS3_PROC_END_CMN Bs3ExtCtxRestore + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-ExtCtxSave.asm b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-ExtCtxSave.asm new file mode 100644 index 00000000..0b9ea324 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-ExtCtxSave.asm @@ -0,0 +1,130 @@ +; $Id: bs3-cmn-ExtCtxSave.asm $ +;; @file +; BS3Kit - Bs3ExtCtxSave. +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + +%include "bs3kit-template-header.mac" + + +;; +; Saves the extended CPU context (FPU, SSE, AVX, ++). +; +; @param pExtCtx +; +BS3_PROC_BEGIN_CMN Bs3ExtCtxSave, BS3_PBC_NEAR + push xBP + mov xBP, xSP + push sAX + push sCX + push sDX + push xBX +BONLY16 push es + +%if ARCH_BITS == 16 + les bx, [xBP + xCB + cbCurRetAddr] + mov al, [es:bx + BS3EXTCTX.enmMethod] + cmp al, BS3EXTCTXMETHOD_XSAVE + je .do_16_xsave + cmp al, BS3EXTCTXMETHOD_FXSAVE + je .do_16_fxsave + cmp al, BS3EXTCTXMETHOD_ANCIENT + je .do_16_ancient + int3 + +.do_16_ancient: + fnsave [es:bx + BS3EXTCTX.Ctx] + jmp .return + +.do_16_fxsave: + fxsave [es:bx + BS3EXTCTX.Ctx] + jmp .return + +.do_16_xsave: + xor ecx, ecx + xgetbv + mov [es:bx + BS3EXTCTX.fXcr0Saved], eax + mov [es:bx + BS3EXTCTX.fXcr0Saved + 4], edx + mov eax, [es:bx + BS3EXTCTX.fXcr0Nominal] + mov edx, [es:bx + BS3EXTCTX.fXcr0Nominal + 4] + xsetbv + + xsave [es:bx + BS3EXTCTX.Ctx] + + mov eax, [es:bx + BS3EXTCTX.fXcr0Saved] + mov edx, [es:bx + BS3EXTCTX.fXcr0Saved + 4] + xsetbv + ;jmp .return + +%else +BONLY32 mov ebx, [xBP + xCB + cbCurRetAddr] +BONLY64 mov rbx, rcx + + mov al, [xBX + BS3EXTCTX.enmMethod] + cmp al, BS3EXTCTXMETHOD_XSAVE + je .do_xsave + cmp al, BS3EXTCTXMETHOD_FXSAVE + je .do_fxsave + cmp al, BS3EXTCTXMETHOD_ANCIENT + je .do_ancient + int3 + +.do_ancient: + fnsave [xBX + BS3EXTCTX.Ctx] + jmp .return + +.do_fxsave: +BONLY32 fxsave [xBX + BS3EXTCTX.Ctx] +BONLY64 fxsave64 [xBX + BS3EXTCTX.Ctx] + jmp .return + +.do_xsave: + xor ecx, ecx + xgetbv + mov [xBX + BS3EXTCTX.fXcr0Saved], eax + mov [xBX + BS3EXTCTX.fXcr0Saved + 4], edx + mov eax, [xBX + BS3EXTCTX.fXcr0Nominal] + mov edx, [xBX + BS3EXTCTX.fXcr0Nominal + 4] + xsetbv + +BONLY32 xsave [xBX + BS3EXTCTX.Ctx] +BONLY64 xsave64 [xBX + BS3EXTCTX.Ctx] + + mov eax, [xBX + BS3EXTCTX.fXcr0Saved] + mov edx, [xBX + BS3EXTCTX.fXcr0Saved + 4] + xsetbv + ;jmp .return + +%endif + +.return: +BONLY16 pop es + pop xBX + pop sDX + pop sCX + pop sAX + mov xSP, xBP + pop xBP + ret +BS3_PROC_END_CMN Bs3ExtCtxSave + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-GetCpuVendor.c b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-GetCpuVendor.c new file mode 100644 index 00000000..ac7328a5 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-GetCpuVendor.c @@ -0,0 +1,51 @@ +/* $Id: bs3-cmn-GetCpuVendor.c $ */ +/** @file + * BS3Kit - Bs3GetCpuVendor + */ + +/* + * Copyright (C) 2007-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + +#include "bs3kit-template-header.h" + +#include <iprt/asm-amd64-x86.h> + + +#undef Bs3GetCpuVendor +BS3_CMN_DEF(BS3CPUVENDOR, Bs3GetCpuVendor,(void)) +{ + if (g_uBs3CpuDetected & BS3CPU_F_CPUID) + { + uint32_t uEbx, uEcx, uEdx; + ASMCpuIdExSlow(0, 0, 0, 0, NULL, &uEbx, &uEcx, &uEdx); + if (ASMIsIntelCpuEx(uEbx, uEcx, uEdx)) + return BS3CPUVENDOR_INTEL; + if (ASMIsAmdCpuEx(uEbx, uEcx, uEdx)) + return BS3CPUVENDOR_AMD; + if (ASMIsViaCentaurCpuEx(uEbx, uEcx, uEdx)) + return BS3CPUVENDOR_VIA; + if (ASMIsShanghaiCpuEx(uEbx, uEcx, uEdx)) + return BS3CPUVENDOR_SHANGHAI; + return BS3CPUVENDOR_UNKNOWN; + } + return BS3CPUVENDOR_INTEL; +} + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-GetModeName.c b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-GetModeName.c new file mode 100644 index 00000000..0c4ae555 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-GetModeName.c @@ -0,0 +1,62 @@ +/* $Id: bs3-cmn-GetModeName.c $ */ +/** @file + * BS3Kit - Bs3GetModeName + */ + +/* + * Copyright (C) 2007-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + +#include "bs3kit-template-header.h" + + + +#undef Bs3GetModeName +BS3_CMN_DEF(const char BS3_FAR *, Bs3GetModeName,(uint8_t bMode)) +{ + switch (bMode) + { + case BS3_MODE_RM: return g_szBs3ModeName_rm; + case BS3_MODE_PE16: return g_szBs3ModeName_pe16; + case BS3_MODE_PE16_32: return g_szBs3ModeName_pe16_32; + case BS3_MODE_PE16_V86: return g_szBs3ModeName_pe16_v86; + case BS3_MODE_PE32: return g_szBs3ModeName_pe32; + case BS3_MODE_PE32_16: return g_szBs3ModeName_pe32_16; + case BS3_MODE_PEV86: return g_szBs3ModeName_pev86; + case BS3_MODE_PP16: return g_szBs3ModeName_pp16; + case BS3_MODE_PP16_32: return g_szBs3ModeName_pp16_32; + case BS3_MODE_PP16_V86: return g_szBs3ModeName_pp16_v86; + case BS3_MODE_PP32: return g_szBs3ModeName_pp32; + case BS3_MODE_PP32_16: return g_szBs3ModeName_pp32_16; + case BS3_MODE_PPV86: return g_szBs3ModeName_ppv86; + case BS3_MODE_PAE16: return g_szBs3ModeName_pae16; + case BS3_MODE_PAE16_32: return g_szBs3ModeName_pae16_32; + case BS3_MODE_PAE16_V86: return g_szBs3ModeName_pae16_v86; + case BS3_MODE_PAE32: return g_szBs3ModeName_pae32; + case BS3_MODE_PAE32_16: return g_szBs3ModeName_pae32_16; + case BS3_MODE_PAEV86: return g_szBs3ModeName_paev86; + case BS3_MODE_LM16: return g_szBs3ModeName_lm16; + case BS3_MODE_LM32: return g_szBs3ModeName_lm32; + case BS3_MODE_LM64: return g_szBs3ModeName_lm64; + case BS3_MODE_INVALID: return "invalid"; + default: return "unknow"; + } +} + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-GetModeNameShortLower.c b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-GetModeNameShortLower.c new file mode 100644 index 00000000..a372cc72 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-GetModeNameShortLower.c @@ -0,0 +1,62 @@ +/* $Id: bs3-cmn-GetModeNameShortLower.c $ */ +/** @file + * BS3Kit - Bs3GetModeNameShortLower + */ + +/* + * Copyright (C) 2007-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + +#include "bs3kit-template-header.h" + + + +#undef Bs3GetModeNameShortLower +BS3_CMN_DEF(const char BS3_FAR *, Bs3GetModeNameShortLower,(uint8_t bMode)) +{ + switch (bMode) + { + case BS3_MODE_RM: return g_szBs3ModeNameShortLower_rm; + case BS3_MODE_PE16: return g_szBs3ModeNameShortLower_pe16; + case BS3_MODE_PE16_32: return g_szBs3ModeNameShortLower_pe16_32; + case BS3_MODE_PE16_V86: return g_szBs3ModeNameShortLower_pe16_v86; + case BS3_MODE_PE32: return g_szBs3ModeNameShortLower_pe32; + case BS3_MODE_PE32_16: return g_szBs3ModeNameShortLower_pe32_16; + case BS3_MODE_PEV86: return g_szBs3ModeNameShortLower_pev86; + case BS3_MODE_PP16: return g_szBs3ModeNameShortLower_pp16; + case BS3_MODE_PP16_32: return g_szBs3ModeNameShortLower_pp16_32; + case BS3_MODE_PP16_V86: return g_szBs3ModeNameShortLower_pp16_v86; + case BS3_MODE_PP32: return g_szBs3ModeNameShortLower_pp32; + case BS3_MODE_PP32_16: return g_szBs3ModeNameShortLower_pp32_16; + case BS3_MODE_PPV86: return g_szBs3ModeNameShortLower_ppv86; + case BS3_MODE_PAE16: return g_szBs3ModeNameShortLower_pae16; + case BS3_MODE_PAE16_32: return g_szBs3ModeNameShortLower_pae16_32; + case BS3_MODE_PAE16_V86: return g_szBs3ModeNameShortLower_pae16_v86; + case BS3_MODE_PAE32: return g_szBs3ModeNameShortLower_pae32; + case BS3_MODE_PAE32_16: return g_szBs3ModeNameShortLower_pae32_16; + case BS3_MODE_PAEV86: return g_szBs3ModeNameShortLower_paev86; + case BS3_MODE_LM16: return g_szBs3ModeNameShortLower_lm16; + case BS3_MODE_LM32: return g_szBs3ModeNameShortLower_lm32; + case BS3_MODE_LM64: return g_szBs3ModeNameShortLower_lm64; + case BS3_MODE_INVALID: return "inv"; + default: return "unk"; + } +} + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-KbdRead.asm b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-KbdRead.asm new file mode 100644 index 00000000..a3569802 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-KbdRead.asm @@ -0,0 +1,65 @@ +; $Id: bs3-cmn-KbdRead.asm $ +;; @file +; BS3Kit - Bs3KbdRead. +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + +%include "bs3kit-template-header.mac" + + +;; +; Sends a read command to the keyboard controller and gets the result. +; +; The caller is responsible for making sure the keyboard controller is ready +; for a command (call Bs3KbdWait if unsure). +; +; @returns The value read is returned (in al). +; @param bCmd The read command. +; @uses al (obviously) +; +; @cproto BS3_DECL(uint8_t) Bs3KbdRead_c16(uint8_t bCmd); +; +BS3_PROC_BEGIN_CMN Bs3KbdRead, BS3_PBC_NEAR + push xBP + mov xBP, xSP + + mov al, [xBP + xCB*2] + out 64h, al ; Write the command. + +.check_status: + in al, 64h + test al, 1 ; KBD_STAT_OBF + jz .check_status + + in al, 60h ; Read the data. + + pop xBP + BS3_HYBRID_RET +BS3_PROC_END_CMN Bs3KbdRead + +; +; We may be using the near code in some critical code paths, so don't +; penalize it. +; +BS3_CMN_FAR_STUB Bs3KbdRead, 2 + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-KbdWait.asm b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-KbdWait.asm new file mode 100644 index 00000000..f4387330 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-KbdWait.asm @@ -0,0 +1,54 @@ +; $Id: bs3-cmn-KbdWait.asm $ +;; @file +; BS3Kit - Bs3KbdWait. +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + +%include "bs3kit-template-header.mac" + +;; +; Waits for the keyboard controller to become ready. +; +; @cproto BS3_DECL(void) Bs3KbdWait_c16(void); +; +BS3_PROC_BEGIN_CMN Bs3KbdWait, BS3_PBC_HYBRID_0_ARGS + push xBP + mov xBP, xSP + push xAX + +.check_status: + in al, 64h + test al, 1 ; KBD_STAT_OBF + jnz .read_data_and_status + test al, 2 ; KBD_STAT_IBF + jnz .check_status + + pop xAX + pop xBP + BS3_HYBRID_RET + +.read_data_and_status: + in al, 60h + jmp .check_status +BS3_PROC_END_CMN Bs3KbdWait + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-KbdWrite.asm b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-KbdWrite.asm new file mode 100644 index 00000000..0b5abb2e --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-KbdWrite.asm @@ -0,0 +1,72 @@ +; $Id: bs3-cmn-KbdWrite.asm $ +;; @file +; BS3Kit - Bs3KbdRead. +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + +%include "bs3kit-template-header.mac" + + +BS3_EXTERN_CMN Bs3KbdWait + + +;; +; Sends a write command to the keyboard controller and then sends the data. +; +; The caller is responsible for making sure the keyboard controller is ready +; for a command (call Bs3KbdWait if unsure). +; +; @param bCmd The write command. +; @param bData The data to write. +; @uses Nothing. +; +; @todo Return status? +; +; @cproto BS3_DECL(void) Bs3KbdWait_c16(uint8_t bCmd, uint8_t bData); +; +BS3_PROC_BEGIN_CMN Bs3KbdWrite, BS3_PBC_NEAR + push xBP + mov xBP, xSP + push xAX +BONLY64 sub rsp, 20h + + mov al, [xBP + xCB*2] + out 64h, al ; Write the command. + call Bs3KbdWait + + mov al, [xBP + xCB*3] + out 60h, al ; Write the data + call Bs3KbdWait + +BONLY64 add rsp, 20h + pop xAX + pop xBP + BS3_HYBRID_RET +BS3_PROC_END_CMN Bs3KbdWrite + +; +; We may be using the near code in some critical code paths, so don't +; penalize it. +; +BS3_CMN_FAR_STUB Bs3KbdWrite, 4 + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-MemAlloc.c b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-MemAlloc.c new file mode 100644 index 00000000..66740531 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-MemAlloc.c @@ -0,0 +1,101 @@ +/* $Id: bs3-cmn-MemAlloc.c $ */ +/** @file + * BS3Kit - Bs3MemAlloc + */ + +/* + * Copyright (C) 2007-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include "bs3kit-template-header.h" +#include "bs3-cmn-memory.h" +#include <iprt/asm.h> + + +#undef Bs3MemAlloc +BS3_CMN_DEF(void BS3_FAR *, Bs3MemAlloc,(BS3MEMKIND enmKind, size_t cb)) +{ + void BS3_FAR *pvRet; + uint8_t idxSlabList; + +#if ARCH_BITS == 16 + /* Don't try allocate memory which address we cannot return. */ + if ( enmKind != BS3MEMKIND_REAL + && BS3_MODE_IS_RM_OR_V86(g_bBs3CurrentMode)) + enmKind = BS3MEMKIND_REAL; +#endif + + idxSlabList = bs3MemSizeToSlabListIndex(cb); + if (idxSlabList < BS3_MEM_SLAB_LIST_COUNT) + { + /* + * Try allocate a chunk from the list. + */ + PBS3SLABHEAD pHead = enmKind == BS3MEMKIND_REAL + ? &g_aBs3LowSlabLists[idxSlabList] + : &g_aBs3UpperTiledSlabLists[idxSlabList]; + + BS3_ASSERT(g_aBs3LowSlabLists[idxSlabList].cbChunk >= cb); + pvRet = Bs3SlabListAlloc(pHead); + if (pvRet) + { /* likely */ } + else + { + /* + * Grow the list. + */ + PBS3SLABCTL pNew = (PBS3SLABCTL)Bs3SlabAlloc( enmKind == BS3MEMKIND_REAL + ? &g_Bs3Mem4KLow.Core + : &g_Bs3Mem4KUpperTiled.Core); + BS3_ASSERT(((uintptr_t)pNew & 0xfff) == 0); + if (pNew) + { + uint16_t const cbHdr = g_cbBs3SlabCtlSizesforLists[idxSlabList]; + BS3_XPTR_AUTO(void, pvNew); + BS3_XPTR_SET(void, pvNew, pNew); + + Bs3SlabInit(pNew, cbHdr, BS3_XPTR_GET_FLAT(void, pvNew) + cbHdr, _4K - cbHdr, pHead->cbChunk); + Bs3SlabListAdd(pHead, pNew); + + pvRet = Bs3SlabListAlloc(pHead); + } + } + } + else + { + /* + * Allocate one or more pages. + */ + size_t const cbAligned = RT_ALIGN_Z(cb, _4K); + uint16_t const cPages = cbAligned >> 12 /* div _4K */; + PBS3SLABCTL pSlabCtl = enmKind == BS3MEMKIND_REAL + ? &g_Bs3Mem4KLow.Core : &g_Bs3Mem4KUpperTiled.Core; + + pvRet = Bs3SlabAllocEx(pSlabCtl, + cPages, + cPages <= _64K / _4K ? BS3_SLAB_ALLOC_F_SAME_TILE : 0); + } + return pvRet; +} + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-MemAllocZ.c b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-MemAllocZ.c new file mode 100644 index 00000000..67dab84a --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-MemAllocZ.c @@ -0,0 +1,43 @@ +/* $Id: bs3-cmn-MemAllocZ.c $ */ +/** @file + * BS3Kit - Bs3MemAllocZ + */ + +/* + * Copyright (C) 2007-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include "bs3kit-template-header.h" +#include "bs3-cmn-memory.h" + + +#undef Bs3MemAllocZ +BS3_CMN_DEF(void BS3_FAR *, Bs3MemAllocZ,(BS3MEMKIND enmKind, size_t cb)) +{ + void BS3_FAR *pvRet = Bs3MemAlloc(enmKind, cb); + if (pvRet) + Bs3MemZero(pvRet, cb); + return pvRet; +} + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-MemChr.asm b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-MemChr.asm new file mode 100644 index 00000000..0b4d4236 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-MemChr.asm @@ -0,0 +1,78 @@ +; $Id: bs3-cmn-MemChr.asm $ +;; @file +; BS3Kit - Bs3MemChr. +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + +%include "bs3kit-template-header.mac" + +;; +; @cproto BS3_CMN_PROTO_NOSB(void BS3_FAR *, Bs3MemChr,(void BS3_FAR const *pvHaystack, uint8_t bNeedle, size_t cbHaystack)); +; +BS3_PROC_BEGIN_CMN Bs3MemChr, BS3_PBC_HYBRID + push xBP + mov xBP, xSP + push xDI +TONLY16 push es + +%if TMPL_BITS == 64 + + mov rdi, rcx ; rdi = pvHaystack + mov rcx, r8 ; rcx = cbHaystack + mov al, dl ; bNeedle + mov rcx, r8 + +%elif TMPL_BITS == 16 + mov di, [bp + 2 + cbCurRetAddr] ; pvHaystack.off + mov es, [bp + 2 + cbCurRetAddr + 2] ; pvHaystack.sel + mov al, [bp + 2 + cbCurRetAddr + 4] ; bNeedle + mov cx, [bp + 2 + cbCurRetAddr + 6] ; cbHaystack + +%elif TMPL_BITS == 32 + mov edi, [ebp + 8] ; pvHaystack + mov al, byte [ebp + 4 + cbCurRetAddr + 4] ; bNeedle + mov ecx, [ebp + 4 + cbCurRetAddr + 8] ; cbHaystack +%else + %error "TMPL_BITS!" +%endif + + cld + repne scasb + je .found + + xor xAX, xAX +TONLY16 xor dx, dx + +.return: +TONLY16 pop es + pop xDI + pop xBP + BS3_HYBRID_RET + +.found: + lea xAX, [xDI - 1] +TONLY16 mov dx, es + jmp .return + +BS3_PROC_END_CMN Bs3MemChr + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-MemCmp.asm b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-MemCmp.asm new file mode 100644 index 00000000..86fd52f6 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-MemCmp.asm @@ -0,0 +1,89 @@ +; $Id: bs3-cmn-MemCmp.asm $ +;; @file +; BS3Kit - Bs3MemCmp. +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + +%include "bs3kit-template-header.mac" + +;; +; @cproto BS3_CMN_PROTO_NOSB(int, Bs3MemCmp,(void const BS3_FAR *pv1, void const BS3_FAR *pv2, size_t cb)); +; +BS3_PROC_BEGIN_CMN Bs3MemCmp, BS3_PBC_HYBRID +TONLY16 CPU 8086 + push xBP + mov xBP, xSP + push xDI + push xSI +TNOT64 push es +TONLY16 push ds + cld + + ; + ; To save complexity and space, do straight forward byte compares. + ; +%if TMPL_BITS == 16 + mov di, [bp + 2 + cbCurRetAddr] ; pv1.off + mov es, [bp + 2 + cbCurRetAddr + 2] ; pv1.sel + mov si, [bp + 2 + cbCurRetAddr + 4] ; pv2.off + mov ds, [bp + 2 + cbCurRetAddr + 6] ; pv2.sel + mov cx, [bp + 2 + cbCurRetAddr + 8] ; cbDst + xor ax, ax + repe cmpsb + je .return + + mov al, [es:di - 1] + xor dx, dx + mov dl, [esi - 1] + sub ax, dx + +%else + %if TMPL_BITS == 64 + mov rdi, rcx ; rdi = pv1 + mov rsi, rdx ; rdi = pv2 + mov rcx, r8 ; rcx = cbDst + %else + mov ax, ds + mov es, ax ; paranoia + mov edi, [ebp + 4 + cbCurRetAddr] ; pv1 + mov esi, [ebp + 4 + cbCurRetAddr + 4] ; pv2 + mov ecx, [ebp + 4 + cbCurRetAddr + 8] ; cbDst + %endif + xor eax, eax + repe cmpsb + je .return + + mov al, [xDI - 1] + movzx edx, byte [xSI - 1] + sub eax, edx +%endif + +.return: +TONLY16 pop ds +TNOT64 pop es + pop xSI + pop xDI + pop xBP + BS3_HYBRID_RET +BS3_PROC_END_CMN Bs3MemCmp + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-MemCpy.c b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-MemCpy.c new file mode 100644 index 00000000..8e1d35e9 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-MemCpy.c @@ -0,0 +1,75 @@ +/* $Id: bs3-cmn-MemCpy.c $ */ +/** @file + * BS3Kit - Bs3MemCpy + */ + +/* + * Copyright (C) 2007-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + +#include "bs3kit-template-header.h" + +#undef Bs3MemCpy +BS3_CMN_DEF(void BS3_FAR *, Bs3MemCpy,(void BS3_FAR *pvDst, const void BS3_FAR *pvSrc, size_t cbToCopy)) +{ +#if 1 + const size_t BS3_FAR *pBigSrc = (const size_t BS3_FAR *)pvSrc; + size_t BS3_FAR *pBigDst = (size_t *)pvDst; + size_t cBig = cbToCopy / sizeof(size_t); + while (cBig-- > 0) + *pBigDst++ = *pBigSrc++; + + switch (cbToCopy % sizeof(size_t)) + { +#if TMPL_BITS >= 64 + case 7: ((uint8_t BS3_FAR *)pBigDst)[6] = ((const uint8_t BS3_FAR *)pBigSrc)[6]; + case 6: ((uint8_t BS3_FAR *)pBigDst)[5] = ((const uint8_t BS3_FAR *)pBigSrc)[5]; + case 5: ((uint8_t BS3_FAR *)pBigDst)[4] = ((const uint8_t BS3_FAR *)pBigSrc)[4]; + case 4: ((uint8_t BS3_FAR *)pBigDst)[3] = ((const uint8_t BS3_FAR *)pBigSrc)[3]; +#endif +#if TMPL_BITS >= 32 + case 3: ((uint8_t BS3_FAR *)pBigDst)[2] = ((const uint8_t BS3_FAR *)pBigSrc)[2]; + case 2: ((uint8_t BS3_FAR *)pBigDst)[1] = ((const uint8_t BS3_FAR *)pBigSrc)[1]; +#endif + case 1: ((uint8_t BS3_FAR *)pBigDst)[0] = ((const uint8_t BS3_FAR *)pBigSrc)[0]; + case 0: + break; + } + +#else + size_t cLargeRounds; + BS3CPTRUNION uSrc; + BS3PTRUNION uDst; + uSrc.pv = pvSrc; + uDst.pv = pvDst; + + cLargeRounds = cbToCopy / sizeof(*uSrc.pcb); + while (cLargeRounds-- > 0) + *uDst.pcb++ = *uSrc.pcb++; + + cbToCopy %= sizeof(*uSrc.pcb); + while (cbToCopy-- > 0) + *uDst.pb++ = *uSrc.pb++; + +#endif + + return pvDst; +} + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-MemFree.c b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-MemFree.c new file mode 100644 index 00000000..afbad309 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-MemFree.c @@ -0,0 +1,63 @@ +/* $Id: bs3-cmn-MemFree.c $ */ +/** @file + * BS3Kit - Bs3MemFree + */ + +/* + * Copyright (C) 2007-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include "bs3kit-template-header.h" +#include "bs3-cmn-memory.h" + + +#undef Bs3MemFree +BS3_CMN_DEF(void, Bs3MemFree,(void BS3_FAR *pv, size_t cb)) +{ + if (pv != NULL) + { + uint16_t cChunks; + PBS3SLABCTL pCtl; + BS3_XPTR_AUTO(void, pvFlat); + BS3_XPTR_SET(void, pvFlat, pv); + + if (BS3_XPTR_GET_FLAT(void, pvFlat) & 0xfffU) + { + /* Use an XPTR here in case we're in real mode and the caller has + messed around with the pointer. */ + BS3_XPTR_AUTO(BS3SLABCTL, pTmp); + BS3_XPTR_SET_FLAT(BS3SLABCTL, pTmp, BS3_XPTR_GET_FLAT(void, pvFlat) & ~(uint32_t)0xfff); + pCtl = BS3_XPTR_GET(BS3SLABCTL, pTmp); + BS3_ASSERT(pCtl->cbChunk >= cb); + cChunks = 1; + } + else + { + pCtl = BS3_XPTR_GET_FLAT(void, pvFlat) < _1M ? &g_Bs3Mem4KLow.Core : &g_Bs3Mem4KUpperTiled.Core; + cChunks = RT_ALIGN_Z(cb, _4K) >> 12; + } + Bs3SlabFree(pCtl, BS3_XPTR_GET_FLAT(void, pvFlat), cChunks); + } +} + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-MemGuardedTestPage.c b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-MemGuardedTestPage.c new file mode 100644 index 00000000..7991295c --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-MemGuardedTestPage.c @@ -0,0 +1,99 @@ +/* $Id: bs3-cmn-MemGuardedTestPage.c $ */ +/** @file + * BS3Kit - Bs3MemGuardedTestPageAlloc, Bs3MemGuardedTestPageFree + */ + +/* + * Copyright (C) 2007-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include "bs3kit-template-header.h" +#include "iprt/asm.h" + + +#undef Bs3MemGuardedTestPageAllocEx +BS3_CMN_PROTO_STUB(void BS3_FAR *, Bs3MemGuardedTestPageAllocEx,(BS3MEMKIND enmKind, uint64_t fPte)) +{ + uint8_t BS3_FAR *pb = (uint8_t BS3_FAR *)Bs3MemAlloc(enmKind, X86_PAGE_4K_SIZE * 3); + if (pb) + { + int rc; + + Bs3MemSet(pb, 0xcc, X86_PAGE_4K_SIZE); + Bs3MemSet(&pb[X86_PAGE_4K_SIZE], 0x00, X86_PAGE_4K_SIZE); + Bs3MemSet(&pb[X86_PAGE_4K_SIZE*2], 0xaa, X86_PAGE_4K_SIZE); + + rc = Bs3PagingProtectPtr(pb, X86_PAGE_4K_SIZE, fPte, UINT64_MAX & ~fPte); + if (RT_SUCCESS(rc)) + { + rc = Bs3PagingProtectPtr(&pb[X86_PAGE_4K_SIZE*2], X86_PAGE_4K_SIZE, fPte, UINT64_MAX & ~fPte); + if (RT_SUCCESS(rc)) + return pb + X86_PAGE_4K_SIZE; + + Bs3TestPrintf("warning: Bs3MemGuardedTestPageAlloc - Tail protect error %d (mode %#x)\n", rc, g_bBs3CurrentMode); + Bs3PagingProtectPtr(pb, X86_PAGE_4K_SIZE, X86_PTE_P, 0); + } + else + Bs3TestPrintf("warning: Bs3MemGuardedTestPageAlloc - Head protect error %d (mode %#x)\n", rc, g_bBs3CurrentMode); + Bs3MemFree(pb, X86_PAGE_4K_SIZE * 3); + } + else + Bs3TestPrintf("warning: Bs3MemGuardedTestPageAlloc - out of memory (mode %#x)\n", g_bBs3CurrentMode); + return NULL; +} + + +#undef Bs3MemGuardedTestPageAlloc +BS3_CMN_DEF(void BS3_FAR *, Bs3MemGuardedTestPageAlloc,(BS3MEMKIND enmKind)) +{ + return BS3_CMN_FAR_NM(Bs3MemGuardedTestPageAllocEx)(enmKind, 0); +} + + +#undef Bs3MemGuardedTestPageFree +BS3_CMN_DEF(void, Bs3MemGuardedTestPageFree,(void BS3_FAR *pvGuardedPage)) +{ + if (pvGuardedPage) + { + uint8_t BS3_FAR *pbGuardViolation; + uint8_t BS3_FAR *pb = (uint8_t BS3_FAR *)pvGuardedPage - X86_PAGE_4K_SIZE; + Bs3PagingProtectPtr(pb, X86_PAGE_4K_SIZE, + X86_PTE_P | X86_PTE_RW | X86_PTE_US | X86_PTE_A | X86_PTE_D, UINT64_MAX); + Bs3PagingProtectPtr(&pb[X86_PAGE_4K_SIZE*2], X86_PAGE_4K_SIZE, + X86_PTE_P | X86_PTE_RW | X86_PTE_US | X86_PTE_A | X86_PTE_D, UINT64_MAX); + + pbGuardViolation = ASMMemFirstMismatchingU8(pb, X86_PAGE_4K_SIZE, 0xcc); + if (pbGuardViolation) + Bs3TestFailedF("Leading guard page touched: byte %#05x is %#04x instead of 0xcc\n", + (unsigned)(uintptr_t)(pbGuardViolation - pb), *pbGuardViolation); + + pbGuardViolation = ASMMemFirstMismatchingU8(&pb[X86_PAGE_4K_SIZE*2], X86_PAGE_4K_SIZE, 0xaa); + if (pbGuardViolation) + Bs3TestFailedF("Trailing guard page touched: byte %#05x is %#04x instead of 0xaa\n", + (unsigned)(uintptr_t)(pbGuardViolation - &pb[X86_PAGE_4K_SIZE*2]), *pbGuardViolation); + + Bs3MemFree(pb, X86_PAGE_4K_SIZE * 3); + } +} + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-MemMove.c b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-MemMove.c new file mode 100644 index 00000000..25a5cbfa --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-MemMove.c @@ -0,0 +1,78 @@ +/* $Id: bs3-cmn-MemMove.c $ */ +/** @file + * BS3Kit - Bs3MemMove + */ + +/* + * Copyright (C) 2007-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + +#include "bs3kit-template-header.h" + +#undef Bs3MemMove +BS3_CMN_DEF(void BS3_FAR *, Bs3MemMove,(void BS3_FAR *pvDst, const void BS3_FAR *pvSrc, size_t cbToCopy)) +{ + size_t cLargeRounds; + BS3CVPTRUNION uSrc; + BS3PTRUNION uDst; + uSrc.pv = pvSrc; + uDst.pv = pvDst; + + /* We don't care about segment wrapping here. */ + if ((uintptr_t)pvDst > (uintptr_t)pvSrc + cbToCopy) + { + /* Reverse copy. */ + uSrc.pb += cbToCopy; + uDst.pb += cbToCopy; + + cLargeRounds = cbToCopy / sizeof(*uSrc.pcb); + while (cLargeRounds-- > 0) + { + size_t uTmp = *--uSrc.pcb; + *--uDst.pcb = uTmp; + } + + cbToCopy %= sizeof(*uSrc.pcb); + while (cbToCopy-- > 0) + { + uint8_t b = *--uSrc.pb; + *--uDst.pb = b; + } + } + else + { + /* Forward copy. */ + cLargeRounds = cbToCopy / sizeof(*uSrc.pcb); + while (cLargeRounds-- > 0) + { + size_t uTmp = *uSrc.pcb++; + *uDst.pcb++ = uTmp; + } + + cbToCopy %= sizeof(*uSrc.pcb); + while (cbToCopy-- > 0) + { + uint8_t b = *uSrc.pb++; + *uDst.pb++ = b; + } + } + return pvDst; +} + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-MemPCpy.c b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-MemPCpy.c new file mode 100644 index 00000000..730b3aea --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-MemPCpy.c @@ -0,0 +1,48 @@ +/* $Id: bs3-cmn-MemPCpy.c $ */ +/** @file + * BS3Kit - Bs3MemPCpy + */ + +/* + * Copyright (C) 2007-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + +#include "bs3kit-template-header.h" + +#undef Bs3MemPCpy +BS3_CMN_DEF(void BS3_FAR *, Bs3MemPCpy,(void BS3_FAR *pvDst, const void BS3_FAR *pvSrc, size_t cbToCopy)) +{ + size_t cLargeRounds; + BS3CPTRUNION uSrc; + BS3PTRUNION uDst; + uSrc.pv = pvSrc; + uDst.pv = pvDst; + + cLargeRounds = cbToCopy / sizeof(*uSrc.pcb); + while (cLargeRounds-- > 0) + *uDst.pcb++ = *uSrc.pcb++; + + cbToCopy %= sizeof(*uSrc.pcb); + while (cbToCopy-- > 0) + *uDst.pb++ = *uSrc.pb++; + + return uDst.pv; +} + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-MemPrintInfo.c b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-MemPrintInfo.c new file mode 100644 index 00000000..d996ab8c --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-MemPrintInfo.c @@ -0,0 +1,85 @@ +/* $Id: bs3-cmn-MemPrintInfo.c $ */ +/** @file + * BS3Kit - Bs3MemPrintInfo + */ + +/* + * Copyright (C) 2007-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include "bs3kit-template-header.h" +#include "bs3-cmn-memory.h" +#include <iprt/asm.h> + + +/** + * Prints a slab control structure with allocation map. + * + * @param pCtl The slab control structure to print. + * @param pszPrefix The output prefix. + */ +static void Bs3MemPrintInfoSlabCtl(PBS3SLABCTL pCtl, const char BS3_FAR *pszPrefix) +{ + unsigned iChunk; + Bs3TestPrintf("%s / %#06x: %u of %u chunks free", pszPrefix, pCtl->cbChunk, pCtl->cFreeChunks, pCtl->cChunks); + for (iChunk = 0; iChunk < pCtl->cChunks; iChunk++) + { + if ((iChunk & 63) == 0) + Bs3TestPrintf("\n%s:", pszPrefix); + if (ASMBitTest(pCtl->bmAllocated, iChunk)) + Bs3TestPrintf((iChunk & 7) != 0 ? "x" : " x"); + else + Bs3TestPrintf((iChunk & 7) != 0 ? "-" : " -"); + } + Bs3TestPrintf("\n"); +} + + + +/** + * Prints a summary of a slab allocation list (i.e. the heap). + * + * @param paLists Array of BS3_MEM_SLAB_LIST_COUNT lists. + * @param pszPrefix The output prefix. + */ +static void Bs3MemPrintInfoSlabList(PBS3SLABHEAD paLists, const char BS3_FAR *pszPrefix) +{ + unsigned iSlab; + for (iSlab = 0; iSlab < BS3_MEM_SLAB_LIST_COUNT; iSlab++) + if (paLists[iSlab].cSlabs) + Bs3TestPrintf("%s / %#06x: %u slabs, %RU32 of %RU32 chunks free\n", + pszPrefix, paLists[iSlab].cbChunk, paLists[iSlab].cSlabs, + paLists[iSlab].cFreeChunks, paLists[iSlab].cChunks); +} + + +#undef Bs3MemPrintInfo +BS3_CMN_DEF(void, Bs3MemPrintInfo,(void)) +{ + Bs3MemPrintInfoSlabList(g_aBs3LowSlabLists, "Lower"); + Bs3MemPrintInfoSlabList(g_aBs3LowSlabLists, "Upper"); + Bs3MemPrintInfoSlabCtl(&g_Bs3Mem4KLow.Core, "4KLow"); + Bs3MemPrintInfoSlabCtl(&g_Bs3Mem4KUpperTiled.Core, "Tiled"); +} + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-MemSet.asm b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-MemSet.asm new file mode 100644 index 00000000..635e7dde --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-MemSet.asm @@ -0,0 +1,92 @@ +; $Id: bs3-cmn-MemSet.asm $ +;; @file +; BS3Kit - Bs3MemSet. +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + +%include "bs3kit-template-header.mac" + +;; +; @cproto BS3_CMN_PROTO_NOSB(void, Bs3MemSet,(void BS3_FAR *pvDst, uint8_t bFiller, size_t cbDst)); +; +BS3_PROC_BEGIN_CMN Bs3MemSet, BS3_PBC_HYBRID + push xBP + mov xBP, xSP + push xDI +%ifdef RT_ARCH_AMD64 + + mov rdi, rcx ; rdi = pvDst + mov rcx, r8 ; rcx = cbDst + movzx edx, dl ; bFiller + mov rax, 0101010101010101h + mul rdx + mov rcx, r8 + shr rcx, 3 ; calc qword count. + cld + rep stosq + + mov rcx, r8 ; cbDst + and rcx, 7 ; calc trailing byte count. + rep stosb + +%elif ARCH_BITS == 16 + push es + + mov di, [bp + 2 + cbCurRetAddr] ; pvDst.off + mov es, [bp + 2 + cbCurRetAddr + 2] ; pvDst.sel + mov al, [bp + 2 + cbCurRetAddr + 4] ; bFiller + mov ah, al + mov cx, [bp + 2 + cbCurRetAddr + 6] ; cbDst + shr cx, 1 ; calc dword count. + rep stosw + + mov cx, [bp + 2 + cbCurRetAddr + 6] ; cbDst + and cx, 1 ; calc tailing byte count. + rep stosb + + pop es + +%elif ARCH_BITS == 32 + mov edi, [ebp + 8] ; pvDst + mov al, byte [ebp + 4 + cbCurRetAddr + 4] ; bFiller + mov ah, al + mov dx, ax + shl eax, 16 + mov ax, dx ; eax = RT_MAKE_U32_FROM_U8(bFiller, bFiller, bFiller, bFiller) + mov ecx, [ebp + 4 + cbCurRetAddr + 8] ; cbDst + shr cx, 2 ; calc dword count. + rep stosd + + mov ecx, [ebp + 4 + cbCurRetAddr + 8] ; cbDst + and ecx, 3 ; calc tailing byte count. + rep stosb + +%else + %error "Unknown bitness." +%endif + + pop xDI + pop xBP + BS3_HYBRID_RET +BS3_PROC_END_CMN Bs3MemSet + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-MemZero.asm b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-MemZero.asm new file mode 100644 index 00000000..04fd8ae6 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-MemZero.asm @@ -0,0 +1,93 @@ +; $Id: bs3-cmn-MemZero.asm $ +;; @file +; BS3Kit - Bs3MemZero. +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + +%include "bs3kit-template-header.mac" + +;; +; @cproto BS3_DECL(void) Bs3MemZero_c16(void BS3_FAR *pvDst, size_t cbDst); +; +BS3_PROC_BEGIN_CMN Bs3MemZero, BS3_PBC_HYBRID +%ifdef RT_ARCH_AMD64 + push rdi + + mov rdi, rcx ; rdi = pvDst + mov rcx, rdx ; rcx = cbDst + shr rcx, 3 ; calc qword count. + xor eax, eax ; rax = 0 (filler qword) + cld + rep stosq + + mov rcx, rdx ; cbDst + and rcx, 7 ; calc trailing byte count. + rep stosb + + pop rdi + BS3_HYBRID_RET + +%elif ARCH_BITS == 16 + push bp + mov bp, sp + push di + push es + + mov di, [bp + 2 + cbCurRetAddr] ; pvDst.off + mov dx, [bp + 2 + cbCurRetAddr + 2] ; pvDst.sel + mov es, dx + mov cx, [bp + 2 + cbCurRetAddr + 4] ; cbDst + shr cx, 1 ; calc dword count. + xor ax, ax + rep stosw + + mov cx, [bp + 2 + cbCurRetAddr + 4] ; cbDst + and cx, 1 ; calc tailing byte count. + rep stosb + + pop es + pop di + pop bp + BS3_HYBRID_RET + +%elif ARCH_BITS == 32 + push edi + + mov edi, [esp + 8] ; pvDst + mov ecx, [esp + 8 + 4] ; cbDst + shr cx, 2 ; calc dword count. + xor eax, eax + rep stosd + + mov ecx, [esp + 8 + 4] ; cbDst + and ecx, 3 ; calc tailing byte count. + rep stosb + + pop edi + BS3_HYBRID_RET + +%else + %error "Unknown bitness." +%endif +BS3_PROC_END_CMN Bs3MemZero + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-PagingAlias.c b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-PagingAlias.c new file mode 100644 index 00000000..a7742af8 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-PagingAlias.c @@ -0,0 +1,183 @@ +/* $Id: bs3-cmn-PagingAlias.c $ */ +/** @file + * BS3Kit - Bs3PagingAlias, Bs3PagingUnalias + */ + +/* + * Copyright (C) 2007-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include "bs3kit-template-header.h" +#include "bs3-cmn-paging.h" +#include "iprt/asm-amd64-x86.h" + + +#undef Bs3PagingAlias +BS3_CMN_DEF(int, Bs3PagingAlias,(uint64_t uDst, uint64_t uPhysToAlias, uint32_t cbHowMuch, uint64_t fPte)) +{ +#if ARCH_BITS == 16 + if (!BS3_MODE_IS_V86(g_bBs3CurrentMode)) +#endif + { + RTCCUINTXREG cr3 = ASMGetCR3(); + uint32_t cPages; + int rc; + + /* + * Validate and adjust the input a little. + */ + if (uDst & X86_PAGE_OFFSET_MASK) + { + cbHowMuch += X86_PAGE_SIZE - (uDst & X86_PAGE_OFFSET_MASK); + uDst &= ~(uint64_t)X86_PAGE_OFFSET_MASK; + } + uPhysToAlias &= X86_PTE_PAE_PG_MASK; + fPte &= ~(X86_PTE_PAE_MBZ_MASK_NX | X86_PTE_PAE_PG_MASK); + cbHowMuch = RT_ALIGN_32(cbHowMuch, X86_PAGE_SIZE); + cPages = cbHowMuch >> X86_PAGE_SHIFT; + //Bs3TestPrintf("Bs3PagingAlias: adjusted: uDst=%RX64 uPhysToAlias=%RX64 cbHowMuch=%RX32 fPte=%Rx64 cPages=%RX32\n", uDst, uPhysToAlias, cbHowMuch, fPte, cPages); + if (BS3_MODE_IS_LEGACY_PAGING(g_bBs3CurrentMode)) + { + X86PTE BS3_FAR *pPteLegacy; + uint32_t uDst32 = (uint32_t)uDst; + uint32_t uPhysToAlias32 = (uint32_t)uPhysToAlias; + if (uDst32 != uDst) + { + Bs3TestPrintf("warning: Bs3PagingAlias - uDst=%RX64 is out of range for legacy paging!\n", uDst); + return VERR_INVALID_PARAMETER; + } + if (uPhysToAlias32 != uPhysToAlias) + { + Bs3TestPrintf("warning: Bs3PagingAlias - uPhysToAlias=%RX64 is out of range for legacy paging!\n", uPhysToAlias); + return VERR_INVALID_PARAMETER; + } + + /* + * Trigger page table splitting first. + */ + while (cPages > 0) + { + pPteLegacy = bs3PagingGetLegacyPte(cr3, uDst32, false, &rc); + if (pPteLegacy) + { + uint32_t cLeftInPt = X86_PG_ENTRIES - ((uDst32 >> X86_PT_SHIFT) & X86_PT_MASK); + if (cPages <= cLeftInPt) + break; + uDst32 += cLeftInPt << X86_PAGE_SHIFT; + cPages -= cLeftInPt; + } + else + { + Bs3TestPrintf("warning: Bs3PagingAlias - bs3PagingGetLegacyPte failed: rc=%d\n", rc); + return rc; + } + } + + /* + * Make the changes. + */ + cPages = cbHowMuch >> X86_PAGE_SHIFT; + uDst32 = (uint32_t)uDst; + while (cPages > 0) + { + uint32_t cLeftInPt = X86_PG_ENTRIES - ((uDst32 >> X86_PT_SHIFT) & X86_PT_MASK); + pPteLegacy = bs3PagingGetLegacyPte(cr3, uDst32, false, &rc); + while (cLeftInPt > 0 && cPages > 0) + { + pPteLegacy->u = uPhysToAlias32 | (uint32_t)fPte; + pPteLegacy++; + uDst32 += X86_PAGE_SIZE; + uPhysToAlias32 += X86_PAGE_SIZE; + cPages--; + cLeftInPt--; + } + } + } + else + { + X86PTEPAE BS3_FAR *pPtePae; + uint64_t const uDstSaved = uDst; + + /* + * Trigger page table splitting first. + */ + while (cPages > 0) + { + pPtePae = bs3PagingGetPaePte(cr3, g_bBs3CurrentMode, uDst, false, &rc); + if (pPtePae) + { + uint32_t cLeftInPt = X86_PG_PAE_ENTRIES - ((uDst >> X86_PT_PAE_SHIFT) & X86_PT_PAE_MASK); + if (cPages <= cLeftInPt) + break; + cPages -= cLeftInPt; + uDst += cLeftInPt << X86_PAGE_SHIFT; + } + else + { + Bs3TestPrintf("warning: Bs3PagingAlias - bs3PagingGetLegacyPte failed: rc=%d\n", rc); + return rc; + } + } + + /* + * Make the changes. + */ + cPages = cbHowMuch >> X86_PAGE_SHIFT; + uDst = uDstSaved; + while (cPages > 0) + { + uint32_t cLeftInPt = X86_PG_PAE_ENTRIES - ((uDst >> X86_PT_PAE_SHIFT) & X86_PT_PAE_MASK); + pPtePae = bs3PagingGetPaePte(cr3, g_bBs3CurrentMode, uDst, false, &rc); + while (cLeftInPt > 0 && cPages > 0) + { + pPtePae->u = uPhysToAlias | fPte; + pPtePae++; + uDst += X86_PAGE_SIZE; + uPhysToAlias += X86_PAGE_SIZE; + cPages--; + cLeftInPt--; + } + } + } + + ASMReloadCR3(); + } +#if ARCH_BITS == 16 + /* + * We can't do this stuff in v8086 mode, so switch to 16-bit prot mode and do it there. + */ + else + return Bs3SwitchFromV86To16BitAndCallC((FPFNBS3FAR)Bs3PagingAlias_f16, sizeof(uint64_t)*3 + sizeof(uint32_t), + uDst, uPhysToAlias, cbHowMuch, fPte); +#endif + return VINF_SUCCESS; +} + + +#undef Bs3PagingUnalias +BS3_CMN_DEF(int, Bs3PagingUnalias,(uint64_t uDst, uint32_t cbHowMuch)) +{ + return BS3_CMN_NM(Bs3PagingAlias)(uDst, uDst, cbHowMuch, X86_PTE_P | X86_PTE_RW | X86_PTE_US | X86_PTE_A | X86_PTE_D); +} + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-PagingData.c b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-PagingData.c new file mode 100644 index 00000000..7f20f36e --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-PagingData.c @@ -0,0 +1,49 @@ +/* $Id: bs3-cmn-PagingData.c $ */ +/** @file + * BS3Kit - Paging Data. + */ + +/* + * Copyright (C) 2007-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include "bs3kit-template-header.h" +#include "bs3-cmn-paging.h" + + +/********************************************************************************************************************************* +* Global Variables * +*********************************************************************************************************************************/ +#if ARCH_BITS == 16 + +uint32_t g_PhysPagingRootPP = UINT32_MAX; +uint32_t g_PhysPagingRootPAE = UINT32_MAX; +uint32_t g_PhysPagingRootLM = UINT32_MAX; + +uint32_t g_uBs3PagingCanonicalTrapsAddr = UINT32_MAX; +uint16_t g_cbBs3PagingCanonicalTraps = 0; +uint16_t g_cbBs3PagingOneCanonicalTrap = 0; + +#endif + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-PagingInitRootForLM.c b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-PagingInitRootForLM.c new file mode 100644 index 00000000..99b9ca9c --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-PagingInitRootForLM.c @@ -0,0 +1,105 @@ +/* $Id: bs3-cmn-PagingInitRootForLM.c $ */ +/** @file + * BS3Kit - Bs3PagingInitRootForLM + */ + +/* + * Copyright (C) 2007-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include "bs3kit-template-header.h" +#include "bs3-cmn-paging.h" + + +#undef Bs3PagingInitRootForLM +BS3_CMN_DEF(int, Bs3PagingInitRootForLM,(void)) +{ + X86PML4 BS3_FAR *pPml4; + + BS3_ASSERT(g_PhysPagingRootLM == UINT32_MAX); + + /* + * The default is an identity mapping of the first 4GB repeated for the + * whole 48-bit virtual address space. So, we need one level more than PAE. + */ + pPml4 = (X86PML4 BS3_FAR *)Bs3MemAlloc(BS3MEMKIND_TILED, _4K); + if (pPml4) + { + X86PDPT BS3_FAR *pPdPtr = (X86PDPT BS3_FAR *)Bs3MemAlloc(BS3MEMKIND_TILED, _4K); + BS3_ASSERT((uintptr_t)pPdPtr != (uintptr_t)pPml4); + if (pPdPtr) + { + X86PDPAE BS3_FAR *paPgDirs = (X86PDPAE BS3_FAR *)Bs3MemAlloc(BS3MEMKIND_TILED, _4K * 4U); + BS3_ASSERT((uintptr_t)paPgDirs != (uintptr_t)pPml4); + if (paPgDirs) + { + unsigned i; + BS3_XPTR_AUTO(X86PML4, XPtrPml4); + BS3_XPTR_AUTO(X86PDPT, XPtrPdPtr); + BS3_XPTR_AUTO(X86PDPAE, XPtrPgDirs); + + /* Set up the 2048 2MB pages first. */ + for (i = 0; i < RT_ELEMENTS(paPgDirs->a) * 4U; i++) + paPgDirs->a[i].u = ((uint32_t)i << X86_PD_PAE_SHIFT) + | X86_PDE4M_P | X86_PDE4M_RW | X86_PDE4M_US | X86_PDE4M_PS | X86_PDE4M_A | X86_PDE4M_D; + + /* Set up the page directory pointer table next (4GB replicated, remember). */ + BS3_XPTR_SET(X86PDPAE, XPtrPgDirs, paPgDirs); + pPdPtr->a[0].u = BS3_XPTR_GET_FLAT(X86PDPAE, XPtrPgDirs) + | X86_PDPE_P | X86_PDPE_RW | X86_PDPE_US | X86_PDPE_A; + pPdPtr->a[1].u = pPdPtr->a[0].u + _4K; + pPdPtr->a[2].u = pPdPtr->a[1].u + _4K; + pPdPtr->a[3].u = pPdPtr->a[2].u + _4K; + + for (i = 4; i < RT_ELEMENTS(pPdPtr->a); i += 4) + { + pPdPtr->a[i + 0].u = pPdPtr->a[0].u; + pPdPtr->a[i + 1].u = pPdPtr->a[1].u; + pPdPtr->a[i + 2].u = pPdPtr->a[2].u; + pPdPtr->a[i + 3].u = pPdPtr->a[3].u; + } + + /* Set up the page map level 4 (all entries are the same). */ + BS3_XPTR_SET(X86PDPT, XPtrPdPtr, pPdPtr); + pPml4->a[0].u = BS3_XPTR_GET_FLAT(X86PDPT, XPtrPdPtr) + | X86_PML4E_P | X86_PML4E_RW | X86_PML4E_US | X86_PML4E_A; + for (i = 1; i < RT_ELEMENTS(pPml4->a); i++) + pPml4->a[i].u = pPml4->a[0].u; + + /* Set the global root pointer and we're done. */ + BS3_XPTR_SET(X86PML4, XPtrPml4, pPml4); + g_PhysPagingRootLM = BS3_XPTR_GET_FLAT(X86PML4, XPtrPml4); + return VINF_SUCCESS; + } + + BS3_ASSERT(false); + Bs3MemFree(pPdPtr, _4K); + } + BS3_ASSERT(false); + Bs3MemFree(pPml4, _4K); + } + BS3_ASSERT(false); + return VERR_NO_MEMORY; +} + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-PagingInitRootForPAE.c b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-PagingInitRootForPAE.c new file mode 100644 index 00000000..828aeda2 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-PagingInitRootForPAE.c @@ -0,0 +1,92 @@ +/* $Id: bs3-cmn-PagingInitRootForPAE.c $ */ +/** @file + * BS3Kit - Bs3PagingInitRootForPAE + */ + +/* + * Copyright (C) 2007-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include "bs3kit-template-header.h" +#include "bs3-cmn-paging.h" + + +#undef Bs3PagingInitRootForPAE +BS3_CMN_DEF(int, Bs3PagingInitRootForPAE,(void)) +{ + X86PDPT BS3_FAR *pPdPtr; + + BS3_ASSERT(g_PhysPagingRootPAE == UINT32_MAX); + + /* + * By default we do a identity mapping of the entire address space + * using 2 GB pages. So, we need four page directories and one page + * directory pointer table with 4 entries. (We cannot share the PDPT with + * long mode because of reserved bit which will cause fatal trouble.) + * + * We assume that the availability of PAE means that PSE is available too. + */ +/** @todo testcase: loading invalid PDPTREs will tripple fault the CPU, won't it? We guru with invalid guest state. */ + pPdPtr = (X86PDPT BS3_FAR *)Bs3MemAlloc(BS3MEMKIND_TILED, sizeof(X86PDPE) * 4U); + if (pPdPtr) + { + X86PDPAE BS3_FAR *paPgDirs; + BS3_ASSERT(((uintptr_t)pPdPtr & 0x3f) == 0); + + paPgDirs = (X86PDPAE BS3_FAR *)Bs3MemAlloc(BS3MEMKIND_TILED, _4K * 4U); + if (paPgDirs) + { + unsigned i; + BS3_XPTR_AUTO(X86PDPT, XPtrPdPtr); + BS3_XPTR_AUTO(X86PDPAE, XPtrPgDirs); + + /* Set up the 2048 2MB pages first. */ + for (i = 0; i < RT_ELEMENTS(paPgDirs->a) * 4U; i++) + paPgDirs->a[i].u = ((uint32_t)i << X86_PD_PAE_SHIFT) + | X86_PDE4M_P | X86_PDE4M_RW | X86_PDE4M_US | X86_PDE4M_PS | X86_PDE4M_A | X86_PDE4M_D; + + /* Set up the four page directory pointer table entries. */ + BS3_XPTR_SET(X86PDPAE, XPtrPgDirs, paPgDirs); + pPdPtr->a[0].u = BS3_XPTR_GET_FLAT(X86PDPAE, XPtrPgDirs) | X86_PDPE_P; + pPdPtr->a[1].u = pPdPtr->a[0].u + _4K; + pPdPtr->a[2].u = pPdPtr->a[1].u + _4K; + pPdPtr->a[3].u = pPdPtr->a[2].u + _4K; + + /* Free up 8 consequtive entries for raw-mode hypervisor code. */ + if (1) /** @todo detect raw-mode and only do this then. */ + for (i = 0; i < 8; i++) + paPgDirs->a[i + (UINT32_C(0xc0000000) >> X86_PD_PAE_SHIFT)].b.u1Present = 0; + + /* Set the global root pointer and we're done. */ + BS3_XPTR_SET(X86PDPT, XPtrPdPtr, pPdPtr); + g_PhysPagingRootPAE = BS3_XPTR_GET_FLAT(X86PDPT, XPtrPdPtr); + return VINF_SUCCESS; + } + BS3_ASSERT(false); + Bs3MemFree(pPdPtr, _4K); + } + BS3_ASSERT(false); + return VERR_NO_MEMORY; +} + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-PagingInitRootForPP.c b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-PagingInitRootForPP.c new file mode 100644 index 00000000..cea59f3a --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-PagingInitRootForPP.c @@ -0,0 +1,153 @@ +/* $Id: bs3-cmn-PagingInitRootForPP.c $ */ +/** @file + * BS3Kit - Bs3PagingInitRootForPP + */ + +/* + * Copyright (C) 2007-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include "bs3kit-template-header.h" +#include "bs3-cmn-paging.h" +#include "bs3-cmn-memory.h" /* bad bird */ +#include <iprt/param.h> + + +/** + * Creates page tables for a section of the page directory. + * + * @returns VINF_SUCCESS or VERR_NO_MEMORY. + * @param pPgDir The page directory. + * @param iFirst The first PD entry. + * @param cEntries How many PD entries to create pages tables for. + */ +static int Bs3PagingInitPageTablesForPgDir(X86PD BS3_FAR *pPgDir, unsigned iFirst, unsigned cEntries) +{ + uint32_t uCurPhys = (uint32_t)iFirst << X86_PD_SHIFT; + + while (cEntries--) + { + X86PT BS3_FAR *pPt = (X86PT BS3_FAR *)Bs3MemAlloc(BS3MEMKIND_TILED, _4K); + if (pPt) + { + unsigned j = 0; + for (j = 0; j < RT_ELEMENTS(pPt->a); j++, uCurPhys += PAGE_SIZE) + { + pPt->a[j].u = uCurPhys; + pPt->a[j].u |= X86_PTE_P | X86_PTE_RW | X86_PTE_US | X86_PTE_A | X86_PTE_D; + } + pPgDir->a[iFirst].u = Bs3SelPtrToFlat(pPt); + pPgDir->a[iFirst].u |= X86_PDE_P | X86_PDE_RW | X86_PDE_US | X86_PDE_A; + iFirst++; + } + else + return VERR_NO_MEMORY; + } + return VINF_SUCCESS; +} + + +#undef Bs3PagingInitRootForPP +BS3_CMN_DEF(int, Bs3PagingInitRootForPP,(void)) +{ + X86PD BS3_FAR *pPgDir; + + BS3_ASSERT(g_PhysPagingRootPP == UINT32_MAX); + + + /* + * By default we do a identity mapping of the entire address space + * using 4 GB pages. So, we only really need one page directory, + * that's all. + * + * ASSUMES page size extension available, i.e. pentium+. + */ + pPgDir = (X86PD BS3_FAR *)Bs3MemAllocZ(BS3MEMKIND_TILED, _4K); + if (pPgDir) + { + BS3_XPTR_AUTO(X86PD, XptrPgDir); + unsigned i; + int rc = VINF_SUCCESS; + + if (g_uBs3CpuDetected & BS3CPU_F_PSE) + { + for (i = 0; i < RT_ELEMENTS(pPgDir->a); i++) + { + pPgDir->a[i].u = (uint32_t)i << X86_PD_SHIFT; + pPgDir->a[i].u |= X86_PDE4M_P | X86_PDE4M_RW | X86_PDE4M_US | X86_PDE4M_PS | X86_PDE4M_A | X86_PDE4M_D; + } + + /* Free up 4 consequtive entries for raw-mode hypervisor code. */ + if (1) /** @todo detect raw-mode and only do this then. */ + for (i = 0; i < 4; i++) + pPgDir->a[i + (UINT32_C(0xc0000000) >> X86_PD_SHIFT)].b.u1Present = 0; + } + else + { + /* + * This requires 4MB of page tables if we map everything. + * So, we check how much memory we have available and make sure we + * don't use all of it for page tables. + */ + unsigned cMax = RT_ELEMENTS(pPgDir->a); + uint32_t cFreePages = g_Bs3Mem4KUpperTiled.Core.cFreeChunks + g_Bs3Mem4KLow.Core.cFreeChunks; + if (cFreePages >= cMax + 128) + Bs3PagingInitPageTablesForPgDir(pPgDir, 0, cMax); + else + { + unsigned cTop; + if (cMax >= 256 /*1MB*/) + { + cMax = cFreePages - 128; + cTop = 32; + } + else if (cMax >= 128) + { + cMax = cFreePages - 48; + cTop = 16; + } + else + { + cMax = cFreePages - 16; + cTop = RT_MIN(16, cMax / 4); + } + Bs3TestPrintf("Bs3PagingInitRootForPP: Warning! insufficient memory for mapping all 4GB!\n" + " Will only map 0x00000000-%#010RX32 and %#010RX32-0xffffffff.\n", + (uint32_t)(cMax - cTop) << PAGE_SHIFT, UINT32_MAX - ((uint32_t)cTop << PAGE_SHIFT) + 1); + rc = Bs3PagingInitPageTablesForPgDir(pPgDir, 0, cMax - cTop); + if (RT_SUCCESS(rc)) + rc = Bs3PagingInitPageTablesForPgDir(pPgDir, RT_ELEMENTS(pPgDir->a) - cTop, cTop); + } + } + + BS3_XPTR_SET(X86PD, XptrPgDir, pPgDir); + g_PhysPagingRootPP = BS3_XPTR_GET_FLAT(X86PD, XptrPgDir); + return rc; + } + + Bs3Printf("Bs3PagingInitRootForPP: No memory!\n"); + BS3_ASSERT(false); + return VERR_NO_MEMORY; +} + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-PagingProtect.c b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-PagingProtect.c new file mode 100644 index 00000000..f922710e --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-PagingProtect.c @@ -0,0 +1,382 @@ +/* $Id: bs3-cmn-PagingProtect.c $ */ +/** @file + * BS3Kit - Bs3PagingProtect + */ + +/* + * Copyright (C) 2007-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include "bs3kit-template-header.h" +#include "bs3-cmn-paging.h" +#include <iprt/asm-amd64-x86.h> +#include <iprt/param.h> + + +/********************************************************************************************************************************* +* Defined Constants And Macros * +*********************************************************************************************************************************/ +#if 0 +# define BS3PAGING_DPRINTF1(a) Bs3TestPrintf a +#else +# define BS3PAGING_DPRINTF1(a) do { } while (0) +#endif +#if 0 +# define BS3PAGING_DPRINTF2(a) Bs3TestPrintf a +#else +# define BS3PAGING_DPRINTF2(a) do { } while (0) +#endif + + +static void *bs3PagingBuildPaeTable(uint64_t uTmpl, uint64_t cbIncrement, BS3MEMKIND enmKind, int *prc) +{ + uint64_t BS3_FAR *pau64 = (uint64_t BS3_FAR *)Bs3MemAlloc(enmKind, _4K); + if (pau64) + { + unsigned i; + for (i = 0; i < _4K / sizeof(uint64_t); i++, uTmpl += cbIncrement) + pau64[i] = uTmpl; + } + else + *prc = VERR_NO_MEMORY; + return pau64; +} + + +#undef bs3PagingGetLegacyPte +BS3_CMN_DEF(X86PTE BS3_FAR *, bs3PagingGetLegacyPte,(RTCCUINTXREG cr3, uint32_t uFlat, bool fUseInvlPg, int *prc)) +{ + X86PTE BS3_FAR *pPTE = NULL; +#if TMPL_BITS == 16 + uint32_t const uMaxAddr = BS3_MODE_IS_RM_OR_V86(g_bBs3CurrentMode) ? _1M - 1 : BS3_SEL_TILED_AREA_SIZE - 1; +#else + uint32_t const uMaxAddr = UINT32_MAX; +#endif + BS3PAGING_DPRINTF2(("bs3PagingGetLegacyPte: cr3=%RX32 uFlat=%RX32 uMaxAddr=%RX32\n", (uint32_t)cr3, uFlat, uMaxAddr)); + + *prc = VERR_OUT_OF_RANGE; + if (cr3 <= uMaxAddr) + { + unsigned const iPde = (uFlat >> X86_PD_SHIFT) & X86_PD_MASK; + PX86PD const pPD = (PX86PD)Bs3XptrFlatToCurrent(cr3 & X86_CR3_PAGE_MASK); + + BS3_ASSERT(pPD->a[iPde].b.u1Present); + if (pPD->a[iPde].b.u1Present) + { + unsigned const iPte = (uFlat >> X86_PT_SHIFT) & X86_PT_MASK; + + BS3_ASSERT(pPD->a[iPde].b.u1Present); + BS3PAGING_DPRINTF2(("bs3PagingGetLegacyPte: pPD=%p iPde=%#x: %#RX32\n", pPD, iPde, pPD->a[iPde])); + if (pPD->a[iPde].b.u1Present) + { + if (!pPD->a[iPde].b.u1Size) + { + if (pPD->a[iPde].u <= uMaxAddr) + pPTE = &((X86PT BS3_FAR *)Bs3XptrFlatToCurrent(pPD->a[iPde].u & ~(uint32_t)PAGE_OFFSET_MASK))->a[iPte]; + else + BS3PAGING_DPRINTF1(("bs3PagingGetLegacyPte: out of range! iPde=%#x: %#x\n", iPde, pPD->a[iPde].u)); + } + else + { + X86PT BS3_FAR *pPT; + uint32_t uPte = (pPD->a[iPde].u & ~(uint32_t)(X86_PDE4M_PS | X86_PDE4M_G | X86_PDE4M_PG_HIGH_MASK)) \ + | X86_PTE_D; + if (pPD->a[iPde].b.u1Global) + uPte |= X86_PTE_G; + if (pPD->a[iPde].b.u1PAT) + uPte |= X86_PTE_PAT; + + pPT = (X86PT BS3_FAR *)bs3PagingBuildPaeTable(RT_MAKE_U64(uPte, uPte | PAGE_SIZE), + RT_MAKE_U64(PAGE_SIZE*2, PAGE_SIZE*2), + uMaxAddr > _1M ? BS3MEMKIND_TILED : BS3MEMKIND_REAL, prc); + + BS3PAGING_DPRINTF2(("bs3PagingGetLegacyPte: Built pPT=%p uPte=%RX32\n", pPT, uPte)); + if (pPT) + { + ASMAtomicUoWriteU32(&pPD->a[iPde].u, + Bs3SelPtrToFlat(pPT) + | ( pPD->a[iPde].u + & ~(uint32_t)(X86_PTE_PG_MASK | X86_PDE4M_PS | X86_PDE4M_G | X86_PDE4M_D))); + BS3PAGING_DPRINTF2(("bs3PagingGetLegacyPte: iPde=%#x: %#RX32\n", iPde, pPD->a[iPde].u)); + if (fUseInvlPg) + ASMInvalidatePage(uFlat); + pPTE = &pPT->a[iPte]; + } + } + } + } + } + else + BS3PAGING_DPRINTF1(("bs3PagingGetLegacyPte: out of range! cr3=%#x\n", cr3)); + return pPTE; +} + + +/** + * Get the PTE for an address, given a PAE or long mode CR3. + * + * @returns Pointer to the PTE on success, NULL on failure. + * @param cr3 The CR3. + * @param bMode Indicates whether it's PAE or long mode. + * @param uFlat The address for which we want the PTE. + * @param fUseInvlPg Whether we can use invalidate page when + * replacing large pages. + * @param prc Updated only on failure. + */ +#undef bs3PagingGetPaePte +BS3_CMN_DEF(X86PTEPAE BS3_FAR *, bs3PagingGetPaePte,(RTCCUINTXREG cr3, uint8_t bMode, uint64_t uFlat, bool fUseInvlPg, int *prc)) +{ + X86PTEPAE BS3_FAR *pPTE = NULL; +#if TMPL_BITS == 16 + uint32_t const uMaxAddr = BS3_MODE_IS_RM_OR_V86(g_bBs3CurrentMode) ? _1M - 1 : BS3_SEL_TILED_AREA_SIZE - 1; +#else + uintptr_t const uMaxAddr = ~(uintptr_t)0; +#endif + + *prc = VERR_OUT_OF_RANGE; + if ((cr3 & X86_CR3_AMD64_PAGE_MASK) <= uMaxAddr) + { + X86PDPAE BS3_FAR *pPD; + if (BS3_MODE_IS_64BIT_SYS(bMode)) + { + unsigned const iPml4e = (uFlat >> X86_PML4_SHIFT) & X86_PML4_MASK; + X86PML4 BS3_FAR *pPml4 = (X86PML4 BS3_FAR *)Bs3XptrFlatToCurrent(cr3 & X86_CR3_AMD64_PAGE_MASK); + BS3_ASSERT(pPml4->a[iPml4e].n.u1Present); + if ((pPml4->a[iPml4e].u & X86_PML4E_PG_MASK) <= uMaxAddr) + { + unsigned const iPdpte = (uFlat >> X86_PDPT_SHIFT) & X86_PDPT_MASK_AMD64; + X86PDPT BS3_FAR *pPdpt = (X86PDPT BS3_FAR *)Bs3XptrFlatToCurrent(pPml4->a[iPml4e].u & X86_PML4E_PG_MASK); + BS3_ASSERT(pPdpt->a[iPdpte].n.u1Present); + if (!pPdpt->a[iPdpte].b.u1Size) + { + if ((pPdpt->a[iPdpte].u & X86_PDPE_PG_MASK) <= uMaxAddr) + pPD = (X86PDPAE BS3_FAR *)Bs3XptrFlatToCurrent(pPdpt->a[iPdpte].u & ~(uint64_t)PAGE_OFFSET_MASK); + else + BS3PAGING_DPRINTF1(("bs3PagingGetPaePte: out of range! iPdpte=%#x: %RX64 max=%RX32\n", + iPdpte, pPdpt->a[iPdpte].u, (uint32_t)uMaxAddr)); + } + else + { + /* Split 1GB page. */ + pPD = (X86PDPAE BS3_FAR *)bs3PagingBuildPaeTable(pPdpt->a[iPdpte].u, _2M, + uMaxAddr > _1M ? BS3MEMKIND_TILED : BS3MEMKIND_REAL, prc); + if (pPD) + { + ASMAtomicUoWriteU64(&pPdpt->a[iPdpte].u, + Bs3SelPtrToFlat(pPD) + | ( pPdpt->a[iPdpte].u + & ~(uint64_t)(X86_PDPE_PG_MASK | X86_PDE4M_PS | X86_PDE4M_G | X86_PDE4M_D))); + if (fUseInvlPg) + ASMInvalidatePage(uFlat); + } + } + } + } + //else if (uFlat <= UINT32_MAX) - fixme! + else if (!(uFlat >> 32)) + { + unsigned const iPdpte = ((uint32_t)uFlat >> X86_PDPT_SHIFT) & X86_PDPT_MASK_PAE; + X86PDPT BS3_FAR *pPdpt = (X86PDPT BS3_FAR *)Bs3XptrFlatToCurrent(cr3 & X86_CR3_PAE_PAGE_MASK); + BS3_ASSERT(pPdpt->a[iPdpte].n.u1Present); + if ((pPdpt->a[iPdpte].u & X86_PDPE_PG_MASK) <= uMaxAddr) + pPD = (X86PDPAE BS3_FAR *)Bs3XptrFlatToCurrent(pPdpt->a[iPdpte].u & X86_PDPE_PG_MASK); + else + BS3PAGING_DPRINTF1(("bs3PagingGetPaePte: out of range! iPdpte=%#x: %RX64 max=%RX32\n", + iPdpte, pPdpt->a[iPdpte].u, (uint32_t)uMaxAddr)); + } + else + { + pPD = NULL; + BS3PAGING_DPRINTF1(("bs3PagingGetPaePte: out of range! uFlat=%#RX64 max=%RX32\n", uFlat, (uint32_t)uMaxAddr)); + } + if (pPD) + { + unsigned const iPte = (uFlat >> X86_PT_PAE_SHIFT) & X86_PT_PAE_MASK; + unsigned const iPde = (uFlat >> X86_PD_PAE_SHIFT) & X86_PD_PAE_MASK; + if (!pPD->a[iPde].b.u1Size) + { + if ((pPD->a[iPde].u & X86_PDE_PAE_PG_MASK) <= uMaxAddr) + pPTE = &((X86PTPAE BS3_FAR *)Bs3XptrFlatToCurrent(pPD->a[iPde].u & ~(uint64_t)PAGE_OFFSET_MASK))->a[iPte]; + else + BS3PAGING_DPRINTF1(("bs3PagingGetPaePte: out of range! iPde=%#x: %RX64 max=%RX32\n", + iPde, pPD->a[iPde].u, (uint32_t)uMaxAddr)); + } + else + { + /* Split 2MB page. */ + X86PTPAE BS3_FAR *pPT; + uint64_t uTmpl = pPD->a[iPde].u & ~(uint64_t)(X86_PDE4M_G | X86_PDE4M_PS | X86_PDE4M_PAT); + if (!pPD->a[iPde].b.u1Global) + uTmpl |= X86_PTE_G; + if (!pPD->a[iPde].b.u1PAT) + uTmpl |= X86_PTE_PAT; + + pPT = (X86PTPAE BS3_FAR *)bs3PagingBuildPaeTable(uTmpl, PAGE_SIZE, + uMaxAddr > _1M ? BS3MEMKIND_TILED : BS3MEMKIND_REAL, prc); + if (pPT) + { + ASMAtomicUoWriteU64(&pPD->a[iPde].u, + Bs3SelPtrToFlat(pPT) + | ( pPD->a[iPde].u + & ~(uint64_t)(X86_PTE_PAE_PG_MASK | X86_PDE4M_PS | X86_PDE4M_G | X86_PDE4M_D))); + if (fUseInvlPg) + ASMInvalidatePage(uFlat); + pPTE = &pPT->a[iPte]; + } + } + } + } + else + BS3PAGING_DPRINTF1(("bs3PagingGetPaePte: out of range! cr3=%#RX32 uMaxAddr=%#RX32\n", (uint32_t)cr3, (uint32_t)uMaxAddr)); + return pPTE; +} + + +#undef Bs3PagingProtect +BS3_CMN_DEF(int, Bs3PagingProtect,(uint64_t uFlat, uint64_t cb, uint64_t fSet, uint64_t fClear)) +{ +#if ARCH_BITS == 16 + if (!BS3_MODE_IS_V86(g_bBs3CurrentMode)) +#endif + { + RTCCUINTXREG const cr3 = ASMGetCR3(); + RTCCUINTXREG const cr4 = g_uBs3CpuDetected & BS3CPU_F_CPUID ? ASMGetCR4() : 0; + bool const fLegacyPTs = !(cr4 & X86_CR4_PAE); + bool const fUseInvlPg = (g_uBs3CpuDetected & BS3CPU_TYPE_MASK) >= BS3CPU_80486 + && ( cb < UINT64_C(16)*PAGE_SIZE + || (cr4 & X86_CR4_PGE)); + unsigned cEntries; + int rc; + + /* + * Adjust the range parameters. + */ + cb += uFlat & PAGE_OFFSET_MASK; + cb = RT_ALIGN_64(cb, PAGE_SIZE); + uFlat &= ~(uint64_t)PAGE_OFFSET_MASK; + + fSet &= ~X86_PTE_PAE_PG_MASK; + fClear &= ~X86_PTE_PAE_PG_MASK; + + BS3PAGING_DPRINTF1(("Bs3PagingProtect: uFlat=%RX64 cb=%RX64 fSet=%RX64 fClear=%RX64 %s %s\n", uFlat, cb, fSet, fClear, + fLegacyPTs ? "legacy" : "pae/amd64", fUseInvlPg ? "invlpg" : "reload-cr3")); + if (fLegacyPTs) + { + /* + * Legacy page tables. + */ + while ((uint32_t)cb > 0) + { + PX86PTE pPte = BS3_CMN_FAR_NM(bs3PagingGetLegacyPte)(cr3, (uint32_t)uFlat, fUseInvlPg, &rc); + if (!pPte) + return rc; + + cEntries = X86_PG_ENTRIES - ((uFlat >> X86_PT_SHIFT) & X86_PT_MASK); + while (cEntries-- > 0 && cb > 0) + { + pPte->u &= ~(uint32_t)fClear; + pPte->u |= (uint32_t)fSet; + if (fUseInvlPg) + ASMInvalidatePage(uFlat); + + pPte++; + uFlat += PAGE_SIZE; + cb -= PAGE_SIZE; + } + } + } + else + { + /* + * Long mode or PAE page tables (at this level they are the same). + */ + while (cb > 0) + { + PX86PTEPAE pPte = BS3_CMN_FAR_NM(bs3PagingGetPaePte)(cr3, g_bBs3CurrentMode, uFlat, fUseInvlPg, &rc); + if (!pPte) + return rc; + + cEntries = X86_PG_ENTRIES - ((uFlat >> X86_PT_PAE_SHIFT) & X86_PT_PAE_MASK); + while (cEntries-- > 0 && cb > 0) + { + pPte->u &= ~fClear; + pPte->u |= fSet; + if (fUseInvlPg) + ASMInvalidatePage(uFlat); + + pPte++; + uFlat += PAGE_SIZE; + cb -= PAGE_SIZE; + } + } + } + + /* + * Flush the TLB if we didn't use INVLPG above. + */ + BS3PAGING_DPRINTF2(("Bs3PagingProtect: reloading cr3=%RX32\n", (uint32_t)cr3)); + //if (!fUseInvlPg) + ASMSetCR3(cr3); + BS3PAGING_DPRINTF2(("Bs3PagingProtect: reloaded cr3=%RX32\n", (uint32_t)cr3)); + } +#if ARCH_BITS == 16 + /* + * We can do this stuff in v8086 mode. + */ + else + return Bs3SwitchFromV86To16BitAndCallC((FPFNBS3FAR)Bs3PagingProtect_f16, sizeof(uint64_t) * 4, uFlat, cb, fSet, fClear); +#endif + return VINF_SUCCESS; +} + + +#undef Bs3PagingProtectPtr +BS3_CMN_DEF(int, Bs3PagingProtectPtr,(void *pv, size_t cb, uint64_t fSet, uint64_t fClear)) +{ +#if ARCH_BITS == 16 + return BS3_CMN_NM(Bs3PagingProtect)(Bs3SelPtrToFlat(pv), cb, fSet, fClear); +#else + return BS3_CMN_NM(Bs3PagingProtect)((uintptr_t)pv, cb, fSet, fClear); +#endif +} + + +#undef Bs3PagingGetPte +BS3_CMN_DEF(void BS3_FAR *, Bs3PagingGetPte,(uint64_t uFlat, int *prc)) +{ + RTCCUINTXREG const cr3 = ASMGetCR3(); + RTCCUINTXREG const cr4 = g_uBs3CpuDetected & BS3CPU_F_CPUID ? ASMGetCR4() : 0; + bool const fLegacyPTs = !(cr4 & X86_CR4_PAE); + bool const fUseInvlPg = (g_uBs3CpuDetected & BS3CPU_TYPE_MASK) >= BS3CPU_80486; + int rc; + if (!prc) + prc = &rc; + if (!fLegacyPTs) + return BS3_CMN_FAR_NM(bs3PagingGetPaePte)(cr3, g_bBs3CurrentMode, uFlat, fUseInvlPg, prc); + if (uFlat < _4G) + return BS3_CMN_FAR_NM(bs3PagingGetLegacyPte)(cr3, (uint32_t)uFlat, fUseInvlPg, prc); + *prc = VERR_OUT_OF_RANGE; + return NULL; +} + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-PagingQueryAddressInfo.c b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-PagingQueryAddressInfo.c new file mode 100644 index 00000000..a556c5b0 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-PagingQueryAddressInfo.c @@ -0,0 +1,149 @@ +/* $Id: bs3-cmn-PagingQueryAddressInfo.c $ */ +/** @file + * BS3Kit - Bs3PagingQueryAddressInfo + */ + +/* + * Copyright (C) 2007-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include <bs3kit.h> +#include <iprt/asm-amd64-x86.h> +#include <VBox/err.h> + + +#undef Bs3PagingQueryAddressInfo +BS3_CMN_DEF(int, Bs3PagingQueryAddressInfo,(uint64_t uFlat, PBS3PAGINGINFO4ADDR pPgInfo)) +{ + RTCCUINTXREG const cr3 = ASMGetCR3(); + RTCCUINTXREG const cr4 = g_uBs3CpuDetected & BS3CPU_F_CPUID ? ASMGetCR4() : 0; + bool const fLegacyPTs = !(cr4 & X86_CR4_PAE); + int rc = VERR_OUT_OF_RANGE; + + + pPgInfo->fFlags = 0; + pPgInfo->u.apbEntries[0] = NULL; + pPgInfo->u.apbEntries[1] = NULL; + pPgInfo->u.apbEntries[2] = NULL; + pPgInfo->u.apbEntries[3] = NULL; + + if (!fLegacyPTs) + { +#if TMPL_BITS == 16 + uint32_t const uMaxAddr = BS3_MODE_IS_RM_OR_V86(g_bBs3CurrentMode) ? _1M - 1 : BS3_SEL_TILED_AREA_SIZE - 1; +#else + uintptr_t const uMaxAddr = ~(uintptr_t)0; +#endif + uint64_t const fEfer = g_uBs3CpuDetected & BS3CPU_F_LONG_MODE ? ASMRdMsr(MSR_K6_EFER) : 0; + + pPgInfo->cEntries = fEfer & MSR_K6_EFER_LMA ? 4 : 3; + pPgInfo->cbEntry = sizeof(X86PTEPAE); + if ((cr3 & X86_CR3_AMD64_PAGE_MASK) <= uMaxAddr) + { + if ( (fEfer & MSR_K6_EFER_LMA) + && X86_IS_CANONICAL(uFlat)) + { + /* 48-bit long mode paging. */ + pPgInfo->u.Pae.pPml4e = (X86PML4E BS3_FAR *)Bs3XptrFlatToCurrent(cr3 & X86_CR3_AMD64_PAGE_MASK); + pPgInfo->u.Pae.pPml4e += (uFlat >> X86_PML4_SHIFT) & X86_PML4_MASK; + if (!pPgInfo->u.Pae.pPml4e->n.u1Present) + rc = VERR_PAGE_NOT_PRESENT; + else if ((pPgInfo->u.Pae.pPml4e->u & X86_PML4E_PG_MASK) <= uMaxAddr) + { + pPgInfo->u.Pae.pPdpe = (X86PDPE BS3_FAR *)Bs3XptrFlatToCurrent(pPgInfo->u.Pae.pPml4e->u & X86_PML4E_PG_MASK); + pPgInfo->u.Pae.pPdpe += (uFlat >> X86_PDPT_SHIFT) & X86_PDPT_MASK_AMD64; + if (!pPgInfo->u.Pae.pPdpe->n.u1Present) + rc = VERR_PAGE_NOT_PRESENT; + else if (pPgInfo->u.Pae.pPdpe->b.u1Size) + rc = VINF_SUCCESS; + else + rc = VINF_TRY_AGAIN; + } + } + else if ( !(fEfer & MSR_K6_EFER_LMA) + && uFlat <= _4G) + { + /* 32-bit PAE paging. */ + pPgInfo->u.Pae.pPdpe = (X86PDPE BS3_FAR *)Bs3XptrFlatToCurrent(cr3 & X86_CR3_PAE_PAGE_MASK); + pPgInfo->u.Pae.pPdpe += ((uint32_t)uFlat >> X86_PDPT_SHIFT) & X86_PDPT_MASK_PAE; + if (!pPgInfo->u.Pae.pPdpe->n.u1Present) + rc = VERR_PAGE_NOT_PRESENT; + else + rc = VINF_TRY_AGAIN; + } + + /* Common code for the PD and PT levels. */ + if ( rc == VINF_TRY_AGAIN + && (pPgInfo->u.Pae.pPdpe->u & X86_PDPE_PG_MASK) <= uMaxAddr) + { + rc = VERR_OUT_OF_RANGE; + pPgInfo->u.Pae.pPde = (X86PDEPAE BS3_FAR *)Bs3XptrFlatToCurrent(pPgInfo->u.Pae.pPdpe->u & X86_PDPE_PG_MASK); + pPgInfo->u.Pae.pPde += (uFlat >> X86_PD_PAE_SHIFT) & X86_PD_PAE_MASK; + if (!pPgInfo->u.Pae.pPde->n.u1Present) + rc = VERR_PAGE_NOT_PRESENT; + else if (pPgInfo->u.Pae.pPde->b.u1Size) + rc = VINF_SUCCESS; + else if ((pPgInfo->u.Pae.pPde->u & X86_PDE_PAE_PG_MASK) <= uMaxAddr) + { + pPgInfo->u.Pae.pPte = (X86PTEPAE BS3_FAR *)Bs3XptrFlatToCurrent(pPgInfo->u.Pae.pPde->u & X86_PDE_PAE_PG_MASK); + rc = VINF_SUCCESS; + } + } + else if (rc == VINF_TRY_AGAIN) + rc = VERR_OUT_OF_RANGE; + } + } + else + { +#if TMPL_BITS == 16 + uint32_t const uMaxAddr = BS3_MODE_IS_RM_OR_V86(g_bBs3CurrentMode) ? _1M - 1 : BS3_SEL_TILED_AREA_SIZE - 1; +#else + uint32_t const uMaxAddr = UINT32_MAX; +#endif + + pPgInfo->cEntries = 2; + pPgInfo->cbEntry = sizeof(X86PTE); + if ( uFlat < _4G + && cr3 <= uMaxAddr) + { + pPgInfo->u.Legacy.pPde = (X86PDE BS3_FAR *)Bs3XptrFlatToCurrent(cr3 & X86_CR3_PAGE_MASK); + pPgInfo->u.Legacy.pPde += ((uint32_t)uFlat >> X86_PD_SHIFT) & X86_PD_MASK; + if (!pPgInfo->u.Legacy.pPde->b.u1Present) + rc = VERR_PAGE_NOT_PRESENT; + else if (pPgInfo->u.Legacy.pPde->b.u1Size) + rc = VINF_SUCCESS; + else if (pPgInfo->u.Legacy.pPde->u <= uMaxAddr) + { + pPgInfo->u.Legacy.pPte = (X86PTE BS3_FAR *)Bs3XptrFlatToCurrent(pPgInfo->u.Legacy.pPde->u & X86_PDE_PG_MASK); + pPgInfo->u.Legacy.pPte += ((uint32_t)uFlat >> X86_PT_SHIFT) & X86_PT_MASK; + if (pPgInfo->u.Legacy.pPte->n.u1Present) + rc = VINF_SUCCESS; + else + rc = VERR_PAGE_NOT_PRESENT; + } + } + } + return rc; +} + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-PagingSetupCanonicalTraps.c b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-PagingSetupCanonicalTraps.c new file mode 100644 index 00000000..e42ae1bf --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-PagingSetupCanonicalTraps.c @@ -0,0 +1,113 @@ +/* $Id: bs3-cmn-PagingSetupCanonicalTraps.c $ */ +/** @file + * BS3Kit - Bs3PagingSetupCanonicalTraps + */ + +/* + * Copyright (C) 2007-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include "bs3kit-template-header.h" +#include "bs3-cmn-paging.h" +#include "iprt/asm-amd64-x86.h" + + +#undef Bs3PagingSetupCanonicalTraps +BS3_CMN_PROTO_STUB(void BS3_FAR *, Bs3PagingSetupCanonicalTraps,(void)) +{ + if (g_uBs3CpuDetected & BS3CPU_F_LONG_MODE) + { +#if ARCH_BITS == 16 + if (!BS3_MODE_IS_RM_OR_V86(g_bBs3CurrentMode)) +#endif + { + uint8_t BS3_FAR *pb; + X86PTEPAE BS3_FAR *paLoPtes; + X86PTEPAE BS3_FAR *paHiPtes; + int rc; + + /* Already initialized? Likely. */ + if (g_cbBs3PagingCanonicalTraps != 0) + return Bs3XptrFlatToCurrent(g_uBs3PagingCanonicalTrapsAddr); + + /* Initialize AMD64 page tables if necessary (unlikely). */ + if (g_PhysPagingRootLM == UINT32_MAX) + { + rc = Bs3PagingInitRootForLM(); + if (RT_FAILURE(rc)) + return NULL; + } + + /* + * Get the page table entries first to avoid having to unmap things. + */ + paLoPtes = bs3PagingGetPaePte(g_PhysPagingRootLM, BS3_MODE_LM64, UINT64_C(0x00007fffffffe000), false, &rc); + paHiPtes = bs3PagingGetPaePte(g_PhysPagingRootLM, BS3_MODE_LM64, UINT64_C(0xffff800000000000), false, &rc); + if (!paHiPtes || !paLoPtes) + { + Bs3TestPrintf("warning: Bs3PagingSetupCanonicalTraps - failed to get PTEs!\n"); + return NULL; + } + + /* + * Allocate the buffer. Currently using 8KB on each side. + */ + pb = (uint8_t BS3_FAR *)Bs3MemAlloc(BS3MEMKIND_TILED, X86_PAGE_SIZE * 4); + if (pb) + { + RTCCUINTXREG uFlat = Bs3SelPtrToFlat(pb); + + /* + * Inject it into the page tables. + */ + paLoPtes[0].u &= ~X86_PTE_PAE_PG_MASK; + paLoPtes[0].u |= uFlat + X86_PAGE_SIZE * 0; + paLoPtes[1].u &= ~X86_PTE_PAE_PG_MASK; + paLoPtes[1].u |= uFlat + X86_PAGE_SIZE * 1; + + paHiPtes[0].u &= ~X86_PTE_PAE_PG_MASK; + paHiPtes[0].u |= uFlat + X86_PAGE_SIZE * 2; + paHiPtes[1].u &= ~X86_PTE_PAE_PG_MASK; + paHiPtes[1].u |= uFlat + X86_PAGE_SIZE * 3; + ASMReloadCR3(); + + /* + * Update globals and return successfully. + */ + g_uBs3PagingCanonicalTrapsAddr = uFlat; + g_cbBs3PagingCanonicalTraps = X86_PAGE_SIZE * 4; + g_cbBs3PagingOneCanonicalTrap = X86_PAGE_SIZE * 2; + return pb; + } + + Bs3TestPrintf("warning: Bs3PagingSetupCanonicalTraps - out of memory (mode %#x)\n", g_bBs3CurrentMode); + } +#if ARCH_BITS == 16 + else + Bs3TestPrintf("warning: Bs3PagingSetupCanonicalTraps was called in RM or V86 mode (%#x)!\n", g_bBs3CurrentMode); +#endif + } + return NULL; +} + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-Panic.asm b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-Panic.asm new file mode 100644 index 00000000..8310ece0 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-Panic.asm @@ -0,0 +1,38 @@ +; $Id: bs3-cmn-Panic.asm $ +;; @file +; BS3Kit - Bs3Panic, Common. +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + +%include "bs3kit-template-header.mac" + + +BS3_PROC_BEGIN_CMN Bs3Panic, BS3_PBC_HYBRID_0_ARGS + push xBP + mov xBP, xSP + cli +.panic_again: + hlt + jmp .panic_again +BS3_PROC_END_CMN Bs3Panic + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-PerCpuData.c b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-PerCpuData.c new file mode 100644 index 00000000..4e2c82d9 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-PerCpuData.c @@ -0,0 +1,64 @@ +/* $Id: bs3-cmn-PerCpuData.c $ */ +/** @file + * BS3Kit - Per CPU Data. + * + * @remarks Not quite sure how to do per-cpu data yet, but this is stuff + * that eventually needs to be per CPU. + */ + +/* + * Copyright (C) 2007-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include "bs3kit-template-header.h" +#include "bs3-cmn-test.h" + + +/********************************************************************************************************************************* +* Global Variables * +*********************************************************************************************************************************/ +#if ARCH_BITS == 16 + +/** Hint for 16-bit trap handlers regarding the high word of EIP. */ +uint32_t g_uBs3TrapEipHint = 0; + +/** Flat pointer to a BS3TRAPFRAME registered by Bs3TrapSetJmp. + * When this is non-zero, the setjmp is considered armed. */ +uint32_t g_pBs3TrapSetJmpFrame = 0; + +/** The current CPU mode. */ +uint8_t g_bBs3CurrentMode = BS3_MODE_RM; + +uint8_t g_bStupidUnalignedCompiler1 = 0xfe; + +/** Set to disable special V8086 \#GP and \#UD handling in Bs3TrapDefaultHandler. + * This is useful for getting */ +bool volatile g_fBs3TrapNoV86Assist = false; + +/** The context of the last Bs3TrapSetJmp call. + * This will have eax set to 1 and need only be restored when it triggers. */ +BS3REGCTX g_Bs3TrapSetJmpCtx; + +#endif /* ARCH_BITS == 16 */ + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-PicMaskAll.c b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-PicMaskAll.c new file mode 100644 index 00000000..42bb2d33 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-PicMaskAll.c @@ -0,0 +1,41 @@ +/* $Id: bs3-cmn-PicMaskAll.c $ */ +/** @file + * BS3Kit - Masks all IRQs on the PIC. + */ + +/* + * Copyright (C) 2007-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include "bs3kit-template-header.h" +#include <iprt/asm-amd64-x86.h> + + +#undef Bs3PicMaskAll +BS3_CMN_DEF(void, Bs3PicMaskAll,(void)) +{ + ASMOutU8(0xa1, 0xff); + ASMOutU8(0x21, 0xff); +} + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-PicSetup.c b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-PicSetup.c new file mode 100644 index 00000000..0af6bad3 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-PicSetup.c @@ -0,0 +1,80 @@ +/* $Id: bs3-cmn-PicSetup.c $ */ +/** @file + * BS3Kit - PIC Setup. + */ + +/* + * Copyright (C) 2007-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include "bs3kit-template-header.h" +#include <iprt/asm-amd64-x86.h> +#include "bs3-cmn-pic.h" + + + +/** + * Configures the PIC, once only. + * + * Subsequent calls to this function will not do anything. + * + * The PIC will be programmed to use IDT/IVT vectors 0x70 thru 0x7f, auto + * end-of-interrupt, and all IRQs masked. The individual PIC users will have to + * use #Bs3PicUpdateMask unmask their IRQ once they've got all the handlers + * installed. + */ +#undef Bs3PicSetup +BS3_CMN_DEF(void, Bs3PicSetup,(void)) +{ + /* + * The first call configures the PIC to send interrupts to vectors 0x70 thru 0x7f, + * masking all of them. Things producing IRQs is responsible for configure their + * handlers and then(!) use Bs3PicUpdateMask to unmask the IRQ. + */ + if (!g_fBs3PicConfigured) + { + g_fBs3PicConfigured = true; + + /* Start init. */ + ASMOutU8(BS3_PIC_PORT_MASTER, BS3_PIC_CMD_INIT | BS3_PIC_CMD_INIT_F_4STEP); + ASMOutU8(BS3_PIC_PORT_SLAVE, BS3_PIC_CMD_INIT | BS3_PIC_CMD_INIT_F_4STEP); + + /* Set IRQ base. */ + ASMOutU8(BS3_PIC_PORT_MASTER + 1, 0x70); + ASMOutU8(BS3_PIC_PORT_SLAVE + 1, 0x78); + + /* Dunno. */ + ASMOutU8(BS3_PIC_PORT_MASTER + 1, 4); + ASMOutU8(BS3_PIC_PORT_SLAVE + 1, 2); + + /* Set IRQ base. */ + ASMOutU8(BS3_PIC_PORT_MASTER + 1, BS3_PIC_I4_F_AUTO_EOI); + ASMOutU8(BS3_PIC_PORT_SLAVE + 1, BS3_PIC_I4_F_AUTO_EOI); + + /* Mask everything. */ + ASMOutU8(BS3_PIC_PORT_MASTER + 1, UINT8_MAX); + ASMOutU8(BS3_PIC_PORT_SLAVE + 1, UINT8_MAX); + } +} + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-PicUpdateMask.c b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-PicUpdateMask.c new file mode 100644 index 00000000..dbd532e0 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-PicUpdateMask.c @@ -0,0 +1,45 @@ +/* $Id: bs3-cmn-PicUpdateMask.c $ */ +/** @file + * BS3Kit - PIC Setup. + */ + +/* + * Copyright (C) 2007-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include "bs3kit-template-header.h" +#include <iprt/asm-amd64-x86.h> +#include "bs3-cmn-pic.h" + + +#undef Bs3PicUpdateMask +BS3_CMN_DEF(uint16_t, Bs3PicUpdateMask,(uint16_t fAndMask, uint16_t fOrMask)) +{ + uint8_t bPic0Mask = (ASMInU8(BS3_PIC_PORT_MASTER + 1) & (uint8_t)fAndMask) | (uint8_t)fOrMask; + uint8_t bPic1Mask = (ASMInU8(BS3_PIC_PORT_SLAVE + 1) & (fAndMask >> 8)) | (fOrMask >> 8); + ASMOutU8(BS3_PIC_PORT_SLAVE + 1, bPic1Mask); + ASMOutU8(BS3_PIC_PORT_MASTER + 1, bPic0Mask); + return RT_MAKE_U16(bPic0Mask, bPic1Mask); +} + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-PitIrqHandler.c b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-PitIrqHandler.c new file mode 100644 index 00000000..6e65085a --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-PitIrqHandler.c @@ -0,0 +1,67 @@ +/* $Id: bs3-cmn-PitIrqHandler.c $ */ +/** @file + * BS3Kit - The PIT IRQ Handler and associated data. + */ + +/* + * Copyright (C) 2007-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include "bs3kit-template-header.h" +#include <iprt/asm-amd64-x86.h> + + +/********************************************************************************************************************************* +* Global Variables * +*********************************************************************************************************************************/ +#if ARCH_BITS == 16 +/** Nano seconds (approx) since last the PIT timer was started. */ +uint64_t volatile g_cBs3PitNs = 0; +/** Milliseconds seconds (very approx) since last the PIT timer was started. */ +uint64_t volatile g_cBs3PitMs = 0; +/** Number of ticks since last the PIT timer was started. */ +uint32_t volatile g_cBs3PitTicks = 0; +/** The current interval in nanon seconds. */ +uint32_t g_cBs3PitIntervalNs = 0; +/** The current interval in milliseconds (approximately). + * This is 0 if not yet started (used for checking the state internally). */ +uint16_t volatile g_cBs3PitIntervalMs = 0; +/** The current PIT frequency (approximately). 0 if not yet started. */ +uint16_t g_cBs3PitIntervalHz = 0; +#endif + + +BS3_DECL_NEAR_CALLBACK(void) BS3_CMN_NM(bs3PitIrqHandler)(PBS3TRAPFRAME pTrapFrame) +{ + uint16_t cMsIntercal = g_cBs3PitIntervalMs; + if (cMsIntercal) + { + g_cBs3PitMs += cMsIntercal; + g_cBs3PitNs += g_cBs3PitIntervalNs; + g_cBs3PitTicks++; + } + NOREF(pTrapFrame); + ASMOutU8(0x20, 0x20); /** @todo function! */ +} + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-PrintChr.asm b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-PrintChr.asm new file mode 100644 index 00000000..61a753c4 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-PrintChr.asm @@ -0,0 +1,105 @@ +; $Id: bs3-cmn-PrintChr.asm $ +;; @file +; BS3Kit - Bs3PrintChr. +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + + +;********************************************************************************************************************************* +;* Header Files * +;********************************************************************************************************************************* +%include "bs3kit-template-header.mac" + + +;********************************************************************************************************************************* +;* External Symbols * +;********************************************************************************************************************************* +%if TMPL_BITS == 16 +BS3_EXTERN_DATA16 g_bBs3CurrentMode +%endif +BS3_EXTERN_CMN Bs3Syscall + + +TMPL_BEGIN_TEXT + +;; +; @cproto BS3_DECL(void) Bs3PrintChr_c16(char ch); +; +BS3_PROC_BEGIN_CMN Bs3PrintChr, BS3_PBC_NEAR + BS3_CALL_CONV_PROLOG 1 + push xBP + mov xBP, xSP + push xAX + push xCX + push xBX + +%if TMPL_BITS == 16 + ; If we're in real mode or v8086 mode, call the VGA BIOS directly. + mov bl, [g_bBs3CurrentMode] + cmp bl, BS3_MODE_RM + je .do_vga_bios_call + %if 0 + test bl, BS3_MODE_CODE_V86 + jz .do_system_call + %else + jmp .do_system_call + %endif + +.do_vga_bios_call: + mov al, [xBP + xCB*2] ; Load the char + cmp al, 0ah ; \n + je .newline + mov bx, 0ff00h + mov ah, 0eh + int 10h + jmp .return +.newline: + mov ax, 0e0dh ; cmd + '\r'. + mov bx, 0ff00h + int 10h + mov ax, 0e0ah ; cmd + '\n'. + mov bx, 0ff00h + int 10h + jmp .return +%endif + +.do_system_call: + mov cl, [xBP + xCB*2] ; Load the char + mov ax, BS3_SYSCALL_PRINT_CHR + call Bs3Syscall ; near! no BS3_CALL! + +.return: + pop xBX + pop xCX + pop xAX + pop xBP + BS3_CALL_CONV_EPILOG 1 + ret +BS3_PROC_END_CMN Bs3PrintChr + +; +; Generate 16-bit far stub. +; Peformance critical, so don't penalize near calls. +; +BS3_CMN_FAR_STUB Bs3PrintChr, 2 + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-PrintStr.c b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-PrintStr.c new file mode 100644 index 00000000..40d256d3 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-PrintStr.c @@ -0,0 +1,34 @@ +/* $Id: bs3-cmn-PrintStr.c $ */ +/** @file + * BS3Kit - Bs3PrintStr + */ + +/* + * Copyright (C) 2007-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + +#include "bs3kit-template-header.h" + +#undef Bs3PrintStr +BS3_CMN_DEF(void, Bs3PrintStr,(const char BS3_FAR *pszString)) +{ + Bs3PrintStrN(pszString, Bs3StrLen(pszString)); +} + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-PrintStrN.asm b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-PrintStrN.asm new file mode 100644 index 00000000..66b6a89b --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-PrintStrN.asm @@ -0,0 +1,194 @@ +; $Id: bs3-cmn-PrintStrN.asm $ +;; @file +; BS3Kit - Bs3PrintStrN. +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + + +;********************************************************************************************************************************* +;* Header Files * +;********************************************************************************************************************************* +%include "bs3kit-template-header.mac" + + +;********************************************************************************************************************************* +;* External Symbols * +;********************************************************************************************************************************* +%if TMPL_BITS == 16 +BS3_EXTERN_DATA16 g_bBs3CurrentMode +%endif +BS3_EXTERN_CMN Bs3Syscall + + +TMPL_BEGIN_TEXT + +;; +; @cproto BS3_DECL(void) Bs3PrintStrN_c16(const char BS3_FAR *pszString, size_t cchString); +; +; ASSUMES cchString < 64KB! +; +BS3_PROC_BEGIN_CMN Bs3PrintStrN, BS3_PBC_NEAR + BS3_CALL_CONV_PROLOG 2 + push xBP + mov xBP, xSP + push xAX + push xCX + push xBX + push xSI + +%if TMPL_BITS == 16 + ; If we're in real mode or v8086 mode, call the VGA BIOS directly. + mov bl, [g_bBs3CurrentMode] + cmp bl, BS3_MODE_RM + je .do_bios_call + %if 0 + test bl, BS3_MODE_CODE_V86 + jz .do_system_call + %else + jmp .do_system_call + %endif + + ; + ; We can do the work right here. + ; +.do_bios_call: + push ds + lds si, [xBP + xCB + cbCurRetAddr] ; DS:SI -> string. + cld + mov cx, [xBP + xCB + cbCurRetAddr + sCB] ; Use CX for counting down. + call Bs3PrintStrN_c16_CX_Bytes_At_DS_SI + pop ds + jmp .return +%endif + + + ; + ; Need to do system call(s). + ; String goes into CX:xSI, count into DX. + ; + ; We must ensure the string is real-mode addressable first, if not we + ; must do it char-by-char. + ; +.do_system_call: +%if TMPL_BITS == 16 + mov cx, [xBP + xCB + cbCurRetAddr + 2] +%else + mov cx, ds +%endif + mov xSI, [xBP + xCB + cbCurRetAddr] + mov dx, [xBP + xCB + cbCurRetAddr + sCB] +%if TMPL_BITS == 16 + +%else + cmp xSI, _1M + jae .char_by_char +%endif + mov ax, BS3_SYSCALL_PRINT_STR + call Bs3Syscall ; near! no BS3_CALL! + +.return: + pop xSI + pop xBX + pop xCX + pop xAX + pop xBP + BS3_CALL_CONV_EPILOG 2 + BS3_HYBRID_RET + + ; + ; Doesn't look like it's real-mode addressable. So, char-by-char. + ; +.char_by_char: +%if TMPL_BITS == 16 + push es + mov es, cx +%endif + cld + test dx, dx + jz .char_by_char_return +.char_by_char_loop: + mov ax, BS3_SYSCALL_PRINT_CHR + mov cl, [BS3_ONLY_16BIT(es:) xSI] + call Bs3Syscall ; near! no BS3_CALL! + inc xSI + dec xDX + jnz .char_by_char_loop +.char_by_char_return: +%if TMPL_BITS == 16 + pop es +%endif + jmp .return + +BS3_PROC_END_CMN Bs3PrintStrN + + +%if TMPL_BITS == 16 +; +; This code is shared with the system handler. +; +; @param CX Number of byte sto print. +; @param DS:SI The string to print +; @uses AX, BX, CX, SI +; +BS3_PROC_BEGIN Bs3PrintStrN_c16_CX_Bytes_At_DS_SI + CPU 8086 + ; Check if CX is zero first. + test cx, cx + jz .bios_loop_done + + ; The loop, processing the string char-by-char. +.bios_loop: + mov bx, 0ff00h + lodsb ; al = next char + cmp al, 0ah ; \n + je .bios_loop_newline +%ifdef BS3_STRICT + test al, al + jnz .not_zero + hlt +.not_zero: +%endif + mov ah, 0eh +.bios_loop_int10h: + int 10h + loop .bios_loop +.bios_loop_done: + ret + +.bios_loop_newline: + mov ax, 0e0dh ; cmd + '\r'. + int 10h + mov ax, 0e0ah ; cmd + '\n'. + mov bx, 0ff00h + jmp .bios_loop_int10h +BS3_PROC_END Bs3PrintStrN_c16_CX_Bytes_At_DS_SI + + +; +; Generate 16-bit far stub. +; Peformance critical, so don't penalize near calls. +; +BS3_CMN_FAR_STUB Bs3PrintStrN, 6 + +%endif + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-PrintU32.asm b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-PrintU32.asm new file mode 100644 index 00000000..1e6cba45 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-PrintU32.asm @@ -0,0 +1,83 @@ +; $Id: bs3-cmn-PrintU32.asm $ +;; @file +; BS3Kit - Bs3PrintU32, Common. +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + +%include "bs3kit-template-header.mac" + + +BS3_EXTERN_CMN Bs3PrintStr + +;; +; Prints a 32-bit unsigned integer value. +; +; @param [xBP + xCB*2] 32-bit value to format and print. +; +BS3_PROC_BEGIN_CMN Bs3PrintU32, BS3_PBC_HYBRID + BS3_CALL_CONV_PROLOG 1 + push xBP + mov xBP, xSP + push sAX + push sDX + push sCX + push sBX +BONLY16 push ds + + mov eax, [xBP + xCB + cbCurRetAddr] + + ; Allocate a stack buffer and terminate it. ds:bx points ot the end. + sub xSP, 30h +BONLY16 mov bx, ss +BONLY16 mov ds, bx + mov xBX, xSP + add xBX, 2fh + mov byte [xBX], 0 + + mov ecx, 10 ; what to divide by +.next: + xor edx, edx + div ecx ; edx:eax / ecx -> eax and rest in edx. + add dl, '0' + dec xBX + mov [BS3_ONLY_16BIT(ss:)xBX], dl + cmp eax, 0 + jnz .next + + ; Print the string. +BONLY64 add rsp, 18h +BONLY16 push ss + push xBX + BS3_CALL Bs3PrintStr, 1 + + add xSP, 30h + BS3_IF_16_32_64BIT(2, 0, 18h) + xCB +BONLY16 pop ds + pop sBX + pop sCX + pop sDX + pop sAX + leave + BS3_CALL_CONV_EPILOG 1 + BS3_HYBRID_RET +BS3_PROC_END_CMN Bs3PrintU32 + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-PrintX32.asm b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-PrintX32.asm new file mode 100644 index 00000000..2cd1c8a8 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-PrintX32.asm @@ -0,0 +1,87 @@ +; $Id: bs3-cmn-PrintX32.asm $ +;; @file +; BS3Kit - Bs3PrintU32, Common. +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + +%include "bs3kit-template-header.mac" + + +BS3_EXTERN_CMN Bs3PrintStr + +;; +; Prints a 32-bit unsigned integer value as hex. +; +; @param [xBP + xCB*2] 32-bit value to format and print. +; +BS3_PROC_BEGIN_CMN Bs3PrintX32, BS3_PBC_HYBRID + BS3_CALL_CONV_PROLOG 1 + push xBP + mov xBP, xSP + push sAX + push sDX + push sCX + push sBX +BONLY16 push ds + + mov eax, [xBP + xCB + cbCurRetAddr] + + ; Allocate a stack buffer and terminate it. ds:bx points ot the end. + sub xSP, 30h +BONLY16 mov bx, ss +BONLY16 mov ds, bx + mov xBX, xSP + add xBX, 2fh + mov byte [xBX], 0 + + mov ecx, 16 ; what to divide by +.next: + xor edx, edx + div ecx ; edx:eax / ecx -> eax and rest in edx. + cmp dl, 10 + jb .decimal + add dl, 'a' - '0' - 10 +.decimal: + add dl, '0' + dec xBX + mov [BS3_ONLY_16BIT(ss:)xBX], dl + cmp eax, 0 + jnz .next + + ; Print the string. +BONLY64 add rsp, 18h +BONLY16 push ss + push xBX + BS3_CALL Bs3PrintStr, 1 + + add xSP, 30h + BS3_IF_16_32_64BIT(2, 0, 18h) + xCB +BONLY16 pop ds + pop sBX + pop sCX + pop sDX + pop sAX + leave + BS3_CALL_CONV_EPILOG 1 + BS3_HYBRID_RET +BS3_PROC_END_CMN Bs3PrintX32 + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-Printf.c b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-Printf.c new file mode 100644 index 00000000..b0284126 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-Printf.c @@ -0,0 +1,85 @@ +/* $Id: bs3-cmn-Printf.c $ */ +/** @file + * BS3Kit - Bs3Printf, Bs3PrintfV + */ + +/* + * Copyright (C) 2007-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include "bs3kit-template-header.h" +#include <iprt/ctype.h> + + +/********************************************************************************************************************************* +* Structures and Typedefs * +*********************************************************************************************************************************/ +/** Output buffering for Bs3TestPrintfV. */ +typedef struct BS3PRINTBUF +{ + uint8_t cchBuf; + char achBuf[79]; +} BS3PRINTBUF; + + +static BS3_DECL_CALLBACK(size_t) bs3PrintFmtOutput(char ch, void BS3_FAR *pvUser) +{ + BS3PRINTBUF BS3_FAR *pBuf = (BS3PRINTBUF BS3_FAR *)pvUser; + if (ch != '\0') + { + BS3_ASSERT(pBuf->cchBuf < RT_ELEMENTS(pBuf->achBuf)); + pBuf->achBuf[pBuf->cchBuf++] = ch; + + /* Whether to flush the buffer. We do line flushing here to avoid + dropping too much info when the formatter crashes on bad input. */ + if ( pBuf->cchBuf < RT_ELEMENTS(pBuf->achBuf) + && ch != '\n') + return 1; + } + Bs3PrintStrN(&pBuf->achBuf[0], pBuf->cchBuf); + pBuf->cchBuf = 0; + return ch != '\0'; +} + + +#undef Bs3PrintfV +BS3_CMN_DEF(size_t, Bs3PrintfV,(const char BS3_FAR *pszFormat, va_list BS3_FAR va)) +{ + BS3PRINTBUF Buf; + Buf.cchBuf = 0; + return Bs3StrFormatV(pszFormat, va, bs3PrintFmtOutput, &Buf); +} + + +#undef Bs3Printf +BS3_CMN_DEF(size_t, Bs3Printf,(const char BS3_FAR *pszFormat, ...)) +{ + size_t cchRet; + va_list va; + va_start(va, pszFormat); + cchRet = BS3_CMN_NM(Bs3PrintfV)(pszFormat, va); + va_end(va); + return cchRet; +} + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-RegCtxConvertToRingX.c b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-RegCtxConvertToRingX.c new file mode 100644 index 00000000..d14c173e --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-RegCtxConvertToRingX.c @@ -0,0 +1,169 @@ +/* $Id: bs3-cmn-RegCtxConvertToRingX.c $ */ +/** @file + * BS3Kit - Bs3RegCtxConvertToRingX + */ + +/* + * Copyright (C) 2007-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include "bs3kit-template-header.h" + + +/** + * Transforms a real mode segment into a protected mode selector. + * + * @returns Protected mode selector. + * @param uSeg The real mode segment. + * @param bRing The target ring. + */ +static uint16_t bs3RegCtxConvertRealSegToRingX(uint16_t uSeg, uint8_t bRing) +{ + uint16_t uSel; + if ( uSeg == 0 + || uSeg == BS3_SEL_R0_SS16) + uSel = BS3_SEL_R0_SS16 + ((uint16_t)bRing << BS3_SEL_RING_SHIFT); + else if ( uSeg == (BS3_ADDR_BS3TEXT16 >> 4) + || uSeg == BS3_SEL_R0_CS16) + uSel = BS3_SEL_R0_CS16 + ((uint16_t)bRing << BS3_SEL_RING_SHIFT); + else if ( uSeg == (BS3_ADDR_BS3DATA16 >> 4) + || uSeg == BS3_SEL_R0_DS16) + uSel = BS3_SEL_R0_DS16 + ((uint16_t)bRing << BS3_SEL_RING_SHIFT); + else if (uSeg == (BS3_ADDR_BS3SYSTEM16 >> 4)) + uSel = BS3_SEL_SYSTEM16; + else if (!(uSeg & 0xfff)) + uSel = (uSeg >> (12 - X86_SEL_SHIFT)) + BS3_SEL_TILED; + else if (uSeg == BS3_SEL_R0_DS16) + uSel = (uSeg >> (12 - X86_SEL_SHIFT)) + BS3_SEL_TILED; + else + { + Bs3Printf("uSeg=%#x\n", uSeg); + BS3_ASSERT(0); + return 0; + } + uSel |= bRing; + return uSel; +} + + +/** + * Transforms a protected mode selector to a different ring. + * + * @returns Adjusted protected mode selector. + * @param uSel The current selector value. + * @param bRing The target ring. + * @param iReg Register index. + */ +static uint16_t bs3RegCtxConvertProtSelToRingX(uint16_t uSel, uint8_t bRing, uint8_t iReg) +{ + if ( uSel > X86_SEL_RPL + && !(uSel & X86_SEL_LDT) ) + { + if (uSel >= BS3_SEL_R0_FIRST && uSel < BS3_SEL_R0_FIRST + (5 << BS3_SEL_RING_SHIFT)) + { + /* Convert BS3_SEL_R*_XXX to the target ring. */ + uSel &= BS3_SEL_RING_SUB_MASK; + uSel |= bRing; + uSel += BS3_SEL_R0_FIRST; + uSel += (uint16_t)bRing << BS3_SEL_RING_SHIFT; + } + else + { + /* Convert TEXT16 and DATA16 to BS3_SEL_R*_XXX. */ + uint16_t const uSelRaw = uSel & X86_SEL_MASK_OFF_RPL; + if (uSelRaw == BS3_SEL_TEXT16) + uSel = (BS3_SEL_R0_CS16 | bRing) + ((uint16_t)bRing << BS3_SEL_RING_SHIFT); + else if (uSelRaw == BS3_SEL_DATA16) + uSel = (BS3_SEL_R0_DS16 | bRing) + ((uint16_t)bRing << BS3_SEL_RING_SHIFT); + /* CS and SS must have CPL == DPL. So, convert to standard selectors as we're + usually here because Bs3SwitchToRing0 was called to get out of a test situation. */ + else if (iReg == X86_SREG_CS || iReg == X86_SREG_SS) + { + if ( Bs3Gdt[uSel >> X86_SEL_SHIFT].Gen.u1Long + && BS3_MODE_IS_64BIT_SYS(g_bBs3CurrentMode) ) + uSel = iReg == X86_SREG_CS ? BS3_SEL_R0_CS64 : BS3_SEL_R0_DS64; + else + { + uint32_t uFlat = Bs3SelFar32ToFlat32(0, uSel); + bool fDefBig = Bs3Gdt[uSel >> X86_SEL_SHIFT].Gen.u1DefBig; + if (!fDefBig && uFlat == BS3_ADDR_BS3TEXT16 && iReg == X86_SREG_CS) + uSel = BS3_SEL_R0_CS16; + else if (!fDefBig && uFlat == 0 && iReg == X86_SREG_SS) + uSel = BS3_SEL_R0_SS16; + else if (fDefBig && uFlat == 0) + uSel = iReg == X86_SREG_CS ? BS3_SEL_R0_CS32 : BS3_SEL_R0_SS32; + else + { + Bs3Printf("uSel=%#x iReg=%d\n", uSel, iReg); + BS3_ASSERT(0); + return uSel; + } + uSel |= bRing; + uSel += (uint16_t)bRing << BS3_SEL_RING_SHIFT; + } + } + /* Adjust the RPL on tiled and MMIO selectors. */ + else if ( uSelRaw == BS3_SEL_VMMDEV_MMIO16 + || uSelRaw >= BS3_SEL_TILED) + uSel = uSelRaw | bRing; + } + } + return uSel; +} + + +/** + * Transforms a register context to a different ring. + * + * @param pRegCtx The register context. + * @param bRing The target ring (0..3). + */ +#undef Bs3RegCtxConvertToRingX +BS3_CMN_DEF(void, Bs3RegCtxConvertToRingX,(PBS3REGCTX pRegCtx, uint8_t bRing)) +{ + if ( (pRegCtx->rflags.u32 & X86_EFL_VM) + || pRegCtx->bMode == BS3_MODE_RM) + { + pRegCtx->rflags.u32 &= ~X86_EFL_VM; + pRegCtx->bMode &= ~BS3_MODE_CODE_MASK; + pRegCtx->bMode |= BS3_MODE_CODE_16; + pRegCtx->cs = bs3RegCtxConvertRealSegToRingX(pRegCtx->cs, bRing); + pRegCtx->ss = bs3RegCtxConvertRealSegToRingX(pRegCtx->ss, bRing); + pRegCtx->ds = bs3RegCtxConvertRealSegToRingX(pRegCtx->ds, bRing); + pRegCtx->es = bs3RegCtxConvertRealSegToRingX(pRegCtx->es, bRing); + pRegCtx->fs = bs3RegCtxConvertRealSegToRingX(pRegCtx->fs, bRing); + pRegCtx->gs = bs3RegCtxConvertRealSegToRingX(pRegCtx->gs, bRing); + } + else + { + pRegCtx->cs = bs3RegCtxConvertProtSelToRingX(pRegCtx->cs, bRing, X86_SREG_CS); + pRegCtx->ss = bs3RegCtxConvertProtSelToRingX(pRegCtx->ss, bRing, X86_SREG_SS); + pRegCtx->ds = bs3RegCtxConvertProtSelToRingX(pRegCtx->ds, bRing, X86_SREG_DS); + pRegCtx->es = bs3RegCtxConvertProtSelToRingX(pRegCtx->es, bRing, X86_SREG_ES); + pRegCtx->fs = bs3RegCtxConvertProtSelToRingX(pRegCtx->fs, bRing, X86_SREG_FS); + pRegCtx->gs = bs3RegCtxConvertProtSelToRingX(pRegCtx->gs, bRing, X86_SREG_GS); + } + pRegCtx->bCpl = bRing; +} + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-RegCtxPrint.c b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-RegCtxPrint.c new file mode 100644 index 00000000..734a63f9 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-RegCtxPrint.c @@ -0,0 +1,67 @@ +/* $Id: bs3-cmn-RegCtxPrint.c $ */ +/** @file + * BS3Kit - Bs3RegCtxPrint + */ + +/* + * Copyright (C) 2007-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include "bs3kit-template-header.h" + + +#undef Bs3RegCtxPrint +BS3_CMN_DEF(void, Bs3RegCtxPrint,(PCBS3REGCTX pRegCtx)) +{ + if (!BS3_MODE_IS_64BIT_CODE(pRegCtx->bMode)) + { + Bs3TestPrintf("eax=%08RX32 ebx=%08RX32 ecx=%08RX32 edx=%08RX32 esi=%08RX32 edi=%08RX32\n", + pRegCtx->rax.u32, pRegCtx->rbx.u32, pRegCtx->rcx.u32, pRegCtx->rdx.u32, pRegCtx->rsi.u32, pRegCtx->rdi.u32); + Bs3TestPrintf("eip=%08RX32 esp=%08RX32 ebp=%08RX32 efl=%08RX32 cr0=%08RX32 cr2=%08RX32\n", + pRegCtx->rip.u32, pRegCtx->rsp.u32, pRegCtx->rbp.u32, pRegCtx->rflags.u32, + pRegCtx->cr0.u32, pRegCtx->cr2.u32); + Bs3TestPrintf("cs=%04RX16 ds=%04RX16 es=%04RX16 fs=%04RX16 gs=%04RX16 ss=%04RX16 cr3=%08RX32 cr4=%08RX32\n", + pRegCtx->cs, pRegCtx->ds, pRegCtx->es, pRegCtx->fs, pRegCtx->gs, pRegCtx->ss, + pRegCtx->cr3.u32, pRegCtx->cr4.u32); + } + else + { + Bs3TestPrintf("rax=%016RX64 rbx=%016RX64 rcx=%016RX64 rdx=%016RX64\n", + pRegCtx->rax.u64, pRegCtx->rbx.u64, pRegCtx->rcx.u64, pRegCtx->rdx.u64); + Bs3TestPrintf("rsi=%016RX64 rdi=%016RX64 r8 =%016RX64 r9 =%016RX64\n", + pRegCtx->rsi.u64, pRegCtx->rdi.u64, pRegCtx->r8.u64, pRegCtx->r9.u64); + Bs3TestPrintf("r10=%016RX64 r11=%016RX64 r12=%016RX64 r13=%016RX64\n", + pRegCtx->r10.u64, pRegCtx->r11.u64, pRegCtx->r12.u64, pRegCtx->r13.u64); + Bs3TestPrintf("r14=%016RX64 r15=%016RX64 cr0=%08RX64 cr4=%08RX64 cr3=%08RX64\n", + pRegCtx->r14.u64, pRegCtx->r15.u64, pRegCtx->cr0.u64, pRegCtx->cr4.u64, pRegCtx->cr3.u64); + Bs3TestPrintf("rip=%016RX64 rsp=%016RX64 rbp=%016RX64 rfl=%08RX64\n", + pRegCtx->rip.u64, pRegCtx->rsp.u64, pRegCtx->rbp.u64, pRegCtx->rflags.u32); + Bs3TestPrintf("cs=%04RX16 ds=%04RX16 es=%04RX16 fs=%04RX16 gs=%04RX16 ss=%04RX16 cr2=%016RX64\n", + pRegCtx->cs, pRegCtx->ds, pRegCtx->es, pRegCtx->fs, pRegCtx->gs, pRegCtx->ss, + pRegCtx->cr3.u64, pRegCtx->cr2.u64); + } + Bs3TestPrintf("tr=%04RX16 ldtr=%04RX16 cpl=%d mode=%#x fbFlags=%#x\n", + pRegCtx->tr, pRegCtx->ldtr, pRegCtx->bCpl, pRegCtx->bMode, pRegCtx->fbFlags); +} + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-RegCtxRestore.asm b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-RegCtxRestore.asm new file mode 100644 index 00000000..628203c6 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-RegCtxRestore.asm @@ -0,0 +1,596 @@ +; $Id: bs3-cmn-RegCtxRestore.asm $ +;; @file +; BS3Kit - Bs3RegCtxRestore. +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + +%include "bs3kit-template-header.mac" + + +BS3_EXTERN_SYSTEM16 Bs3Gdt +BS3_EXTERN_DATA16 g_bBs3CurrentMode +BS3_EXTERN_DATA16 g_fBs3TrapNoV86Assist +%if TMPL_BITS != 64 +BS3_EXTERN_DATA16 g_uBs3CpuDetected +%endif +TMPL_BEGIN_TEXT +BS3_EXTERN_CMN Bs3Syscall +BS3_EXTERN_CMN Bs3Panic +TMPL_BEGIN_TEXT + + +;; +; Restores the given register context. +; +; @param pRegCtx +; @param fFlags +; @uses All registers and may trash stack immediately before the resume point. +; +; @note Only respects the BS3_MODE_CODE_MASK part of pRegCtx->bMode. +; +%if TMPL_BITS == 16 +BS3_PROC_BEGIN_CMN Bs3RegCtxRestore_aborts, BS3_PBC_FAR ; special entry point for when watcom applies __aborts +BS3_PROC_BEGIN_CMN Bs3RegCtxRestore_aborts, BS3_PBC_NEAR ; special entry point for when watcom applies __aborts + CPU 8086 + xor xAX, xAX + push xAX ; fake return address. + push xAX + jmp _Bs3RegCtxRestore_f16 +%elif TMPL_BITS == 32 +BS3_PROC_BEGIN_CMN Bs3RegCtxRestore_aborts, BS3_PBC_NEAR ; special entry point for when watcom applies __aborts + push 0feedfaceh ; fake return address. +%endif +BS3_PROC_BEGIN_CMN Bs3RegCtxRestore, BS3_PBC_HYBRID + BS3_CALL_CONV_PROLOG 2 + push xBP + mov xBP, xSP + + ; + ; If we're not in ring-0, ask the kernel to restore it for us (quicker + ; and less problematic if we're in a funny context right now with weird + ; CS or SS values). + ; +%if TMPL_BITS == 16 + cmp byte [BS3_DATA16_WRT(g_bBs3CurrentMode)], BS3_MODE_RM + je .in_ring0 + test byte [BS3_DATA16_WRT(g_bBs3CurrentMode)], BS3_MODE_CODE_V86 + jnz .do_syscall_restore_ctx +%endif + mov ax, ss + test al, 3 + jz .in_ring0 + +.do_syscall_restore_ctx: +%if TMPL_BITS != 16 +.do_syscall_restore_ctx_restore_ds: + mov cx, ds + mov xSI, [xBP + xCB*2] + movzx edx, word [xBP + xCB*3] + mov eax, BS3_SYSCALL_RESTORE_CTX +%else + mov si, [bp + xCB + cbCurRetAddr] + mov cx, [bp + xCB + cbCurRetAddr + 2] + mov dx, [bp + xCB + cbCurRetAddr + sCB] + mov ax, BS3_SYSCALL_RESTORE_CTX +%endif + call Bs3Syscall + call Bs3Panic + +%if TMPL_BITS == 16 +.do_syscall_restore_ctx_restore_ds: + push es + pop ds + jmp .do_syscall_restore_ctx +%endif + + ; + ; Prologue. Loads ES with BS3KIT_GRPNM_DATA16/FLAT (for g_bBs3CurrentMode + ; and g_uBs3CpuDetected), DS:xBX with pRegCtx and fFlags into xCX. + ; +.in_ring0: +%if TMPL_BITS == 16 + mov ax, BS3_SEL_DATA16 + mov es, ax + lds bx, [bp + xCB + cbCurRetAddr] + mov cx, [bp + xCB + cbCurRetAddr + sCB] +%elif TMPL_BITS == 32 + mov ax, BS3_SEL_R0_DS32 + mov ds, ax + mov xBX, [xBP + xCB*2] + movzx xCX, word [xBP + xCB*3] +%else + mov ax, BS3_SEL_R0_DS64 + mov ds, ax + mov xBX, [xBP + xCB*2] + movzx xCX, word [xBP + xCB*3] +%endif + + +%if TMPL_BITS != 64 + ; Restoring a 64-bit context is best done from 64-bit code. + mov al, [xBX + BS3REGCTX.bMode] + test al, BS3_MODE_CODE_64 + jnz .do_syscall_restore_ctx_restore_ds +%endif + + ; The remainder must be done with interrupts disabled. + cli + + ; + ; Update g_bs3CurrentMode. + ; +%if TMPL_BITS == 64 + mov al, [xBX + BS3REGCTX.bMode] +%endif + and al, BS3_MODE_CODE_MASK + mov ah, [BS3_ONLY_16BIT(es:) BS3_DATA16_WRT(g_bBs3CurrentMode)] + and ah, ~BS3_MODE_CODE_MASK + or al, ah + mov [BS3_ONLY_16BIT(es:) BS3_DATA16_WRT(g_bBs3CurrentMode)], al + + ; + ; Set g_fBs3TrapNoV86Assist if BS3REGCTXRESTORE_F_NO_V86_ASSIST specified. + ; + test cl, BS3REGCTXRESTORE_F_NO_V86_ASSIST + jz .no_f_no_v86_assist + mov byte [BS3_ONLY_16BIT(es:) BS3_DATA16_WRT(g_fBs3TrapNoV86Assist)], 1 +.no_f_no_v86_assist: + +%if TMPL_BITS == 16 + ; + ; Check what the CPU can do. + ; + cmp byte [es:BS3_DATA16_WRT(g_uBs3CpuDetected)], BS3CPU_80386 + jae .restore_full + + ; Do the 80286 specifics first. + cmp byte [es:BS3_DATA16_WRT(g_uBs3CpuDetected)], BS3CPU_80286 + jb .restore_16_bit_ancient + CPU 286 + + lmsw [bx + BS3REGCTX.cr0] + cmp byte [es:BS3_DATA16_WRT(g_bBs3CurrentMode)], BS3_MODE_RM + je .restore_16_bit_ancient + lldt [bx + BS3REGCTX.ldtr] + + ; TR - complicated because we need to clear the busy bit. ASSUMES GDT. + str ax + cmp ax, [bx + BS3REGCTX.tr] + je .skip_tr_286 + + mov di, word [xBX + BS3REGCTX.tr] + or di, di ; check for null. + jz .load_tr_286 + + push ds + push BS3_SEL_SYSTEM16 + pop ds + add di, Bs3Gdt wrt BS3SYSTEM16 + add di, X86DESCGENERIC_BIT_OFF_TYPE / 8 + and byte [di], ~(X86_SEL_TYPE_SYS_TSS_BUSY_MASK << (X86DESCGENERIC_BIT_OFF_TYPE % 8)) + pop ds + +.load_tr_286: + ltr [bx + BS3REGCTX.tr] +.skip_tr_286: + +.restore_16_bit_ancient: + CPU 8086 + ; Some general registers. + mov cx, [bx + BS3REGCTX.rcx] + mov dx, [bx + BS3REGCTX.rdx] + + ; Do the return frame and final registers (keep short as we're not quite + ; NMI safe here if pRegCtx is on the stack). + cmp byte [es:BS3_DATA16_WRT(g_bBs3CurrentMode)], BS3_MODE_RM + mov di, [bx + BS3REGCTX.rsp] + je .restore_16_bit_same_privilege + cmp byte [bx + BS3REGCTX.bCpl], 0 + je .restore_16_bit_same_privilege + + mov ax, [bx + BS3REGCTX.ss] + push ax + mov ax, [bx + BS3REGCTX.rsp] + push ax + mov ax, [bx + BS3REGCTX.rflags] + push ax + mov ax, [bx + BS3REGCTX.cs] + push ax + mov ax, [bx + BS3REGCTX.rip] + push ax + mov ax, [bx + BS3REGCTX.ds] + push ax + + mov si, [bx + BS3REGCTX.rsi] + mov di, [bx + BS3REGCTX.rdi] + mov es, [bx + BS3REGCTX.es] + mov ax, [bx + BS3REGCTX.rax] + mov bp, [bx + BS3REGCTX.rbp] ; restore late for better stacks. + mov bx, [bx + BS3REGCTX.rbx] + + pop ds + iret + +.restore_16_bit_same_privilege: + sub di, 2*5 ; iret frame + pop ds + mov si, di + mov es, [bx + BS3REGCTX.ss] ; ES is target stack segment. + cld + + mov ax, [bx + BS3REGCTX.ds] + stosw + mov ax, [bx + BS3REGCTX.rbp] ; Restore esp as late as possible for better stacks. + stosw + mov ax, [bx + BS3REGCTX.rip] + stosw + mov ax, [bx + BS3REGCTX.cs] + stosw + mov ax, [bx + BS3REGCTX.rflags] + stosw + + mov di, [bx + BS3REGCTX.rdi] + mov es, [bx + BS3REGCTX.es] + mov ax, [bx + BS3REGCTX.rax] + mov ss, [bx + BS3REGCTX.ss] + mov sp, si + mov si, [bx + BS3REGCTX.rsi] + mov bx, [bx + BS3REGCTX.rbx] + + pop ds + pop bp + iret + + CPU 386 +%endif + +.restore_full: + ; + ; 80386 or later. + ; For 32-bit and 16-bit versions, we always use 32-bit iret. + ; + + ; Restore control registers if they've changed. + test cl, BS3REGCTXRESTORE_F_SKIP_CRX + jnz .skip_control_regs + test byte [xBX + BS3REGCTX.fbFlags], BS3REG_CTX_F_NO_CR0_IS_MSW | BS3REG_CTX_F_NO_CR2_CR3 + jnz .skip_control_regs + + test byte [xBX + BS3REGCTX.fbFlags], BS3REG_CTX_F_NO_CR4 ; (old 486s and 386s didn't have CR4) + jnz .skip_cr4 +%if TMPL_BITS != 64 + test word [BS3_ONLY_16BIT(es:) BS3_DATA16_WRT(g_uBs3CpuDetected)], BS3CPU_F_CPUID + jz .skip_cr4 +%endif + mov sAX, [xBX + BS3REGCTX.cr4] + mov sDX, cr4 + cmp sAX, sDX + je .skip_cr4 + mov cr4, sAX +.skip_cr4: + + mov sAX, [xBX + BS3REGCTX.cr0] + mov sDX, cr0 + cmp sAX, sDX + je .skip_cr0 + mov cr0, sAX +.skip_cr0: + + mov sAX, [xBX + BS3REGCTX.cr3] + mov sDX, cr3 + cmp sAX, sDX + je .skip_cr3 + mov cr3, sAX +.skip_cr3: + + mov sAX, [xBX + BS3REGCTX.cr2] + mov sDX, cr2 + cmp sAX, sDX + je .skip_cr2 + mov cr2, sAX +.skip_cr2: + + ; + ; Restore + ; +%if TMPL_BITS != 64 + ; We cannot restore ldtr and tr if we're in real-mode. + cmp byte [BS3_ONLY_16BIT(es:) BS3_DATA16_WRT(g_bBs3CurrentMode)], BS3_MODE_RM + je .skip_control_regs +%endif + test byte [xBX + BS3REGCTX.fbFlags], BS3REG_CTX_F_NO_TR_LDTR + jnz .skip_control_regs + + ; LDTR + sldt ax + cmp ax, [xBX + BS3REGCTX.ldtr] + je .skip_ldtr + lldt [xBX + BS3REGCTX.ldtr] +.skip_ldtr: + + ; TR - complicated because we need to clear the busy bit. ASSUMES GDT. + str ax + cmp ax, [xBX + BS3REGCTX.tr] + je .skip_tr + + movzx edi, word [xBX + BS3REGCTX.tr] + or edi, edi ; check for null. + jz .load_tr + +%if TMPL_BITS == 16 + push ds + push BS3_SEL_SYSTEM16 + pop ds + add xDI, Bs3Gdt wrt BS3SYSTEM16 +%else + add xDI, Bs3Gdt wrt FLAT +%endif + add xDI, X86DESCGENERIC_BIT_OFF_TYPE / 8 + and byte [xDI], ~(X86_SEL_TYPE_SYS_TSS_BUSY_MASK << (X86DESCGENERIC_BIT_OFF_TYPE % 8)) +%if TMPL_BITS == 16 + pop ds +%endif +.load_tr: + ltr [xBX + BS3REGCTX.tr] +.skip_tr: + +.skip_control_regs: + + +%if TMPL_BITS == 64 + ; + ; 64-bit returns are simple because ss:rsp are always restored. + ; + ; A small complication here when returning to a 16-bit stack (only + ; applicable to 16-bit and 32-bit code), iret doesn't touch the high + ; ESP bits and we can easily later end up with trap handlers + ; accessing memory never intended as stack. + ; + mov rcx, qword [xBX + BS3REGCTX.rsp] ; (also 1st param for conv call below) + cmp rcx, 0ffffh + ja .iretq_maybe_annoying_16bit_stack + cmp rsp, 0ffffh + ja .iretq_maybe_annoying_16bit_stack +.iretq_ok: + + movzx eax, word [xBX + BS3REGCTX.ss] + push rax + push qword [xBX + BS3REGCTX.rsp] + push qword [xBX + BS3REGCTX.rflags] + movzx eax, word [xBX + BS3REGCTX.cs] + push rax + push qword [xBX + BS3REGCTX.rip] + +.iretq_restore_regs_and_iret: + mov es, [xBX + BS3REGCTX.es] + mov fs, [xBX + BS3REGCTX.fs] + mov gs, [xBX + BS3REGCTX.gs] + mov rax, [xBX + BS3REGCTX.rax] + mov rdx, [xBX + BS3REGCTX.rdx] + mov rcx, [xBX + BS3REGCTX.rcx] + mov rsi, [xBX + BS3REGCTX.rsi] + mov rdi, [xBX + BS3REGCTX.rdi] + mov r8, [xBX + BS3REGCTX.r8] + mov r9, [xBX + BS3REGCTX.r9] + mov r10, [xBX + BS3REGCTX.r10] + mov r11, [xBX + BS3REGCTX.r11] + mov r12, [xBX + BS3REGCTX.r12] + mov r13, [xBX + BS3REGCTX.r13] + mov r14, [xBX + BS3REGCTX.r14] + mov r15, [xBX + BS3REGCTX.r15] + mov rbp, [xBX + BS3REGCTX.rbp] ; restore late for better stacks. + mov ds, [xBX + BS3REGCTX.ds] + mov rbx, [xBX + BS3REGCTX.rbx] + iretq + +.iretq_maybe_annoying_16bit_stack: + movzx edx, word [xBX + BS3REGCTX.ss] ; (also 2nd param for conv call below) + lar eax, dx + jnz .iretq_ok + test eax, X86LAR_F_D | X86LAR_F_L + jnz .iretq_ok ; Returning to a big of long SS needs not extra work. + + lar eax, word [xBX + BS3REGCTX.cs] + jnz .iretq_ok + test eax, X86LAR_F_L + jnz .iretq_ok ; It doesn't matter when returning to 64-bit code. + + ; Convert ss:sp to a flat address. + BS3_EXTERN_CMN Bs3SelFar32ToFlat32NoClobber + call Bs3SelFar32ToFlat32NoClobber + mov rdi, rax + + ; 2nd return frame (32-bit, same CPL). + mov eax, [xBX + BS3REGCTX.rflags] + mov [rdi - 4], eax + movzx eax, word [xBX + BS3REGCTX.cs] + mov [rdi - 8], eax + mov eax, [xBX + BS3REGCTX.rip] + mov [rdi - 12], eax + mov ecx, [xBX + BS3REGCTX.rsp] + sub cx, 12 + mov [rdi - 16], ecx + + ; 1st return frame. + movzx eax, word [xBX + BS3REGCTX.ss] + push rax ; new 16-bit SS + sub cx, 4 + push rcx ; new esp + mov rax, [xBX + BS3REGCTX.rflags] + and rax, ~(X86_EFL_NT | X86_EFL_TF) + push rax ; rflags + AssertCompile(BS3_SEL_RING_SHIFT == 8) + mov eax, BS3_SEL_R0_CS32 + add ah, [xBX + BS3REGCTX.bCpl] + or al, [xBX + BS3REGCTX.bCpl] + push rax ; 32-bit CS + push .iretq_pop_real_esp_and_iret_again wrt FLAT + jmp .iretq_restore_regs_and_iret + + BS3_SET_BITS 32 +.iretq_pop_real_esp_and_iret_again: + pop esp + iretd + BS3_SET_BITS 64 + +%else + ; + ; 32-bit/16-bit is more complicated as we have three different iret frames. + ; + mov al, [BS3_ONLY_16BIT(es:) BS3_DATA16_WRT(g_bBs3CurrentMode)] + cmp al, BS3_MODE_RM + je .iretd_same_cpl_rm + + test dword [xBX + BS3REGCTX.rflags], X86_EFL_VM + jnz .restore_v8086 + + cmp byte [xBX + BS3REGCTX.bCpl], 0 + je .iretd_same_cpl + + ; + ; IRETD to different CPL. Frame includes ss:esp. + ; +.iretd_different_cpl: + or eax, 0ffffffffh ; poison unused parts of segment pushes + mov ax, [xBX + BS3REGCTX.ss] + push eax + push dword [xBX + BS3REGCTX.rsp] + push dword [xBX + BS3REGCTX.rflags] + mov ax, [xBX + BS3REGCTX.cs] + push eax + push dword [xBX + BS3REGCTX.rip] + push dword [xBX + BS3REGCTX.rbp] ; Restore esp as late as possible for better stacks. + mov ax, [xBX + BS3REGCTX.ds] + push xAX + + mov es, [xBX + BS3REGCTX.es] + mov fs, [xBX + BS3REGCTX.fs] + mov gs, [xBX + BS3REGCTX.gs] + mov eax, [xBX + BS3REGCTX.rax] + mov edx, [xBX + BS3REGCTX.rdx] + mov ecx, [xBX + BS3REGCTX.rcx] + mov esi, [xBX + BS3REGCTX.rsi] + %if TMPL_BITS == 16 ; if SS is 16-bit, we will not be able to restore the high word. +;; @todo 16-bit stack will also mess us up in 32-bit code, so this needs fixing (see 64-bit above). + mov edi, [xBX + BS3REGCTX.rsp] + mov di, sp + mov esp, edi + %endif + mov edi, [xBX + BS3REGCTX.rdi] + mov ebx, [xBX + BS3REGCTX.rbx] + + pop ds + pop ebp + iretd + + ; + ; IRETD to same CPL (includes real mode). + ; +.iretd_same_cpl_rm: + ; Use STOSD/ES:EDI to create the frame. + mov es, [xBX + BS3REGCTX.ss] + mov esi, [xBX + BS3REGCTX.rsp] + sub esi, 5*4 + movzx edi, si + jmp .es_edi_is_pointing_to_return_frame_location + +.iretd_same_cpl: + ; Use STOSD/ES:EDI to create the frame. + mov es, [xBX + BS3REGCTX.ss] + mov edi, [xBX + BS3REGCTX.rsp] + sub edi, 5*4 + + ; Which part of the stack pointer is actually used depends on the SS.D/B bit. + lar eax, [xBX + BS3REGCTX.ss] + jnz .using_32_bit_stack_pointer + test eax, X86LAR_F_D + jnz .using_32_bit_stack_pointer +.using_16_bit_stack_pointer: + mov esi, edi ; save rsp for later. + movzx edi, di + jmp .es_edi_is_pointing_to_return_frame_location +.using_32_bit_stack_pointer: + mov esi, edi +.es_edi_is_pointing_to_return_frame_location: + cld + mov ax, [xBX + BS3REGCTX.ds] + o32 stosd + mov eax, [xBX + BS3REGCTX.rbp] ; Restore esp as late as possible for better stacks. + o32 stosd + mov eax, [xBX + BS3REGCTX.rip] + o32 stosd + mov ax, [xBX + BS3REGCTX.cs] + o32 stosd + mov eax, [xBX + BS3REGCTX.rflags] + o32 stosd + + mov es, [xBX + BS3REGCTX.es] + mov fs, [xBX + BS3REGCTX.fs] + mov gs, [xBX + BS3REGCTX.gs] + mov eax, [xBX + BS3REGCTX.rax] + mov edx, [xBX + BS3REGCTX.rdx] + mov ecx, [xBX + BS3REGCTX.rcx] + mov edi, [xBX + BS3REGCTX.rdi] + mov ebp, [xBX + BS3REGCTX.rbp] ; restore late for better stacks. + + mov ss, [xBX + BS3REGCTX.ss] + mov esp, esi + mov esi, [xBX + BS3REGCTX.rsi] + mov ebx, [xBX + BS3REGCTX.rbx] + + o32 pop ds + pop ebp + iretd + + ; + ; IRETD to v8086 mode. Frame includes ss:esp and the 4 data segment registers. + ; +.restore_v8086: + or eax, 0ffffffffh ; poison unused parts of segment pushes + mov eax, [xBX + BS3REGCTX.gs] + push eax + mov eax, [xBX + BS3REGCTX.fs] + push eax + mov eax, [xBX + BS3REGCTX.ds] + push eax + mov eax, [xBX + BS3REGCTX.es] + push eax + mov eax, [xBX + BS3REGCTX.ss] + push eax + push dword [xBX + BS3REGCTX.rsp] + push dword [xBX + BS3REGCTX.rflags] + mov ax, [xBX + BS3REGCTX.cs] + push eax + push dword [xBX + BS3REGCTX.rip] + + mov eax, [xBX + BS3REGCTX.rax] + mov edx, [xBX + BS3REGCTX.rdx] + mov ecx, [xBX + BS3REGCTX.rcx] + mov esi, [xBX + BS3REGCTX.rsi] + mov edi, [xBX + BS3REGCTX.rdi] + mov ebp, [xBX + BS3REGCTX.rbp] ; restore late for better stacks. + mov ebx, [xBX + BS3REGCTX.rbx] + + iretd +%endif +BS3_PROC_END_CMN Bs3RegCtxRestore + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-RegCtxSave.asm b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-RegCtxSave.asm new file mode 100644 index 00000000..93684b7d --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-RegCtxSave.asm @@ -0,0 +1,261 @@ +; $Id: bs3-cmn-RegCtxSave.asm $ +;; @file +; BS3Kit - Bs3RegCtxSave. +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + +%include "bs3kit-template-header.mac" + + +BS3_EXTERN_SYSTEM16 Bs3Gdt +BS3_EXTERN_DATA16 g_bBs3CurrentMode +%if TMPL_BITS != 64 +BS3_EXTERN_DATA16 g_uBs3CpuDetected +%endif +TMPL_BEGIN_TEXT + + + +;; +; Saves the current register context. +; +; @param pRegCtx +; @uses None. +; +BS3_PROC_BEGIN_CMN Bs3RegCtxSave, BS3_PBC_HYBRID_SAFE +TONLY16 CPU 8086 + BS3_CALL_CONV_PROLOG 1 + push xBP + mov xBP, xSP + xPUSHF ; xBP - xCB*1: save the incoming flags exactly. + push xAX ; xBP - xCB*2: save incoming xAX + push xCX ; xBP - xCB*3: save incoming xCX + push xDI ; xBP - xCB*4: save incoming xDI +BONLY16 push es ; xBP - xCB*5 +BONLY16 push ds ; xBP - xCB*6 + + ; + ; Clear the whole structure first. + ; + xor xAX, xAX + cld + AssertCompileSizeAlignment(BS3REGCTX, 4) +%if TMPL_BITS == 16 + les xDI, [xBP + xCB + cbCurRetAddr] + mov xCX, BS3REGCTX_size / 2 + rep stosw +%else + mov xDI, [xBP + xCB + cbCurRetAddr] + mov xCX, BS3REGCTX_size / 4 + rep stosd +%endif + mov xDI, [xBP + xCB + cbCurRetAddr] + + ; + ; Save the current mode. + ; + mov cl, [BS3_DATA16_WRT(g_bBs3CurrentMode)] + mov [BS3_ONLY_16BIT(es:) xDI + BS3REGCTX.bMode], cl +%if TMPL_BITS == 16 + + ; + ; In 16-bit mode we could be running on really ancient CPUs, so check + ; mode and detected CPU and proceed with care. + ; + cmp cl, BS3_MODE_PP16 + jae .save_full + + mov cl, [BS3_DATA16_WRT(g_uBs3CpuDetected)] + cmp cl, BS3CPU_80386 + jae .save_full + + ; load ES into DS so we can save some segment prefix bytes. + push es + pop ds + + ; 16-bit GPRs not on the stack. + mov [xDI + BS3REGCTX.rdx], dx + mov [xDI + BS3REGCTX.rbx], bx + mov [xDI + BS3REGCTX.rsi], si + + ; Join the common code. + cmp cl, BS3CPU_80286 + jb .common_ancient + CPU 286 + smsw [xDI + BS3REGCTX.cr0] + + mov cl, [xDI + BS3REGCTX.bMode] ; assumed by jump destination + jmp .common_80286 + + CPU 386 +%endif + + +.save_full: + ; + ; 80386 or later. + ; +%if TMPL_BITS != 64 + ; Check for CR4 here while we've got a working DS in all contexts. + test byte [1 + BS3_DATA16_WRT(g_uBs3CpuDetected)], (BS3CPU_F_CPUID >> 8) + jnz .save_full_have_cr4 + or byte [BS3_ONLY_16BIT(es:) xDI + BS3REGCTX.fbFlags], BS3REG_CTX_F_NO_CR4 +.save_full_have_cr4: +%endif +%if TMPL_BITS == 16 + ; Load es into ds so we can save ourselves some segment prefix bytes. + push es + pop ds +%endif + + ; GPRs first. + mov [xDI + BS3REGCTX.rdx], sDX + mov [xDI + BS3REGCTX.rbx], sBX + mov [xDI + BS3REGCTX.rsi], sSI +%if TMPL_BITS == 64 + mov [xDI + BS3REGCTX.r8], r8 + mov [xDI + BS3REGCTX.r9], r9 + mov [xDI + BS3REGCTX.r10], r10 + mov [xDI + BS3REGCTX.r11], r11 + mov [xDI + BS3REGCTX.r12], r12 + mov [xDI + BS3REGCTX.r13], r13 + mov [xDI + BS3REGCTX.r14], r14 + mov [xDI + BS3REGCTX.r15], r15 +%else + or byte [xDI + BS3REGCTX.fbFlags], BS3REG_CTX_F_NO_AMD64 +%endif +%if TMPL_BITS == 16 ; Save high bits. + mov [xDI + BS3REGCTX.rax], eax + mov [xDI + BS3REGCTX.rcx], ecx + mov [xDI + BS3REGCTX.rdi], edi + mov [xDI + BS3REGCTX.rbp], ebp + mov [xDI + BS3REGCTX.rsp], esp + pushfd + pop dword [xDI + BS3REGCTX.rflags] +%endif +%if TMPL_BITS != 64 + ; The VM flag is never on the stack, so derive it from the bMode we saved above. + test byte [xDI + BS3REGCTX.bMode], BS3_MODE_CODE_V86 + jz .not_v8086 + or byte [xDI + BS3REGCTX.rflags + 2], X86_EFL_VM >> 16 + mov byte [xDI + BS3REGCTX.bCpl], 3 +.not_v8086: +%endif + + ; 386 segment registers. + mov [xDI + BS3REGCTX.fs], fs + mov [xDI + BS3REGCTX.gs], gs + +%if TMPL_BITS == 16 ; v8086 and real mode woes. + mov cl, [xDI + BS3REGCTX.bMode] + cmp cl, BS3_MODE_RM + je .common_full_control_regs + test cl, BS3_MODE_CODE_V86 + jnz .common_full_no_control_regs +%endif + mov ax, ss + test al, 3 + jnz .common_full_no_control_regs + + ; Control registers (ring-0 and real-mode only). +.common_full_control_regs: + mov sAX, cr0 + mov [xDI + BS3REGCTX.cr0], sAX + mov sAX, cr2 + mov [xDI + BS3REGCTX.cr2], sAX + mov sAX, cr3 + mov [xDI + BS3REGCTX.cr3], sAX +%if TMPL_BITS != 64 + test byte [xDI + BS3REGCTX.fbFlags], BS3REG_CTX_F_NO_CR4 + jnz .common_80286 +%endif + mov sAX, cr4 + mov [xDI + BS3REGCTX.cr4], sAX + jmp .common_80286 + +.common_full_no_control_regs: + or byte [xDI + BS3REGCTX.fbFlags], BS3REG_CTX_F_NO_CR0_IS_MSW | BS3REG_CTX_F_NO_CR2_CR3 | BS3REG_CTX_F_NO_CR4 + smsw [xDI + BS3REGCTX.cr0] + + ; 80286 control registers. +.common_80286: +TONLY16 CPU 286 +%if TMPL_BITS != 64 + cmp cl, BS3_MODE_RM + je .no_str_sldt + test cl, BS3_MODE_CODE_V86 + jnz .no_str_sldt +%endif + str [xDI + BS3REGCTX.tr] + sldt [xDI + BS3REGCTX.ldtr] + jmp .common_ancient + +.no_str_sldt: + or byte [xDI + BS3REGCTX.fbFlags], BS3REG_CTX_F_NO_TR_LDTR + + ; Common stuff - stuff on the stack, 286 segment registers. +.common_ancient: +TONLY16 CPU 8086 + mov xAX, [xBP - xCB*1] + mov [xDI + BS3REGCTX.rflags], xAX + mov xAX, [xBP - xCB*2] + mov [xDI + BS3REGCTX.rax], xAX + mov xAX, [xBP - xCB*3] + mov [xDI + BS3REGCTX.rcx], xAX + mov xAX, [xBP - xCB*4] + mov [xDI + BS3REGCTX.rdi], xAX + mov xAX, [xBP] + mov [xDI + BS3REGCTX.rbp], xAX + mov xAX, [xBP + xCB] + mov [xDI + BS3REGCTX.rip], xAX + lea xAX, [xBP + xCB + cbCurRetAddr] + mov [xDI + BS3REGCTX.rsp], xAX + +%if TMPL_BITS == 16 + mov ax, [xBP + xCB + 2] + mov [xDI + BS3REGCTX.cs], ax + mov ax, [xBP - xCB*6] + mov [xDI + BS3REGCTX.ds], ax + mov ax, [xBP - xCB*5] + mov [xDI + BS3REGCTX.es], ax +%else + mov [xDI + BS3REGCTX.cs], cs + mov [xDI + BS3REGCTX.ds], ds + mov [xDI + BS3REGCTX.es], es +%endif + mov [xDI + BS3REGCTX.ss], ss + + ; + ; Return. + ; +.return: +BONLY16 pop ds +BONLY16 pop es + pop xDI + pop xCX + pop xAX + xPOPF + pop xBP + BS3_HYBRID_RET +BS3_PROC_END_CMN Bs3RegCtxSave + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-RegCtxSaveEx.asm b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-RegCtxSaveEx.asm new file mode 100644 index 00000000..a39f4718 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-RegCtxSaveEx.asm @@ -0,0 +1,450 @@ +; $Id: bs3-cmn-RegCtxSaveEx.asm $ +;; @file +; BS3Kit - Bs3RegCtxSaveEx. +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + +%include "bs3kit-template-header.mac" + + + +;********************************************************************************************************************************* +;* External Symbols * +;********************************************************************************************************************************* +BS3_EXTERN_DATA16 g_bBs3CurrentMode +%if ARCH_BITS != 64 +BS3_EXTERN_DATA16 g_uBs3CpuDetected +%endif + +TMPL_BEGIN_TEXT +BS3_EXTERN_CMN Bs3Panic +BS3_EXTERN_CMN Bs3RegCtxSave +BS3_EXTERN_CMN Bs3SwitchTo16Bit +%if TMPL_BITS != 64 +BS3_EXTERN_CMN Bs3SwitchTo16BitV86 +%endif +%if TMPL_BITS != 32 +BS3_EXTERN_CMN Bs3SwitchTo32Bit +%endif +%if TMPL_BITS != 64 +BS3_EXTERN_CMN Bs3SwitchTo64Bit +%endif +%if TMPL_BITS == 16 +BS3_EXTERN_CMN Bs3SelRealModeDataToProtFar16 +BS3_EXTERN_CMN Bs3SelProtFar16DataToRealMode +BS3_EXTERN_CMN Bs3SelRealModeDataToFlat +BS3_EXTERN_CMN Bs3SelProtFar16DataToFlat +%else +BS3_EXTERN_CMN Bs3SelFlatDataToProtFar16 +%endif +%if TMPL_BITS == 32 +BS3_EXTERN_CMN Bs3SelFlatDataToRealMode +%endif + +BS3_BEGIN_TEXT16 +%if TMPL_BITS != 16 +extern _Bs3RegCtxSave_c16 +extern _Bs3SwitchTo%[TMPL_BITS]Bit_c16 +%endif + +BS3_BEGIN_TEXT32 +%if TMPL_BITS != 32 +extern _Bs3RegCtxSave_c32 +extern _Bs3SwitchTo%[TMPL_BITS]Bit_c32 +%endif +%if TMPL_BITS == 16 +extern _Bs3SwitchTo16BitV86_c32 +%endif + +BS3_BEGIN_TEXT64 +%if TMPL_BITS != 64 +extern _Bs3RegCtxSave_c64 +extern _Bs3SwitchTo%[TMPL_BITS]Bit_c64 +%endif + +TMPL_BEGIN_TEXT + + + +;; +; Saves the current register context. +; +; @param pRegCtx +; @param bBitMode (8) +; @param cbExtraStack (16) +; @uses xAX, xDX, xCX +; +BS3_PROC_BEGIN_CMN Bs3RegCtxSaveEx, BS3_PBC_NEAR ; Far stub generated by the makefile/bs3kit.h. +TONLY16 CPU 8086 + BS3_CALL_CONV_PROLOG 3 + push xBP + mov xBP, xSP +%if ARCH_BITS == 64 + push rcx ; Save pRegCtx +%endif + + ; + ; Get the CPU bitcount part of the current mode. + ; + mov dl, [BS3_DATA16_WRT(g_bBs3CurrentMode)] + and dl, BS3_MODE_CODE_MASK +%if TMPL_BITS == 16 + push dx ; bp - 2: previous CPU mode (16-bit) +%endif + + ; + ; Reserve extra stack space. Make sure we've got 20h here in case we + ; are saving a 64-bit context. + ; +TONLY16 mov ax, [xBP + xCB + cbCurRetAddr + sCB + xCB] +TNOT16 movzx eax, word [xBP + xCB + cbCurRetAddr + sCB + xCB] +%ifdef BS3_STRICT + cmp xAX, 4096 + jb .extra_stack_ok + call Bs3Panic +.extra_stack_ok: +%endif + cmp xAX, 20h + jae .at_least_20h_extra_stack + add xAX, 20h +.at_least_20h_extra_stack: + sub xSP, xAX + + ; + ; Are we just saving the mode we're already in? + ; + mov al, [xBP + xCB + cbCurRetAddr + sCB] + and al, BS3_MODE_CODE_MASK + cmp dl, al + jne .not_the_same_mode + +%if TMPL_BITS == 16 + push word [xBP + xCB + cbCurRetAddr + 2] + push word [xBP + xCB + cbCurRetAddr] +%elif TMPL_BITS == 32 + push dword [xBP + xCB + cbCurRetAddr] +%endif + call Bs3RegCtxSave ; 64-bit: rcx is untouched thus far. + + + ; + ; Return - no need to pop xAX and xDX as the last two + ; operations preserves all registers. + ; +.return: + mov xSP, xBP + pop xBP + BS3_CALL_CONV_EPILOG 3 + BS3_HYBRID_RET + + ; + ; Turns out we have to do switch to a different bitcount before saving. + ; +.not_the_same_mode: + cmp al, BS3_MODE_CODE_16 + je .code_16 + +TONLY16 CPU 386 +%if TMPL_BITS != 32 + cmp al, BS3_MODE_CODE_32 + je .code_32 +%endif +%if TMPL_BITS != 64 + cmp al, BS3_MODE_CODE_V86 + je .code_v86 + cmp al, BS3_MODE_CODE_64 + jne .bad_input_mode + jmp .code_64 +%endif + + ; Bad input (al=input, dl=current). +.bad_input_mode: + call Bs3Panic + + + ; + ; Save a 16-bit context. + ; + ; Convert pRegCtx to 16:16 protected mode and make sure we're in the + ; 16-bit code segment. + ; +.code_16: +%if TMPL_BITS == 16 + %ifdef BS3_STRICT + cmp dl, BS3_MODE_CODE_V86 + jne .bad_input_mode + %endif + push word [xBP + xCB + cbCurRetAddr + 2] + push word [xBP + xCB + cbCurRetAddr] + call Bs3SelRealModeDataToProtFar16 + add sp, 4h + push dx ; Parameter #0 for _Bs3RegCtxSave_c16 + push ax +%else + %if TMPL_BITS == 32 + push dword [xBP + xCB + cbCurRetAddr] + %endif + call Bs3SelFlatDataToProtFar16 ; 64-bit: BS3_CALL not needed, ecx not touched thus far. + mov [xSP], eax ; Parameter #0 for _Bs3RegCtxSave_c16 + jmp .code_16_safe_segment + BS3_BEGIN_TEXT16 + BS3_SET_BITS TMPL_BITS +.code_16_safe_segment: +%endif + call Bs3SwitchTo16Bit + BS3_SET_BITS 16 + + call _Bs3RegCtxSave_c16 + +%if TMPL_BITS == 16 + call _Bs3SwitchTo16BitV86_c16 +%else + call _Bs3SwitchTo%[TMPL_BITS]Bit_c16 +%endif + BS3_SET_BITS TMPL_BITS + jmp .supplement_and_return + TMPL_BEGIN_TEXT + +TONLY16 CPU 386 + + +%if TMPL_BITS != 64 + ; + ; Save a v8086 context. + ; +.code_v86: + %if TMPL_BITS == 16 + %ifdef BS3_STRICT + cmp dl, BS3_MODE_CODE_16 + jne .bad_input_mode + %endif + push word [xBP + xCB + cbCurRetAddr + 2] + push word [xBP + xCB + cbCurRetAddr] + call Bs3SelProtFar16DataToRealMode + add sp, 4h + push dx ; Parameter #0 for _Bs3RegCtxSave_c16 + push ax + %else + push dword [xBP + xCB + cbCurRetAddr] + call Bs3SelFlatDataToRealMode + mov [xSP], eax ; Parameter #0 for _Bs3RegCtxSave_c16 + jmp .code_v86_safe_segment + BS3_BEGIN_TEXT16 + BS3_SET_BITS TMPL_BITS +.code_v86_safe_segment: + %endif + call Bs3SwitchTo16BitV86 + BS3_SET_BITS 16 + + call _Bs3RegCtxSave_c16 + + call _Bs3SwitchTo%[TMPL_BITS]Bit_c16 + BS3_SET_BITS TMPL_BITS + jmp .supplement_and_return +TMPL_BEGIN_TEXT +%endif + + +%if TMPL_BITS != 32 + ; + ; Save a 32-bit context. + ; +.code_32: + %if TMPL_BITS == 16 + push word [xBP + xCB + cbCurRetAddr + 2] + push word [xBP + xCB + cbCurRetAddr] + test dl, BS3_MODE_CODE_V86 + jnz .code_32_from_v86 + call Bs3SelProtFar16DataToFlat + jmp .code_32_flat_ptr +.code_32_from_v86: + call Bs3SelRealModeDataToFlat +.code_32_flat_ptr: + add sp, 4h + push dx ; Parameter #0 for _Bs3RegCtxSave_c32 + push ax + %else + mov [rsp], ecx ; Parameter #0 for _Bs3RegCtxSave_c16 + %endif + call Bs3SwitchTo32Bit + BS3_SET_BITS 32 + + call _Bs3RegCtxSave_c32 + + %if TMPL_BITS == 16 + cmp byte [bp - 2], BS3_MODE_CODE_V86 + je .code_32_back_to_v86 + call _Bs3SwitchTo16Bit_c32 + BS3_SET_BITS TMPL_BITS + jmp .supplement_and_return +.code_32_back_to_v86: + BS3_SET_BITS 32 + call _Bs3SwitchTo16BitV86_c32 + BS3_SET_BITS TMPL_BITS + jmp .return + %else + call _Bs3SwitchTo64Bit_c32 + BS3_SET_BITS TMPL_BITS + jmp .supplement_and_return + %endif +%endif + + +%if TMPL_BITS != 64 + ; + ; Save a 64-bit context. + ; + CPU x86-64 +.code_64: + %if TMPL_BITS == 16 + %ifdef BS3_STRICT + cmp dl, BS3_MODE_CODE_16 + jne .bad_input_mode + %endif + push word [xBP + xCB + cbCurRetAddr + 2] + push word [xBP + xCB + cbCurRetAddr] + call Bs3SelProtFar16DataToFlat + add sp, 4h + mov cx, dx ; Parameter #0 for _Bs3RegCtxSave_c64 + shl ecx, 16 + mov cx, ax + %else + mov ecx, [xBP + xCB + cbCurRetAddr] ; Parameter #0 for _Bs3RegCtxSave_c64 + %endif + call Bs3SwitchTo64Bit ; (preserves all 32-bit GPRs) + BS3_SET_BITS 64 + + call _Bs3RegCtxSave_c64 ; No BS3_CALL as rcx is already ready. + + call _Bs3SwitchTo%[TMPL_BITS]Bit_c64 + BS3_SET_BITS TMPL_BITS + jmp .return +%endif + + + ; + ; Supplement the state out of the current context and then return. + ; +.supplement_and_return: +%if ARCH_BITS == 16 + CPU 8086 + ; Skip 286 and older. Also make 101% sure we not in real mode or v8086 mode. + cmp byte [BS3_DATA16_WRT(g_uBs3CpuDetected)], BS3CPU_80386 + jb .return ; Just skip if 286 or older. + test byte [BS3_DATA16_WRT(g_bBs3CurrentMode)], BS3_MODE_CODE_V86 + jnz .return + cmp byte [BS3_DATA16_WRT(g_bBs3CurrentMode)], BS3_MODE_RM + jne .return ; paranoia + CPU 386 +%endif + + ; Load the context pointer into a suitable register. +%if ARCH_BITS == 64 + %define pRegCtx rcx + mov rcx, [xBP - xCB] +%elif ARCH_BITS == 32 + %define pRegCtx ecx + mov ecx, [xBP + xCB + cbCurRetAddr] +%else + %define pRegCtx es:bx + push es + push bx + les bx, [xBP + xCB + cbCurRetAddr] +%endif +%if ARCH_BITS == 64 + ; If we're in 64-bit mode we can capture and restore the high bits. + test byte [pRegCtx + BS3REGCTX.fbFlags], BS3REG_CTX_F_NO_AMD64 + jz .supplemented_64bit_registers + mov [pRegCtx + BS3REGCTX.r8], r8 + mov [pRegCtx + BS3REGCTX.r9], r9 + mov [pRegCtx + BS3REGCTX.r10], r10 + mov [pRegCtx + BS3REGCTX.r11], r11 + mov [pRegCtx + BS3REGCTX.r12], r12 + mov [pRegCtx + BS3REGCTX.r13], r13 + mov [pRegCtx + BS3REGCTX.r14], r14 + mov [pRegCtx + BS3REGCTX.r15], r15 + shr rax, 32 + mov [pRegCtx + BS3REGCTX.rax + 4], eax + mov rax, rbx + shr rax, 32 + mov [pRegCtx + BS3REGCTX.rbx + 4], eax + mov rax, rcx + shr rax, 32 + mov [pRegCtx + BS3REGCTX.rcx + 4], eax + mov rax, rdx + shr rax, 32 + mov [pRegCtx + BS3REGCTX.rdx + 4], eax + mov rax, rsp + shr rax, 32 + mov [pRegCtx + BS3REGCTX.rsp + 4], eax + mov rax, rbp + shr rax, 32 + mov [pRegCtx + BS3REGCTX.rbp + 4], eax + mov rax, rsi + shr rax, 32 + mov [pRegCtx + BS3REGCTX.rsi + 4], eax + mov rax, rdi + shr rax, 32 + mov [pRegCtx + BS3REGCTX.rdi + 4], eax + and byte [pRegCtx + BS3REGCTX.fbFlags], ~BS3REG_CTX_F_NO_AMD64 +.supplemented_64bit_registers: +%endif + ; The rest requires ring-0 (at least during restore). + mov ax, ss + test ax, 3 + jnz .done_supplementing + + ; Do control registers. + test byte [pRegCtx + BS3REGCTX.fbFlags], BS3REG_CTX_F_NO_CR2_CR3 | BS3REG_CTX_F_NO_CR0_IS_MSW | BS3REG_CTX_F_NO_CR4 + jz .supplemented_control_registers + mov sAX, cr0 + mov [pRegCtx + BS3REGCTX.cr0], sAX + mov sAX, cr2 + mov [pRegCtx + BS3REGCTX.cr2], sAX + mov sAX, cr3 + mov [pRegCtx + BS3REGCTX.cr3], sAX + and byte [pRegCtx + BS3REGCTX.fbFlags], ~(BS3REG_CTX_F_NO_CR2_CR3 | BS3REG_CTX_F_NO_CR0_IS_MSW) + +%if ARCH_BITS != 64 + test byte [1 + BS3_DATA16_WRT(g_uBs3CpuDetected)], (BS3CPU_F_CPUID >> 8) + jz .supplemented_control_registers +%endif + mov sAX, cr4 + mov [pRegCtx + BS3REGCTX.cr4], sAX + and byte [pRegCtx + BS3REGCTX.fbFlags], ~BS3REG_CTX_F_NO_CR4 +.supplemented_control_registers: + + ; Supply tr and ldtr if necessary + test byte [pRegCtx + BS3REGCTX.fbFlags], BS3REG_CTX_F_NO_TR_LDTR + jz .done_supplementing + str [pRegCtx + BS3REGCTX.tr] + sldt [pRegCtx + BS3REGCTX.ldtr] + and byte [pRegCtx + BS3REGCTX.fbFlags], ~BS3REG_CTX_F_NO_TR_LDTR + +.done_supplementing: +TONLY16 pop bx +TONLY16 pop es + jmp .return +%undef pRegCtx +BS3_PROC_END_CMN Bs3RegCtxSaveEx + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-RegCtxSetGrpSegFromCurPtr.c b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-RegCtxSetGrpSegFromCurPtr.c new file mode 100644 index 00000000..8864e2ab --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-RegCtxSetGrpSegFromCurPtr.c @@ -0,0 +1,50 @@ +/* $Id: bs3-cmn-RegCtxSetGrpSegFromCurPtr.c $ */ +/** @file + * BS3Kit - Bs3RegCtxSetGrpSegFromCurPtr, Bs3RegCtxSetGrpDsFromCurPtr + */ + +/* + * Copyright (C) 2007-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include "bs3kit-template-header.h" + + +#undef Bs3RegCtxSetGrpSegFromCurPtr +BS3_CMN_DEF(void, Bs3RegCtxSetGrpSegFromCurPtr,(PBS3REGCTX pRegCtx, PBS3REG pGpr, PRTSEL pSel, void BS3_FAR *pvPtr)) +{ +#if ARCH_BITS == 16 + Bs3RegCtxSetGrpSegFromFlat(pRegCtx, pGpr, pSel, Bs3SelPtrToFlat(pvPtr)); +#else + Bs3RegCtxSetGrpSegFromFlat(pRegCtx, pGpr, pSel, (uintptr_t)pvPtr); +#endif +} + + +#undef Bs3RegCtxSetGrpDsFromCurPtr +BS3_CMN_DEF(void, Bs3RegCtxSetGrpDsFromCurPtr,(PBS3REGCTX pRegCtx, PBS3REG pGpr, void BS3_FAR *pvPtr)) +{ + BS3_CMN_FAR_NM(Bs3RegCtxSetGrpSegFromCurPtr)(pRegCtx, pGpr, &pRegCtx->ds, pvPtr); +} + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-RegCtxSetGrpSegFromFlat.c b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-RegCtxSetGrpSegFromFlat.c new file mode 100644 index 00000000..4e055b0b --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-RegCtxSetGrpSegFromFlat.c @@ -0,0 +1,65 @@ +/* $Id: bs3-cmn-RegCtxSetGrpSegFromFlat.c $ */ +/** @file + * BS3Kit - Bs3RegCtxSetGrpSegFromFlat + */ + +/* + * Copyright (C) 2007-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include "bs3kit-template-header.h" + + +#undef Bs3RegCtxSetGrpSegFromFlat +BS3_CMN_DEF(void, Bs3RegCtxSetGrpSegFromFlat,(PBS3REGCTX pRegCtx, PBS3REG pGpr, PRTSEL pSel, RTCCUINTXREG uFlat)) +{ + if (BS3_MODE_IS_16BIT_CODE(pRegCtx->bMode)) + { + uint32_t uFar1616; + if (BS3_MODE_IS_RM_OR_V86(pRegCtx->bMode)) + uFar1616 = Bs3SelFlatDataToRealMode(uFlat); + else + uFar1616 = Bs3SelFlatDataToProtFar16(uFlat); + pGpr->u = uFar1616 & UINT16_MAX; + *pSel = uFar1616 >> 16; + } + else + { + pGpr->u = uFlat; + if (BS3_MODE_IS_32BIT_CODE(pRegCtx->bMode)) + *pSel = BS3_SEL_R0_DS32; + else + *pSel = BS3_SEL_R0_DS64; + } + + /* Adjust CS to the right ring, if not ring-0 or V86 context. */ + if ( pRegCtx->bCpl != 0 + && !BS3_MODE_IS_RM_OR_V86(pRegCtx->bMode)) + { + if (BS3_SEL_IS_IN_R0_RANGE(*pSel)) + *pSel += (uint16_t)pRegCtx->bCpl << BS3_SEL_RING_SHIFT; + *pSel |= pRegCtx->bCpl; + } +} + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-RegCtxSetRipCsFromCurPtr.c b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-RegCtxSetRipCsFromCurPtr.c new file mode 100644 index 00000000..392b13c3 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-RegCtxSetRipCsFromCurPtr.c @@ -0,0 +1,43 @@ +/* $Id: bs3-cmn-RegCtxSetRipCsFromCurPtr.c $ */ +/** @file + * BS3Kit - Bs3RegCtxSetRipCsFromCurPtr + */ + +/* + * Copyright (C) 2007-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include "bs3kit-template-header.h" + + +#undef Bs3RegCtxSetRipCsFromCurPtr +BS3_CMN_DEF(void, Bs3RegCtxSetRipCsFromCurPtr,(PBS3REGCTX pRegCtx, FPFNBS3FAR pfnCode)) +{ +#if ARCH_BITS == 16 + Bs3RegCtxSetRipCsFromFlat(pRegCtx, Bs3SelPtrToFlat((void BS3_FAR *)pfnCode)); +#else + Bs3RegCtxSetRipCsFromFlat(pRegCtx, (uintptr_t)pfnCode); +#endif +} + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-RegCtxSetRipCsFromFlat.c b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-RegCtxSetRipCsFromFlat.c new file mode 100644 index 00000000..a821c532 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-RegCtxSetRipCsFromFlat.c @@ -0,0 +1,65 @@ +/* $Id: bs3-cmn-RegCtxSetRipCsFromFlat.c $ */ +/** @file + * BS3Kit - Bs3RegCtxSetRipCsFromFlat + */ + +/* + * Copyright (C) 2007-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include "bs3kit-template-header.h" + + +#undef Bs3RegCtxSetRipCsFromFlat +BS3_CMN_DEF(void, Bs3RegCtxSetRipCsFromFlat,(PBS3REGCTX pRegCtx, RTCCUINTXREG uFlatCode)) +{ + if (BS3_MODE_IS_16BIT_CODE(pRegCtx->bMode)) + { + uint32_t uFar1616; + if (BS3_MODE_IS_RM_OR_V86(pRegCtx->bMode)) + uFar1616 = Bs3SelFlatCodeToRealMode(uFlatCode); + else + uFar1616 = Bs3SelFlatCodeToProtFar16(uFlatCode); + pRegCtx->rip.u = uFar1616 & UINT16_MAX; + pRegCtx->cs = uFar1616 >> 16; + } + else + { + pRegCtx->rip.u = uFlatCode; + if (BS3_MODE_IS_32BIT_CODE(pRegCtx->bMode)) + pRegCtx->cs = BS3_SEL_R0_CS32; + else + pRegCtx->cs = BS3_SEL_R0_CS64; + } + + /* Adjust CS to the right ring, if not ring-0 or V86 context. */ + if ( pRegCtx->bCpl != 0 + && !BS3_MODE_IS_RM_OR_V86(pRegCtx->bMode) + && BS3_SEL_IS_IN_R0_RANGE(pRegCtx->cs)) + { + pRegCtx->cs += (uint16_t)pRegCtx->bCpl << BS3_SEL_RING_SHIFT; + pRegCtx->cs |= pRegCtx->bCpl; + } +} + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-RegCtxSetRipCsFromLnkPtr.c b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-RegCtxSetRipCsFromLnkPtr.c new file mode 100644 index 00000000..f740bfda --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-RegCtxSetRipCsFromLnkPtr.c @@ -0,0 +1,77 @@ +/* $Id: bs3-cmn-RegCtxSetRipCsFromLnkPtr.c $ */ +/** @file + * BS3Kit - Bs3RegCtxSetRipCsFromLnkPtr + */ + +/* + * Copyright (C) 2007-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include "bs3kit-template-header.h" + + +#undef Bs3RegCtxSetRipCsFromLnkPtr +BS3_CMN_DEF(void, Bs3RegCtxSetRipCsFromLnkPtr,(PBS3REGCTX pRegCtx, FPFNBS3FAR pfnCode)) +{ + if (BS3_MODE_IS_16BIT_CODE(pRegCtx->bMode)) + { +#if ARCH_BITS == 16 + pRegCtx->rip.u = BS3_FP_OFF(pfnCode); + if (BS3_MODE_IS_RM_OR_V86(pRegCtx->bMode)) + pRegCtx->cs = BS3_FP_SEG(pfnCode); + else + pRegCtx->cs = Bs3SelRealModeCodeToProtMode(BS3_FP_SEG(pfnCode)); +#else + uint32_t uFar1616; + if (BS3_MODE_IS_RM_OR_V86(pRegCtx->bMode)) + uFar1616 = Bs3SelFlatCodeToRealMode((uint32_t)(uintptr_t)pfnCode); + else + uFar1616 = Bs3SelFlatCodeToProtFar16((uint32_t)(uintptr_t)pfnCode); + pRegCtx->rip.u = uFar1616 & UINT16_MAX; + pRegCtx->cs = uFar1616 >> 16; +#endif + } + else + { +#if ARCH_BITS == 16 + pRegCtx->rip.u = Bs3SelRealModeCodeToFlat(pfnCode); +#else + pRegCtx->rip.u = (uintptr_t)pfnCode; +#endif + if (BS3_MODE_IS_32BIT_CODE(pRegCtx->bMode)) + pRegCtx->cs = BS3_SEL_R0_CS32; + else + pRegCtx->cs = BS3_SEL_R0_CS64; + } + + /* Adjust CS to the right ring, if not ring-0 or V86 context. */ + if ( pRegCtx->bCpl != 0 + && !BS3_MODE_IS_RM_OR_V86(pRegCtx->bMode) + && BS3_SEL_IS_IN_R0_RANGE(pRegCtx->cs)) + { + pRegCtx->cs += (uint16_t)pRegCtx->bCpl << BS3_SEL_RING_SHIFT; + pRegCtx->cs |= pRegCtx->bCpl; + } +} + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-RegGetCr0.asm b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-RegGetCr0.asm new file mode 100644 index 00000000..adae1d21 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-RegGetCr0.asm @@ -0,0 +1,79 @@ +; $Id: bs3-cmn-RegGetCr0.asm $ +;; @file +; BS3Kit - Bs3RegGetCr0 +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + +%include "bs3kit-template-header.mac" + + +BS3_EXTERN_CMN Bs3Panic +BS3_EXTERN_CMN Bs3Syscall +%if TMPL_BITS == 16 +BS3_EXTERN_DATA16 g_bBs3CurrentMode +%endif +TMPL_BEGIN_TEXT + + +;; +; @cproto BS3_CMN_PROTO_STUB(RTCCUINTXREG, Bs3RegGetCr0,(void)); +; +; @returns Register value. +; @remarks Does not require 20h of parameter scratch space in 64-bit mode. +; +; @uses No GPRs (only return full register(s)). +; +BS3_PROC_BEGIN_CMN Bs3RegGetCr0, BS3_PBC_HYBRID_SAFE + BS3_CALL_CONV_PROLOG 0 + push xBP + mov xBP, xSP + +%if TMPL_BITS == 16 + ; If V8086 mode we have to go thru a syscall. + test byte [BS3_DATA16_WRT(g_bBs3CurrentMode)], BS3_MODE_CODE_V86 + jnz .via_system_call + cmp byte [BS3_DATA16_WRT(g_bBs3CurrentMode)], BS3_MODE_RM + je .direct_access +%endif + ; If not in ring-0, we have to make a system call. + mov ax, ss + and ax, X86_SEL_RPL + jnz .via_system_call + +.direct_access: + mov sAX, cr0 +TONLY16 mov edx, eax +TONLY16 shr edx, 16 + jmp .return + +.via_system_call: + mov xAX, BS3_SYSCALL_GET_CRX + mov dl, 0 + call Bs3Syscall + +.return: + pop xBP + BS3_CALL_CONV_EPILOG 0 + BS3_HYBRID_RET +BS3_PROC_END_CMN Bs3RegGetCr0 + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-RegGetCr2.asm b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-RegGetCr2.asm new file mode 100644 index 00000000..14a8f811 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-RegGetCr2.asm @@ -0,0 +1,79 @@ +; $Id: bs3-cmn-RegGetCr2.asm $ +;; @file +; BS3Kit - Bs3RegGetCr2 +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + +%include "bs3kit-template-header.mac" + + +BS3_EXTERN_CMN Bs3Panic +BS3_EXTERN_CMN Bs3Syscall +%if TMPL_BITS == 16 +BS3_EXTERN_DATA16 g_bBs3CurrentMode +%endif +TMPL_BEGIN_TEXT + + +;; +; @cproto BS3_CMN_PROTO_STUB(RTCCUINTXREG, Bs3RegGetCr2,(void)); +; +; @returns Register value. +; @remarks Does not require 20h of parameter scratch space in 64-bit mode. +; +; @uses No GPRs (only return full register(s)). +; +BS3_PROC_BEGIN_CMN Bs3RegGetCr2, BS3_PBC_HYBRID_SAFE + BS3_CALL_CONV_PROLOG 0 + push xBP + mov xBP, xSP + +%if TMPL_BITS == 16 + ; If V8086 mode we have to go thru a syscall. + test byte [BS3_DATA16_WRT(g_bBs3CurrentMode)], BS3_MODE_CODE_V86 + jnz .via_system_call + cmp byte [BS3_DATA16_WRT(g_bBs3CurrentMode)], BS3_MODE_RM + je .direct_access +%endif + ; If not in ring-0, we have to make a system call. + mov ax, ss + and ax, X86_SEL_RPL + jnz .via_system_call + +.direct_access: + mov sAX, cr2 +TONLY16 mov edx, eax +TONLY16 shr edx, 16 + jmp .return + +.via_system_call: + mov xAX, BS3_SYSCALL_GET_CRX + mov dl, 2 + call Bs3Syscall + +.return: + pop xBP + BS3_CALL_CONV_EPILOG 0 + BS3_HYBRID_RET +BS3_PROC_END_CMN Bs3RegGetCr2 + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-RegGetCr3.asm b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-RegGetCr3.asm new file mode 100644 index 00000000..c1ed34bf --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-RegGetCr3.asm @@ -0,0 +1,79 @@ +; $Id: bs3-cmn-RegGetCr3.asm $ +;; @file +; BS3Kit - Bs3RegGetCr3 +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + +%include "bs3kit-template-header.mac" + + +BS3_EXTERN_CMN Bs3Panic +BS3_EXTERN_CMN Bs3Syscall +%if TMPL_BITS == 16 +BS3_EXTERN_DATA16 g_bBs3CurrentMode +%endif +TMPL_BEGIN_TEXT + + +;; +; @cproto BS3_CMN_PROTO_STUB(RTCCUINTXREG, Bs3RegGetCr3,(void)); +; +; @returns Register value. +; @remarks Does not require 20h of parameter scratch space in 64-bit mode. +; +; @uses No GPRs (only return full register(s)). +; +BS3_PROC_BEGIN_CMN Bs3RegGetCr3, BS3_PBC_HYBRID_SAFE + BS3_CALL_CONV_PROLOG 0 + push xBP + mov xBP, xSP + +%if TMPL_BITS == 16 + ; If V8086 mode we have to go thru a syscall. + test byte [BS3_DATA16_WRT(g_bBs3CurrentMode)], BS3_MODE_CODE_V86 + jnz .via_system_call + cmp byte [BS3_DATA16_WRT(g_bBs3CurrentMode)], BS3_MODE_RM + je .direct_access +%endif + ; If not in ring-0, we have to make a system call. + mov ax, ss + and ax, X86_SEL_RPL + jnz .via_system_call + +.direct_access: + mov sAX, cr3 +TONLY16 mov edx, eax +TONLY16 shr edx, 16 + jmp .return + +.via_system_call: + mov xAX, BS3_SYSCALL_GET_CRX + mov dl, 3 + call Bs3Syscall + +.return: + pop xBP + BS3_CALL_CONV_EPILOG 0 + BS3_HYBRID_RET +BS3_PROC_END_CMN Bs3RegGetCr3 + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-RegGetCr4.asm b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-RegGetCr4.asm new file mode 100644 index 00000000..e897d377 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-RegGetCr4.asm @@ -0,0 +1,79 @@ +; $Id: bs3-cmn-RegGetCr4.asm $ +;; @file +; BS3Kit - Bs3RegGetCr4 +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + +%include "bs3kit-template-header.mac" + + +BS3_EXTERN_CMN Bs3Panic +BS3_EXTERN_CMN Bs3Syscall +%if TMPL_BITS == 16 +BS3_EXTERN_DATA16 g_bBs3CurrentMode +%endif +TMPL_BEGIN_TEXT + + +;; +; @cproto BS3_CMN_PROTO_STUB(RTCCUINTXREG, Bs3RegGetCr4,(void)); +; +; @returns Register value. +; @remarks Does not require 20h of parameter scratch space in 64-bit mode. +; +; @uses No GPRs (only return full register(s)). +; +BS3_PROC_BEGIN_CMN Bs3RegGetCr4, BS3_PBC_HYBRID_SAFE + BS3_CALL_CONV_PROLOG 0 + push xBP + mov xBP, xSP + +%if TMPL_BITS == 16 + ; If V8086 mode we have to go thru a syscall. + test byte [BS3_DATA16_WRT(g_bBs3CurrentMode)], BS3_MODE_CODE_V86 + jnz .via_system_call + cmp byte [BS3_DATA16_WRT(g_bBs3CurrentMode)], BS3_MODE_RM + je .direct_access +%endif + ; If not in ring-0, we have to make a system call. + mov ax, ss + and ax, X86_SEL_RPL + jnz .via_system_call + +.direct_access: + mov sAX, cr4 +TONLY16 mov edx, eax +TONLY16 shr edx, 16 + jmp .return + +.via_system_call: + mov xAX, BS3_SYSCALL_GET_CRX + mov dl, 4 + call Bs3Syscall + +.return: + pop xBP + BS3_CALL_CONV_EPILOG 0 + BS3_HYBRID_RET +BS3_PROC_END_CMN Bs3RegGetCr4 + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-RegGetDr0.asm b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-RegGetDr0.asm new file mode 100644 index 00000000..94fd37a4 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-RegGetDr0.asm @@ -0,0 +1,79 @@ +; $Id: bs3-cmn-RegGetDr0.asm $ +;; @file +; BS3Kit - Bs3RegGetDr0 +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + +%include "bs3kit-template-header.mac" + + +BS3_EXTERN_CMN Bs3Panic +BS3_EXTERN_CMN Bs3Syscall +%if TMPL_BITS == 16 +BS3_EXTERN_DATA16 g_bBs3CurrentMode +%endif +TMPL_BEGIN_TEXT + + +;; +; @cproto BS3_CMN_PROTO_STUB(RTCCUINTXREG, Bs3RegGetDr0,(void)); +; +; @returns Register value. +; @remarks Does not require 20h of parameter scratch space in 64-bit mode. +; +; @uses No GPRs (only return full register(s)). +; +BS3_PROC_BEGIN_CMN Bs3RegGetDr0, BS3_PBC_HYBRID_SAFE + BS3_CALL_CONV_PROLOG 0 + push xBP + mov xBP, xSP + +%if TMPL_BITS == 16 + ; If V8086 mode we have to go thru a syscall. + test byte [BS3_DATA16_WRT(g_bBs3CurrentMode)], BS3_MODE_CODE_V86 + jnz .via_system_call + cmp byte [BS3_DATA16_WRT(g_bBs3CurrentMode)], BS3_MODE_RM + je .direct_access +%endif + ; If not in ring-0, we have to make a system call. + mov ax, ss + and ax, X86_SEL_RPL + jnz .via_system_call + +.direct_access: + mov sAX, dr0 +TONLY16 mov edx, eax +TONLY16 shr edx, 16 + jmp .return + +.via_system_call: + mov xAX, BS3_SYSCALL_GET_DRX + mov dl, 0 + call Bs3Syscall + +.return: + pop xBP + BS3_CALL_CONV_EPILOG 0 + BS3_HYBRID_RET +BS3_PROC_END_CMN Bs3RegGetDr0 + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-RegGetDr1.asm b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-RegGetDr1.asm new file mode 100644 index 00000000..9e5236e6 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-RegGetDr1.asm @@ -0,0 +1,79 @@ +; $Id: bs3-cmn-RegGetDr1.asm $ +;; @file +; BS3Kit - Bs3RegGetDr1 +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + +%include "bs3kit-template-header.mac" + + +BS3_EXTERN_CMN Bs3Panic +BS3_EXTERN_CMN Bs3Syscall +%if TMPL_BITS == 16 +BS3_EXTERN_DATA16 g_bBs3CurrentMode +%endif +TMPL_BEGIN_TEXT + + +;; +; @cproto BS3_CMN_PROTO_STUB(RTCCUINTXREG, Bs3RegGetDr1,(void)); +; +; @returns Register value. +; @remarks Does not require 20h of parameter scratch space in 64-bit mode. +; +; @uses No GPRs (only return full register(s)). +; +BS3_PROC_BEGIN_CMN Bs3RegGetDr1, BS3_PBC_HYBRID_SAFE + BS3_CALL_CONV_PROLOG 0 + push xBP + mov xBP, xSP + +%if TMPL_BITS == 16 + ; If V8086 mode we have to go thru a syscall. + test byte [BS3_DATA16_WRT(g_bBs3CurrentMode)], BS3_MODE_CODE_V86 + jnz .via_system_call + cmp byte [BS3_DATA16_WRT(g_bBs3CurrentMode)], BS3_MODE_RM + je .direct_access +%endif + ; If not in ring-0, we have to make a system call. + mov ax, ss + and ax, X86_SEL_RPL + jnz .via_system_call + +.direct_access: + mov sAX, dr1 +TONLY16 mov edx, eax +TONLY16 shr edx, 16 + jmp .return + +.via_system_call: + mov xAX, BS3_SYSCALL_GET_DRX + mov dl, 1 + call Bs3Syscall + +.return: + pop xBP + BS3_CALL_CONV_EPILOG 0 + BS3_HYBRID_RET +BS3_PROC_END_CMN Bs3RegGetDr1 + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-RegGetDr2.asm b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-RegGetDr2.asm new file mode 100644 index 00000000..103fcbf8 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-RegGetDr2.asm @@ -0,0 +1,79 @@ +; $Id: bs3-cmn-RegGetDr2.asm $ +;; @file +; BS3Kit - Bs3RegGetDr2 +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + +%include "bs3kit-template-header.mac" + + +BS3_EXTERN_CMN Bs3Panic +BS3_EXTERN_CMN Bs3Syscall +%if TMPL_BITS == 16 +BS3_EXTERN_DATA16 g_bBs3CurrentMode +%endif +TMPL_BEGIN_TEXT + + +;; +; @cproto BS3_CMN_PROTO_STUB(RTCCUINTXREG, Bs3RegGetDr2,(void)); +; +; @returns Register value. +; @remarks Does not require 20h of parameter scratch space in 64-bit mode. +; +; @uses No GPRs (only return full register(s)). +; +BS3_PROC_BEGIN_CMN Bs3RegGetDr2, BS3_PBC_HYBRID_SAFE + BS3_CALL_CONV_PROLOG 0 + push xBP + mov xBP, xSP + +%if TMPL_BITS == 16 + ; If V8086 mode we have to go thru a syscall. + test byte [BS3_DATA16_WRT(g_bBs3CurrentMode)], BS3_MODE_CODE_V86 + jnz .via_system_call + cmp byte [BS3_DATA16_WRT(g_bBs3CurrentMode)], BS3_MODE_RM + je .direct_access +%endif + ; If not in ring-0, we have to make a system call. + mov ax, ss + and ax, X86_SEL_RPL + jnz .via_system_call + +.direct_access: + mov sAX, dr2 +TONLY16 mov edx, eax +TONLY16 shr edx, 16 + jmp .return + +.via_system_call: + mov xAX, BS3_SYSCALL_GET_DRX + mov dl, 2 + call Bs3Syscall + +.return: + pop xBP + BS3_CALL_CONV_EPILOG 0 + BS3_HYBRID_RET +BS3_PROC_END_CMN Bs3RegGetDr2 + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-RegGetDr3.asm b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-RegGetDr3.asm new file mode 100644 index 00000000..4842d2fa --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-RegGetDr3.asm @@ -0,0 +1,79 @@ +; $Id: bs3-cmn-RegGetDr3.asm $ +;; @file +; BS3Kit - Bs3RegGetDr3 +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + +%include "bs3kit-template-header.mac" + + +BS3_EXTERN_CMN Bs3Panic +BS3_EXTERN_CMN Bs3Syscall +%if TMPL_BITS == 16 +BS3_EXTERN_DATA16 g_bBs3CurrentMode +%endif +TMPL_BEGIN_TEXT + + +;; +; @cproto BS3_CMN_PROTO_STUB(RTCCUINTXREG, Bs3RegGetDr3,(void)); +; +; @returns Register value. +; @remarks Does not require 20h of parameter scratch space in 64-bit mode. +; +; @uses No GPRs (only return full register(s)). +; +BS3_PROC_BEGIN_CMN Bs3RegGetDr3, BS3_PBC_HYBRID_SAFE + BS3_CALL_CONV_PROLOG 0 + push xBP + mov xBP, xSP + +%if TMPL_BITS == 16 + ; If V8086 mode we have to go thru a syscall. + test byte [BS3_DATA16_WRT(g_bBs3CurrentMode)], BS3_MODE_CODE_V86 + jnz .via_system_call + cmp byte [BS3_DATA16_WRT(g_bBs3CurrentMode)], BS3_MODE_RM + je .direct_access +%endif + ; If not in ring-0, we have to make a system call. + mov ax, ss + and ax, X86_SEL_RPL + jnz .via_system_call + +.direct_access: + mov sAX, dr3 +TONLY16 mov edx, eax +TONLY16 shr edx, 16 + jmp .return + +.via_system_call: + mov xAX, BS3_SYSCALL_GET_DRX + mov dl, 3 + call Bs3Syscall + +.return: + pop xBP + BS3_CALL_CONV_EPILOG 0 + BS3_HYBRID_RET +BS3_PROC_END_CMN Bs3RegGetDr3 + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-RegGetDr6.asm b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-RegGetDr6.asm new file mode 100644 index 00000000..f17b6597 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-RegGetDr6.asm @@ -0,0 +1,79 @@ +; $Id: bs3-cmn-RegGetDr6.asm $ +;; @file +; BS3Kit - Bs3RegGetDr6 +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + +%include "bs3kit-template-header.mac" + + +BS3_EXTERN_CMN Bs3Panic +BS3_EXTERN_CMN Bs3Syscall +%if TMPL_BITS == 16 +BS3_EXTERN_DATA16 g_bBs3CurrentMode +%endif +TMPL_BEGIN_TEXT + + +;; +; @cproto BS3_CMN_PROTO_STUB(RTCCUINTXREG, Bs3RegGetDr6,(void)); +; +; @returns Register value. +; @remarks Does not require 20h of parameter scratch space in 64-bit mode. +; +; @uses No GPRs (only return full register(s)). +; +BS3_PROC_BEGIN_CMN Bs3RegGetDr6, BS3_PBC_HYBRID_SAFE + BS3_CALL_CONV_PROLOG 0 + push xBP + mov xBP, xSP + +%if TMPL_BITS == 16 + ; If V8086 mode we have to go thru a syscall. + test byte [BS3_DATA16_WRT(g_bBs3CurrentMode)], BS3_MODE_CODE_V86 + jnz .via_system_call + cmp byte [BS3_DATA16_WRT(g_bBs3CurrentMode)], BS3_MODE_RM + je .direct_access +%endif + ; If not in ring-0, we have to make a system call. + mov ax, ss + and ax, X86_SEL_RPL + jnz .via_system_call + +.direct_access: + mov sAX, dr6 +TONLY16 mov edx, eax +TONLY16 shr edx, 16 + jmp .return + +.via_system_call: + mov xAX, BS3_SYSCALL_GET_DRX + mov dl, 6 + call Bs3Syscall + +.return: + pop xBP + BS3_CALL_CONV_EPILOG 0 + BS3_HYBRID_RET +BS3_PROC_END_CMN Bs3RegGetDr6 + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-RegGetDr7.asm b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-RegGetDr7.asm new file mode 100644 index 00000000..15810c6f --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-RegGetDr7.asm @@ -0,0 +1,79 @@ +; $Id: bs3-cmn-RegGetDr7.asm $ +;; @file +; BS3Kit - Bs3RegGetDr7 +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + +%include "bs3kit-template-header.mac" + + +BS3_EXTERN_CMN Bs3Panic +BS3_EXTERN_CMN Bs3Syscall +%if TMPL_BITS == 16 +BS3_EXTERN_DATA16 g_bBs3CurrentMode +%endif +TMPL_BEGIN_TEXT + + +;; +; @cproto BS3_CMN_PROTO_STUB(RTCCUINTXREG, Bs3RegGetDr7,(void)); +; +; @returns Register value. +; @remarks Does not require 20h of parameter scratch space in 64-bit mode. +; +; @uses No GPRs (only return full register(s)). +; +BS3_PROC_BEGIN_CMN Bs3RegGetDr7, BS3_PBC_HYBRID_SAFE + BS3_CALL_CONV_PROLOG 0 + push xBP + mov xBP, xSP + +%if TMPL_BITS == 16 + ; If V8086 mode we have to go thru a syscall. + test byte [BS3_DATA16_WRT(g_bBs3CurrentMode)], BS3_MODE_CODE_V86 + jnz .via_system_call + cmp byte [BS3_DATA16_WRT(g_bBs3CurrentMode)], BS3_MODE_RM + je .direct_access +%endif + ; If not in ring-0, we have to make a system call. + mov ax, ss + and ax, X86_SEL_RPL + jnz .via_system_call + +.direct_access: + mov sAX, dr7 +TONLY16 mov edx, eax +TONLY16 shr edx, 16 + jmp .return + +.via_system_call: + mov xAX, BS3_SYSCALL_GET_DRX + mov dl, 7 + call Bs3Syscall + +.return: + pop xBP + BS3_CALL_CONV_EPILOG 0 + BS3_HYBRID_RET +BS3_PROC_END_CMN Bs3RegGetDr7 + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-RegGetDrX.asm b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-RegGetDrX.asm new file mode 100644 index 00000000..331732b4 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-RegGetDrX.asm @@ -0,0 +1,125 @@ +; $Id: bs3-cmn-RegGetDrX.asm $ +;; @file +; BS3Kit - Bs3RegGetDrX +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + +%include "bs3kit-template-header.mac" + + +BS3_EXTERN_CMN Bs3Panic +BS3_EXTERN_CMN Bs3Syscall +%if TMPL_BITS == 16 +BS3_EXTERN_DATA16 g_bBs3CurrentMode +%endif +TMPL_BEGIN_TEXT + +;TONLY16 CPU 386 + +;; +; @cproto BS3_CMN_PROTO_STUB(RTCCUINTXREG, Bs3RegGetDrX,(uint8_t iReg)); +; +; @returns Register value. +; @param iRegister The source register +; @remarks Does not require 20h of parameter scratch space in 64-bit mode. +; +; @uses No GPRs (only return full register(s)). +; +BS3_PROC_BEGIN_CMN Bs3RegGetDrX, BS3_PBC_HYBRID_SAFE + BS3_CALL_CONV_PROLOG 1 + push xBP + mov xBP, xSP + +%if TMPL_BITS == 16 + ; If V8086 mode we have to go thru a syscall. + test byte [BS3_DATA16_WRT(g_bBs3CurrentMode)], BS3_MODE_CODE_V86 + jnz .via_system_call + cmp byte [BS3_DATA16_WRT(g_bBs3CurrentMode)], BS3_MODE_RM + je .direct_access +%endif + ; If not in ring-0, we have to make a system call. + mov ax, ss + and ax, X86_SEL_RPL + jnz .via_system_call + +.direct_access: + ; Switch (iRegister) + mov al, [xBP + xCB + cbCurRetAddr] + cmp al, 6 + jz .get_dr6 + cmp al, 7 + jz .get_dr7 + cmp al, 0 + jz .get_dr0 + cmp al, 1 + jz .get_dr1 + cmp al, 2 + jz .get_dr2 + cmp al, 3 + jz .get_dr3 + cmp al, 4 + jz .get_dr4 + cmp al, 5 + jz .get_dr5 + call Bs3Panic + +.get_dr0: + mov sAX, dr0 + jmp .return_fixup +.get_dr1: + mov sAX, dr1 + jmp .return_fixup +.get_dr2: + mov sAX, dr2 + jmp .return_fixup +.get_dr3: + mov sAX, dr3 + jmp .return_fixup +.get_dr4: + mov sAX, dr4 + jmp .return_fixup +.get_dr5: + mov sAX, dr5 + jmp .return_fixup +.get_dr7: + mov sAX, dr7 + jmp .return_fixup +.get_dr6: + mov sAX, dr6 + jmp .return_fixup + +.via_system_call: + mov xAX, BS3_SYSCALL_GET_DRX + mov dl, [xBP + xCB + cbCurRetAddr] + call Bs3Syscall + jmp .return + +.return_fixup: +TONLY16 mov edx, eax +TONLY16 shr edx, 16 +.return: + pop xBP + BS3_CALL_CONV_EPILOG 1 + BS3_HYBRID_RET +BS3_PROC_END_CMN Bs3RegGetDrX + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-RegGetLdtr.asm b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-RegGetLdtr.asm new file mode 100644 index 00000000..8e160b07 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-RegGetLdtr.asm @@ -0,0 +1,70 @@ +; $Id: bs3-cmn-RegGetLdtr.asm $ +;; @file +; BS3Kit - Bs3RegGetLdtr +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + +%include "bs3kit-template-header.mac" + + +BS3_EXTERN_CMN Bs3Syscall +%if TMPL_BITS == 16 +BS3_EXTERN_DATA16 g_bBs3CurrentMode +%endif +BS3_EXTERN_SYSTEM16 Bs3Gdt +TMPL_BEGIN_TEXT + + +;; +; @cproto BS3_CMN_PROTO_STUB(uint16_t, Bs3RegGetLdtr,(void)); +; +; @returns The LDTR value. + +; @remarks Does not require 20h of parameter scratch space in 64-bit mode. +; +; @uses No GPRs. +; +BS3_PROC_BEGIN_CMN Bs3RegGetLdtr, BS3_PBC_HYBRID_SAFE + BS3_CALL_CONV_PROLOG 0 + push xBP + mov xBP, xSP + +%if TMPL_BITS == 16 + ; If V8086 mode we have to go thru a syscall. + test byte [BS3_DATA16_WRT(g_bBs3CurrentMode)], BS3_MODE_CODE_V86 + jnz .via_system_call +%endif + ; Load it. + sldt ax + jmp .return + +.via_system_call: + mov ax, BS3_SYSCALL_GET_LDTR + call Bs3Syscall + +.return: + pop xBP + BS3_CALL_CONV_EPILOG 0 + BS3_HYBRID_RET +BS3_PROC_END_CMN Bs3RegGetLdtr + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-RegGetTr.asm b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-RegGetTr.asm new file mode 100644 index 00000000..6e4ff7d4 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-RegGetTr.asm @@ -0,0 +1,70 @@ +; $Id: bs3-cmn-RegGetTr.asm $ +;; @file +; BS3Kit - Bs3RegGetTr +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + +%include "bs3kit-template-header.mac" + + +BS3_EXTERN_CMN Bs3Syscall +%if TMPL_BITS == 16 +BS3_EXTERN_DATA16 g_bBs3CurrentMode +%endif +BS3_EXTERN_SYSTEM16 Bs3Gdt +TMPL_BEGIN_TEXT + + +;; +; @cproto BS3_CMN_PROTO_STUB(uint16_t, Bs3RegGetTr,(void)); +; +; @returns The LDTR value. + +; @remarks Does not require 20h of parameter scratch space in 64-bit mode. +; +; @uses No GPRs. +; +BS3_PROC_BEGIN_CMN Bs3RegGetTr, BS3_PBC_HYBRID_SAFE + BS3_CALL_CONV_PROLOG 0 + push xBP + mov xBP, xSP + +%if TMPL_BITS == 16 + ; If V8086 mode we have to go thru a syscall. + test byte [BS3_DATA16_WRT(g_bBs3CurrentMode)], BS3_MODE_CODE_V86 + jnz .via_system_call +%endif + ; Load it. + str ax + jmp .return + +.via_system_call: + mov ax, BS3_SYSCALL_GET_TR + call Bs3Syscall + +.return: + pop xBP + BS3_CALL_CONV_EPILOG 0 + BS3_HYBRID_RET +BS3_PROC_END_CMN Bs3RegGetTr + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-RegSetCr0.asm b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-RegSetCr0.asm new file mode 100644 index 00000000..1efc8e31 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-RegSetCr0.asm @@ -0,0 +1,86 @@ +; $Id: bs3-cmn-RegSetCr0.asm $ +;; @file +; BS3Kit - Bs3RegSetCr0 +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + +%include "bs3kit-template-header.mac" + + +BS3_EXTERN_CMN Bs3Syscall +%if TMPL_BITS == 16 +BS3_EXTERN_DATA16 g_bBs3CurrentMode +%endif +TMPL_BEGIN_TEXT + + +;; +; @cproto BS3_CMN_PROTO_STUB(void, Bs3RegSetCr0,(RTCCUINTXREG uValue)); +; +; @param uValue The value to set. + +; @remarks Does not require 20h of parameter scratch space in 64-bit mode. +; +; @uses No GPRs. +; +BS3_PROC_BEGIN_CMN Bs3RegSetCr0, BS3_PBC_HYBRID_SAFE + BS3_CALL_CONV_PROLOG 1 + push xBP + mov xBP, xSP + push sSI + +%if TMPL_BITS == 16 + ; If V8086 mode we have to go thru a syscall. + test byte [BS3_DATA16_WRT(g_bBs3CurrentMode)], BS3_MODE_CODE_V86 + jnz .via_system_call + cmp byte [BS3_DATA16_WRT(g_bBs3CurrentMode)], BS3_MODE_RM + je .direct_access +%endif + ; If not in ring-0, we have to make a system call. + mov si, ss + and si, X86_SEL_RPL + jnz .via_system_call + +.direct_access: + mov sSI, [xBP + xCB + cbCurRetAddr] + mov cr0, sSI + jmp .return + +.via_system_call: + push xDX + push xAX + + mov sSI, [xBP + xCB + cbCurRetAddr] + mov xAX, BS3_SYSCALL_SET_DRX + mov dl, 0 + call Bs3Syscall + pop xAX + pop xDX + +.return: + pop sSI + pop xBP + BS3_CALL_CONV_EPILOG 1 + BS3_HYBRID_RET +BS3_PROC_END_CMN Bs3RegSetCr0 + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-RegSetCr2.asm b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-RegSetCr2.asm new file mode 100644 index 00000000..c277179f --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-RegSetCr2.asm @@ -0,0 +1,86 @@ +; $Id: bs3-cmn-RegSetCr2.asm $ +;; @file +; BS3Kit - Bs3RegSetCr2 +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + +%include "bs3kit-template-header.mac" + + +BS3_EXTERN_CMN Bs3Syscall +%if TMPL_BITS == 16 +BS3_EXTERN_DATA16 g_bBs3CurrentMode +%endif +TMPL_BEGIN_TEXT + + +;; +; @cproto BS3_CMN_PROTO_STUB(void, Bs3RegSetCr1,(RTCCUINTXREG uValue)); +; +; @param uValue The value to set. + +; @remarks Does not require 20h of parameter scratch space in 64-bit mode. +; +; @uses No GPRs. +; +BS3_PROC_BEGIN_CMN Bs3RegSetCr2, BS3_PBC_HYBRID_SAFE + BS3_CALL_CONV_PROLOG 1 + push xBP + mov xBP, xSP + push sSI + +%if TMPL_BITS == 16 + ; If V8086 mode we have to go thru a syscall. + test byte [BS3_DATA16_WRT(g_bBs3CurrentMode)], BS3_MODE_CODE_V86 + jnz .via_system_call + cmp byte [BS3_DATA16_WRT(g_bBs3CurrentMode)], BS3_MODE_RM + je .direct_access +%endif + ; If not in ring-0, we have to make a system call. + mov si, ss + and si, X86_SEL_RPL + jnz .via_system_call + +.direct_access: + mov sSI, [xBP + xCB + cbCurRetAddr] + mov cr2, sSI + jmp .return + +.via_system_call: + push xDX + push xAX + + mov sSI, [xBP + xCB + cbCurRetAddr] + mov xAX, BS3_SYSCALL_SET_DRX + mov dl, 2 + call Bs3Syscall + pop xAX + pop xDX + +.return: + pop sSI + pop xBP + BS3_CALL_CONV_EPILOG 1 + BS3_HYBRID_RET +BS3_PROC_END_CMN Bs3RegSetCr2 + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-RegSetCr3.asm b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-RegSetCr3.asm new file mode 100644 index 00000000..ea165a95 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-RegSetCr3.asm @@ -0,0 +1,86 @@ +; $Id: bs3-cmn-RegSetCr3.asm $ +;; @file +; BS3Kit - Bs3RegSetCr3 +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + +%include "bs3kit-template-header.mac" + + +BS3_EXTERN_CMN Bs3Syscall +%if TMPL_BITS == 16 +BS3_EXTERN_DATA16 g_bBs3CurrentMode +%endif +TMPL_BEGIN_TEXT + + +;; +; @cproto BS3_CMN_PROTO_STUB(void, Bs3RegSetCr3,(RTCCUINTXREG uValue)); +; +; @param uValue The value to set. + +; @remarks Does not require 20h of parameter scratch space in 64-bit mode. +; +; @uses No GPRs. +; +BS3_PROC_BEGIN_CMN Bs3RegSetCr3, BS3_PBC_HYBRID_SAFE + BS3_CALL_CONV_PROLOG 1 + push xBP + mov xBP, xSP + push sSI + +%if TMPL_BITS == 16 + ; If V8086 mode we have to go thru a syscall. + test byte [BS3_DATA16_WRT(g_bBs3CurrentMode)], BS3_MODE_CODE_V86 + jnz .via_system_call + cmp byte [BS3_DATA16_WRT(g_bBs3CurrentMode)], BS3_MODE_RM + je .direct_access +%endif + ; If not in ring-0, we have to make a system call. + mov si, ss + and si, X86_SEL_RPL + jnz .via_system_call + +.direct_access: + mov sSI, [xBP + xCB + cbCurRetAddr] + mov cr3, sSI + jmp .return + +.via_system_call: + push xDX + push xAX + + mov sSI, [xBP + xCB + cbCurRetAddr] + mov xAX, BS3_SYSCALL_SET_DRX + mov dl, 3 + call Bs3Syscall + pop xAX + pop xDX + +.return: + pop sSI + pop xBP + BS3_CALL_CONV_EPILOG 1 + BS3_HYBRID_RET +BS3_PROC_END_CMN Bs3RegSetCr3 + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-RegSetCr4.asm b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-RegSetCr4.asm new file mode 100644 index 00000000..1d79cc90 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-RegSetCr4.asm @@ -0,0 +1,86 @@ +; $Id: bs3-cmn-RegSetCr4.asm $ +;; @file +; BS3Kit - Bs3RegSetCr4 +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + +%include "bs3kit-template-header.mac" + + +BS3_EXTERN_CMN Bs3Syscall +%if TMPL_BITS == 16 +BS3_EXTERN_DATA16 g_bBs3CurrentMode +%endif +TMPL_BEGIN_TEXT + + +;; +; @cproto BS3_CMN_PROTO_STUB(void, Bs3RegSetCr4,(RTCCUINTXREG uValue)); +; +; @param uValue The value to set. + +; @remarks Does not require 20h of parameter scratch space in 64-bit mode. +; +; @uses No GPRs. +; +BS3_PROC_BEGIN_CMN Bs3RegSetCr4, BS3_PBC_HYBRID_SAFE + BS3_CALL_CONV_PROLOG 1 + push xBP + mov xBP, xSP + push sSI + +%if TMPL_BITS == 16 + ; If V8086 mode we have to go thru a syscall. + test byte [BS3_DATA16_WRT(g_bBs3CurrentMode)], BS3_MODE_CODE_V86 + jnz .via_system_call + cmp byte [BS3_DATA16_WRT(g_bBs3CurrentMode)], BS3_MODE_RM + je .direct_access +%endif + ; If not in ring-0, we have to make a system call. + mov si, ss + and si, X86_SEL_RPL + jnz .via_system_call + +.direct_access: + mov sSI, [xBP + xCB + cbCurRetAddr] + mov cr4, sSI + jmp .return + +.via_system_call: + push xDX + push xAX + + mov sSI, [xBP + xCB + cbCurRetAddr] + mov xAX, BS3_SYSCALL_SET_DRX + mov dl, 4 + call Bs3Syscall + pop xAX + pop xDX + +.return: + pop sSI + pop xBP + BS3_CALL_CONV_EPILOG 1 + BS3_HYBRID_RET +BS3_PROC_END_CMN Bs3RegSetCr4 + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-RegSetDr0.asm b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-RegSetDr0.asm new file mode 100644 index 00000000..2050450d --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-RegSetDr0.asm @@ -0,0 +1,86 @@ +; $Id: bs3-cmn-RegSetDr0.asm $ +;; @file +; BS3Kit - Bs3RegSetDr0 +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + +%include "bs3kit-template-header.mac" + + +BS3_EXTERN_CMN Bs3Syscall +%if TMPL_BITS == 16 +BS3_EXTERN_DATA16 g_bBs3CurrentMode +%endif +TMPL_BEGIN_TEXT + + +;; +; @cproto BS3_CMN_PROTO_STUB(void, Bs3RegSetDr0,(RTCCUINTXREG uValue)); +; +; @param uValue The value to set. + +; @remarks Does not require 20h of parameter scratch space in 64-bit mode. +; +; @uses No GPRs. +; +BS3_PROC_BEGIN_CMN Bs3RegSetDr0, BS3_PBC_HYBRID_SAFE + BS3_CALL_CONV_PROLOG 1 + push xBP + mov xBP, xSP + push sSI + +%if TMPL_BITS == 16 + ; If V8086 mode we have to go thru a syscall. + test byte [BS3_DATA16_WRT(g_bBs3CurrentMode)], BS3_MODE_CODE_V86 + jnz .via_system_call + cmp byte [BS3_DATA16_WRT(g_bBs3CurrentMode)], BS3_MODE_RM + je .direct_access +%endif + ; If not in ring-0, we have to make a system call. + mov si, ss + and si, X86_SEL_RPL + jnz .via_system_call + +.direct_access: + mov sSI, [xBP + xCB + cbCurRetAddr] + mov dr0, sSI + jmp .return + +.via_system_call: + push xDX + push xAX + + mov sSI, [xBP + xCB + cbCurRetAddr] + mov xAX, BS3_SYSCALL_SET_DRX + mov dl, 0 + call Bs3Syscall + pop xAX + pop xDX + +.return: + pop sSI + pop xBP + BS3_CALL_CONV_EPILOG 1 + BS3_HYBRID_RET +BS3_PROC_END_CMN Bs3RegSetDr0 + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-RegSetDr1.asm b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-RegSetDr1.asm new file mode 100644 index 00000000..b5cc4387 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-RegSetDr1.asm @@ -0,0 +1,86 @@ +; $Id: bs3-cmn-RegSetDr1.asm $ +;; @file +; BS3Kit - Bs3RegSetDr1 +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + +%include "bs3kit-template-header.mac" + + +BS3_EXTERN_CMN Bs3Syscall +%if TMPL_BITS == 16 +BS3_EXTERN_DATA16 g_bBs3CurrentMode +%endif +TMPL_BEGIN_TEXT + + +;; +; @cproto BS3_CMN_PROTO_STUB(void, Bs3RegSetDr1,(RTCCUINTXREG uValue)); +; +; @param uValue The value to set. + +; @remarks Does not require 20h of parameter scratch space in 64-bit mode. +; +; @uses No GPRs. +; +BS3_PROC_BEGIN_CMN Bs3RegSetDr1, BS3_PBC_HYBRID_SAFE + BS3_CALL_CONV_PROLOG 1 + push xBP + mov xBP, xSP + push sSI + +%if TMPL_BITS == 16 + ; If V8086 mode we have to go thru a syscall. + test byte [BS3_DATA16_WRT(g_bBs3CurrentMode)], BS3_MODE_CODE_V86 + jnz .via_system_call + cmp byte [BS3_DATA16_WRT(g_bBs3CurrentMode)], BS3_MODE_RM + je .direct_access +%endif + ; If not in ring-0, we have to make a system call. + mov si, ss + and si, X86_SEL_RPL + jnz .via_system_call + +.direct_access: + mov sSI, [xBP + xCB + cbCurRetAddr] + mov dr1, sSI + jmp .return + +.via_system_call: + push xDX + push xAX + + mov sSI, [xBP + xCB + cbCurRetAddr] + mov xAX, BS3_SYSCALL_SET_DRX + mov dl, 1 + call Bs3Syscall + pop xAX + pop xDX + +.return: + pop sSI + pop xBP + BS3_CALL_CONV_EPILOG 1 + BS3_HYBRID_RET +BS3_PROC_END_CMN Bs3RegSetDr1 + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-RegSetDr2.asm b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-RegSetDr2.asm new file mode 100644 index 00000000..d639308d --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-RegSetDr2.asm @@ -0,0 +1,86 @@ +; $Id: bs3-cmn-RegSetDr2.asm $ +;; @file +; BS3Kit - Bs3RegSetDr2 +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + +%include "bs3kit-template-header.mac" + + +BS3_EXTERN_CMN Bs3Syscall +%if TMPL_BITS == 16 +BS3_EXTERN_DATA16 g_bBs3CurrentMode +%endif +TMPL_BEGIN_TEXT + + +;; +; @cproto BS3_CMN_PROTO_STUB(void, Bs3RegSetDr2,(RTCCUINTXREG uValue)); +; +; @param uValue The value to set. + +; @remarks Does not require 20h of parameter scratch space in 64-bit mode. +; +; @uses No GPRs. +; +BS3_PROC_BEGIN_CMN Bs3RegSetDr2, BS3_PBC_HYBRID_SAFE + BS3_CALL_CONV_PROLOG 1 + push xBP + mov xBP, xSP + push sSI + +%if TMPL_BITS == 16 + ; If V8086 mode we have to go thru a syscall. + test byte [BS3_DATA16_WRT(g_bBs3CurrentMode)], BS3_MODE_CODE_V86 + jnz .via_system_call + cmp byte [BS3_DATA16_WRT(g_bBs3CurrentMode)], BS3_MODE_RM + je .direct_access +%endif + ; If not in ring-0, we have to make a system call. + mov si, ss + and si, X86_SEL_RPL + jnz .via_system_call + +.direct_access: + mov sSI, [xBP + xCB + cbCurRetAddr] + mov dr2, sSI + jmp .return + +.via_system_call: + push xDX + push xAX + + mov sSI, [xBP + xCB + cbCurRetAddr] + mov xAX, BS3_SYSCALL_SET_DRX + mov dl, 2 + call Bs3Syscall + pop xAX + pop xDX + +.return: + pop sSI + pop xBP + BS3_CALL_CONV_EPILOG 1 + BS3_HYBRID_RET +BS3_PROC_END_CMN Bs3RegSetDr2 + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-RegSetDr3.asm b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-RegSetDr3.asm new file mode 100644 index 00000000..73f74239 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-RegSetDr3.asm @@ -0,0 +1,86 @@ +; $Id: bs3-cmn-RegSetDr3.asm $ +;; @file +; BS3Kit - Bs3RegSetDr3 +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + +%include "bs3kit-template-header.mac" + + +BS3_EXTERN_CMN Bs3Syscall +%if TMPL_BITS == 16 +BS3_EXTERN_DATA16 g_bBs3CurrentMode +%endif +TMPL_BEGIN_TEXT + + +;; +; @cproto BS3_CMN_PROTO_STUB(void, Bs3RegSetDr3,(RTCCUINTXREG uValue)); +; +; @param uValue The value to set. + +; @remarks Does not require 20h of parameter scratch space in 64-bit mode. +; +; @uses No GPRs. +; +BS3_PROC_BEGIN_CMN Bs3RegSetDr3, BS3_PBC_HYBRID_SAFE + BS3_CALL_CONV_PROLOG 1 + push xBP + mov xBP, xSP + push sSI + +%if TMPL_BITS == 16 + ; If V8086 mode we have to go thru a syscall. + test byte [BS3_DATA16_WRT(g_bBs3CurrentMode)], BS3_MODE_CODE_V86 + jnz .via_system_call + cmp byte [BS3_DATA16_WRT(g_bBs3CurrentMode)], BS3_MODE_RM + je .direct_access +%endif + ; If not in ring-0, we have to make a system call. + mov si, ss + and si, X86_SEL_RPL + jnz .via_system_call + +.direct_access: + mov sSI, [xBP + xCB + cbCurRetAddr] + mov dr3, sSI + jmp .return + +.via_system_call: + push xDX + push xAX + + mov sSI, [xBP + xCB + cbCurRetAddr] + mov xAX, BS3_SYSCALL_SET_DRX + mov dl, 3 + call Bs3Syscall + pop xAX + pop xDX + +.return: + pop sSI + pop xBP + BS3_CALL_CONV_EPILOG 1 + BS3_HYBRID_RET +BS3_PROC_END_CMN Bs3RegSetDr3 + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-RegSetDr6.asm b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-RegSetDr6.asm new file mode 100644 index 00000000..84ed493c --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-RegSetDr6.asm @@ -0,0 +1,86 @@ +; $Id: bs3-cmn-RegSetDr6.asm $ +;; @file +; BS3Kit - Bs3RegSetDr6 +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + +%include "bs3kit-template-header.mac" + + +BS3_EXTERN_CMN Bs3Syscall +%if TMPL_BITS == 16 +BS3_EXTERN_DATA16 g_bBs3CurrentMode +%endif +TMPL_BEGIN_TEXT + + +;; +; @cproto BS3_CMN_PROTO_STUB(void, Bs3RegSetDr6,(RTCCUINTXREG uValue)); +; +; @param uValue The value to set. + +; @remarks Does not require 20h of parameter scratch space in 64-bit mode. +; +; @uses No GPRs. +; +BS3_PROC_BEGIN_CMN Bs3RegSetDr6, BS3_PBC_HYBRID_SAFE + BS3_CALL_CONV_PROLOG 1 + push xBP + mov xBP, xSP + push sSI + +%if TMPL_BITS == 16 + ; If V8086 mode we have to go thru a syscall. + test byte [BS3_DATA16_WRT(g_bBs3CurrentMode)], BS3_MODE_CODE_V86 + jnz .via_system_call + cmp byte [BS3_DATA16_WRT(g_bBs3CurrentMode)], BS3_MODE_RM + je .direct_access +%endif + ; If not in ring-0, we have to make a system call. + mov si, ss + and si, X86_SEL_RPL + jnz .via_system_call + +.direct_access: + mov sSI, [xBP + xCB + cbCurRetAddr] + mov dr6, sSI + jmp .return + +.via_system_call: + push xDX + push xAX + + mov sSI, [xBP + xCB + cbCurRetAddr] + mov xAX, BS3_SYSCALL_SET_DRX + mov dl, 6 + call Bs3Syscall + pop xAX + pop xDX + +.return: + pop sSI + pop xBP + BS3_CALL_CONV_EPILOG 1 + BS3_HYBRID_RET +BS3_PROC_END_CMN Bs3RegSetDr6 + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-RegSetDr7.asm b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-RegSetDr7.asm new file mode 100644 index 00000000..6720c29a --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-RegSetDr7.asm @@ -0,0 +1,86 @@ +; $Id: bs3-cmn-RegSetDr7.asm $ +;; @file +; BS3Kit - Bs3RegSetDr7 +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + +%include "bs3kit-template-header.mac" + + +BS3_EXTERN_CMN Bs3Syscall +%if TMPL_BITS == 16 +BS3_EXTERN_DATA16 g_bBs3CurrentMode +%endif +TMPL_BEGIN_TEXT + + +;; +; @cproto BS3_CMN_PROTO_STUB(void, Bs3RegSetDr7,(RTCCUINTXREG uValue)); +; +; @param uValue The value to set. + +; @remarks Does not require 20h of parameter scratch space in 64-bit mode. +; +; @uses No GPRs. +; +BS3_PROC_BEGIN_CMN Bs3RegSetDr7, BS3_PBC_HYBRID_SAFE + BS3_CALL_CONV_PROLOG 1 + push xBP + mov xBP, xSP + push sSI + +%if TMPL_BITS == 16 + ; If V8086 mode we have to go thru a syscall. + test byte [BS3_DATA16_WRT(g_bBs3CurrentMode)], BS3_MODE_CODE_V86 + jnz .via_system_call + cmp byte [BS3_DATA16_WRT(g_bBs3CurrentMode)], BS3_MODE_RM + je .direct_access +%endif + ; If not in ring-0, we have to make a system call. + mov si, ss + and si, X86_SEL_RPL + jnz .via_system_call + +.direct_access: + mov sSI, [xBP + xCB + cbCurRetAddr] + mov dr7, sSI + jmp .return + +.via_system_call: + push xDX + push xAX + + mov sSI, [xBP + xCB + cbCurRetAddr] + mov xAX, BS3_SYSCALL_SET_DRX + mov dl, 7 + call Bs3Syscall + pop xAX + pop xDX + +.return: + pop sSI + pop xBP + BS3_CALL_CONV_EPILOG 1 + BS3_HYBRID_RET +BS3_PROC_END_CMN Bs3RegSetDr7 + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-RegSetDrX.asm b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-RegSetDrX.asm new file mode 100644 index 00000000..eeddad92 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-RegSetDrX.asm @@ -0,0 +1,132 @@ +; $Id: bs3-cmn-RegSetDrX.asm $ +;; @file +; BS3Kit - Bs3RegSetDrX +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + +%include "bs3kit-template-header.mac" + + +BS3_EXTERN_CMN Bs3Panic +BS3_EXTERN_CMN Bs3Syscall +%if TMPL_BITS == 16 +BS3_EXTERN_DATA16 g_bBs3CurrentMode +%endif +TMPL_BEGIN_TEXT + +;TONLY16 CPU 386 + +;; +; @cproto BS3_CMN_PROTO_STUB(void, Bs3RegSetDrX,(uint8_t iReg, RTCCUINTXREG uValue)); +; +; @returns Register value. +; @param iRegister The source register +; @param uValue The new Value. + +; @remarks Does not require 20h of parameter scratch space in 64-bit mode. +; +; @uses No GPRs. +; +BS3_PROC_BEGIN_CMN Bs3RegSetDrX, BS3_PBC_HYBRID_SAFE + BS3_CALL_CONV_PROLOG 2 + push xBP + mov xBP, xSP + push sSI + push xDX + + mov sSI, [xBP + xCB + cbCurRetAddr + xCB] + +%if TMPL_BITS == 16 + ; If V8086 mode we have to go thru a syscall. + test byte [BS3_DATA16_WRT(g_bBs3CurrentMode)], BS3_MODE_CODE_V86 + jnz .via_system_call + cmp byte [BS3_DATA16_WRT(g_bBs3CurrentMode)], BS3_MODE_RM + je .direct_access +%endif + ; If not in ring-0, we have to make a system call. + mov dx, ss + and dx, X86_SEL_RPL + jnz .via_system_call + +.direct_access: + ; Switch (iRegister) + mov dl, [xBP + xCB + cbCurRetAddr] + cmp dl, 6 + jz .set_dr6 + cmp dl, 7 + jz .set_dr7 + cmp dl, 0 + jz .set_dr0 + cmp dl, 1 + jz .set_dr1 + cmp dl, 2 + jz .set_dr2 + cmp dl, 3 + jz .set_dr3 + cmp dl, 4 + jz .set_dr4 + cmp dl, 5 + jz .set_dr5 + + call Bs3Panic + +.set_dr0: + mov dr0, sSI + jmp .return +.set_dr1: + mov dr1, sSI + jmp .return +.set_dr2: + mov dr2, sSI + jmp .return +.set_dr3: + mov dr3, sSI + jmp .return +.set_dr4: + mov dr4, sSI + jmp .return +.set_dr5: + mov dr5, sSI + jmp .return +.set_dr7: + mov dr7, sSI + jmp .return +.set_dr6: + mov dr6, sSI + jmp .return + +.via_system_call: + mov dl, [xBP + xCB + cbCurRetAddr] + push xAX + mov xAX, BS3_SYSCALL_SET_DRX + call Bs3Syscall + pop xAX + +.return: + pop xDX + pop sSI + pop xBP + BS3_CALL_CONV_EPILOG 2 + BS3_HYBRID_RET +BS3_PROC_END_CMN Bs3RegSetDrX + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-RegSetLdtr.asm b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-RegSetLdtr.asm new file mode 100644 index 00000000..df4ead2d --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-RegSetLdtr.asm @@ -0,0 +1,81 @@ +; $Id: bs3-cmn-RegSetLdtr.asm $ +;; @file +; BS3Kit - Bs3RegSetLdtr +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + +%include "bs3kit-template-header.mac" + + +BS3_EXTERN_CMN Bs3Syscall +%if TMPL_BITS == 16 +BS3_EXTERN_DATA16 g_bBs3CurrentMode +%endif +BS3_EXTERN_SYSTEM16 Bs3Gdt +TMPL_BEGIN_TEXT + + +;; +; @cproto BS3_CMN_PROTO_STUB(void, Bs3RegSetLdtr,(uint16_t uValue)); +; +; @param uValue The value to set. + +; @remarks Does not require 20h of parameter scratch space in 64-bit mode. +; +; @uses No GPRs. +; +BS3_PROC_BEGIN_CMN Bs3RegSetLdtr, BS3_PBC_HYBRID_SAFE + BS3_CALL_CONV_PROLOG 1 + push xBP + mov xBP, xSP + push xDX + push xAX + + mov dx, [xBP + xCB + cbCurRetAddr] + +%if TMPL_BITS == 16 + ; If V8086 mode we have to go thru a syscall. + test byte [BS3_DATA16_WRT(g_bBs3CurrentMode)], BS3_MODE_CODE_V86 + jnz .via_system_call +%endif + ; If not in ring-0, we have to make a system call. + mov ax, ss + and ax, X86_SEL_RPL + jnz .via_system_call + + ; Load it. + lldt dx + jmp .return + +.via_system_call: + mov ax, BS3_SYSCALL_SET_LDTR + call Bs3Syscall + +.return: + pop xAX + pop xDX + pop xBP + BS3_CALL_CONV_EPILOG 1 + BS3_HYBRID_RET +BS3_PROC_END_CMN Bs3RegSetLdtr + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-RegSetTr.asm b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-RegSetTr.asm new file mode 100644 index 00000000..a35c1000 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-RegSetTr.asm @@ -0,0 +1,96 @@ +; $Id: bs3-cmn-RegSetTr.asm $ +;; @file +; BS3Kit - Bs3RegSetTr +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + +%include "bs3kit-template-header.mac" + + +BS3_EXTERN_CMN Bs3Syscall +%if TMPL_BITS == 16 +BS3_EXTERN_DATA16 g_bBs3CurrentMode +%endif +BS3_EXTERN_SYSTEM16 Bs3Gdt +TMPL_BEGIN_TEXT + + +;; +; @cproto BS3_CMN_PROTO_STUB(void, Bs3RegSetTr,(uint16_t uValue)); +; +; @param uValue The value to set. + +; @remarks Does not require 20h of parameter scratch space in 64-bit mode. +; +; @uses No GPRs. +; +BS3_PROC_BEGIN_CMN Bs3RegSetTr, BS3_PBC_HYBRID_SAFE + BS3_CALL_CONV_PROLOG 1 + push xBP + mov xBP, xSP + push xDX + push xAX + push xDI + + mov dx, [xBP + xCB + cbCurRetAddr] + +%if TMPL_BITS == 16 + ; If V8086 mode we have to go thru a syscall. + test byte [BS3_DATA16_WRT(g_bBs3CurrentMode)], BS3_MODE_CODE_V86 + jnz .via_system_call +%endif + ; If not in ring-0, we have to make a system call. + mov ax, ss + and ax, X86_SEL_RPL + jnz .via_system_call + + ; Before we can load it, we must mark it non-busy. +%if TMPL_BITS == 16 + push ds + mov ax, BS3_SEL_SYSTEM16 + mov ds, ax + add xDI, Bs3Gdt wrt BS3SYSTEM16 +%else + add xDI, Bs3Gdt wrt FLAT +%endif + add xDI, X86DESCGENERIC_BIT_OFF_TYPE / 8 + and byte [xDI], ~(X86_SEL_TYPE_SYS_TSS_BUSY_MASK << (X86DESCGENERIC_BIT_OFF_TYPE % 8)) +%if TMPL_BITS == 16 + pop ds +%endif + ltr dx + jmp .return + +.via_system_call: + mov ax, BS3_SYSCALL_SET_TR + call Bs3Syscall + +.return: + pop xDI + pop xAX + pop xDX + pop xBP + BS3_CALL_CONV_EPILOG 1 + BS3_HYBRID_RET +BS3_PROC_END_CMN Bs3RegSetTr + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-SelFar32ToFlat32.c b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-SelFar32ToFlat32.c new file mode 100644 index 00000000..6e642b3f --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-SelFar32ToFlat32.c @@ -0,0 +1,37 @@ +/* $Id: bs3-cmn-SelFar32ToFlat32.c $ */ +/** @file + * BS3Kit - Bs3SelFar32ToFlat32 + */ + +/* + * Copyright (C) 2007-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + +#include "bs3kit-template-header.h" + + +#undef Bs3SelFar32ToFlat32 +BS3_CMN_DEF(uint32_t, Bs3SelFar32ToFlat32,(uint32_t off, uint16_t uSel)) +{ + if (BS3_MODE_IS_RM_OR_V86(g_bBs3CurrentMode)) + return ((uint32_t)uSel << 4) + off; + return Bs3SelProtFar32ToFlat32(off, uSel); +} + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-SelFar32ToFlat32NoClobber.asm b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-SelFar32ToFlat32NoClobber.asm new file mode 100644 index 00000000..ff76d667 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-SelFar32ToFlat32NoClobber.asm @@ -0,0 +1,104 @@ +; $Id: bs3-cmn-SelFar32ToFlat32NoClobber.asm $ +;; @file +; BS3Kit - Bs3SelFar32ToFlat32NoClobber. +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + + +;********************************************************************************************************************************* +;* Header Files * +;********************************************************************************************************************************* +%include "bs3kit-template-header.mac" + + +;********************************************************************************************************************************* +;* External Symbols * +;********************************************************************************************************************************* +BS3_EXTERN_CMN Bs3SelFar32ToFlat32 +TMPL_BEGIN_TEXT + + +;; +; Wrapper around the Bs3SelFar32ToFlat32 C function that doesn't +; clobber any registers nor require 20h stack scratch area (64-bit). +; +; @uses Only return registers (ax:dx, eax, eax) +; @remarks No 20h scratch space required in 64-bit mode. +; +BS3_PROC_BEGIN_CMN Bs3SelFar32ToFlat32NoClobber, BS3_PBC_NEAR ; Far stub generated by the makefile. + push xBP + mov xBP, xSP + +%if TMPL_BITS == 16 + push bx + push cx + push es + + push word [xBP + xCB + cbCurRetAddr + 4] ; uSel + push word [xBP + xCB + cbCurRetAddr + 2] ; high off + push word [xBP + xCB + cbCurRetAddr] ; low off + call Bs3SelFar32ToFlat32 + add sp, 6 + + pop es + pop cx + pop bx +%else + push xDX + push xCX + %if TMPL_BITS == 32 + push es + push fs + push gs + + push dword [xBP + xCB + cbCurRetAddr + 4] ; uSel + push dword [xBP + xCB + cbCurRetAddr] ; off + call Bs3SelFar32ToFlat32 + add esp, 8 + + pop gs + pop fs + pop es + %else + push r8 + push r9 + push r10 + push r11 + sub rsp, 20h + + call Bs3SelFar32ToFlat32 ; Just pass ECX and DX along as-is. + + add rsp, 20h + pop r11 + pop r10 + pop r9 + pop r8 + %endif + pop xCX + pop xDX +%endif + + pop xBP + BS3_HYBRID_RET +BS3_PROC_END_CMN Bs3SelFar32ToFlat32NoClobber + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-SelFlatCodeToProtFar16.asm b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-SelFlatCodeToProtFar16.asm new file mode 100644 index 00000000..6b3a62fc --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-SelFlatCodeToProtFar16.asm @@ -0,0 +1,118 @@ +; $Id: bs3-cmn-SelFlatCodeToProtFar16.asm $ +;; @file +; BS3Kit - Bs3SelFlatCodeToProtFar16. +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + + +;********************************************************************************************************************************* +;* Header Files * +;********************************************************************************************************************************* +%include "bs3kit-template-header.mac" + + +;********************************************************************************************************************************* +;* External Symbols * +;********************************************************************************************************************************* +BS3_EXTERN_CMN Bs3SelFlatCodeToRealMode +BS3_EXTERN_CMN Bs3SelRealModeCodeToProtMode +TMPL_BEGIN_TEXT + + +;; +; @cproto BS3_CMN_PROTO(uint32_t, Bs3SelRealModeCodeToProtMode,(uint32_t uFlatAddr), false); +; +; @uses Only return registers (ax:dx, eax, eax) +; +BS3_PROC_BEGIN_CMN Bs3SelFlatCodeToProtFar16, BS3_PBC_NEAR + BS3_CALL_CONV_PROLOG 1 + push xBP + mov xBP, xSP + + ; + ; Call Bs3SelFlatCodeToRealMode and then Bs3SelRealModeCodeToProtMode. + ; This avoid some code duplication. + ; +%if TMPL_BITS == 16 + push word [xBP + xCB + cbCurRetAddr + 2] + push word [xBP + xCB + cbCurRetAddr] + call Bs3SelFlatCodeToRealMode + add sp, 4h + + push ax ; save the offset as it will be the same. + + push dx + call Bs3SelRealModeCodeToProtMode + add sp, 2h + + mov dx, ax ; The protected mode selector. + pop ax ; The offset. + +%elif TMPL_BITS == 32 + push dword [xBP + xCB + cbCurRetAddr] + call Bs3SelFlatCodeToRealMode + add esp, 4h + + push eax ; save the result. + + shr eax, 16 + push eax + call Bs3SelRealModeCodeToProtMode + add esp, 4h + + mov [esp + 2], ax ; Update the selector before popping the result. + pop eax + +%elif TMPL_BITS == 64 + push xCX ; Preserve RCX to make the behaviour uniform. + sub xSP, 28h ; 20h bytes of calling convention scratch and 8 byte for saving the result. + + mov ecx, [xBP + xCB + cbCurRetAddr] ; move straight to parameter 0 register. + call Bs3SelFlatCodeToRealMode + + mov [xBP - xCB*2], eax ; Save the result. + + shr eax, 16 + mov ecx, eax ; Move straight to parameter 0 register. + call Bs3SelRealModeCodeToProtMode + + shl eax, 16 ; Shift prot mode selector into result position. + mov ax, [xBP - xCB*2] ; The segment offset from the previous call. + + add xSP, 28h + pop xCX +%else + %error "TMPL_BITS=" TMPL_BITS "!" +%endif + pop xBP + BS3_CALL_CONV_EPILOG 1 + BS3_HYBRID_RET +BS3_PROC_END_CMN Bs3SelFlatCodeToProtFar16 + + +; +; We may be using the near code in some critical code paths, so don't +; penalize it. +; +BS3_CMN_FAR_STUB Bs3SelFlatCodeToProtFar16, 4 + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-SelFlatCodeToRealMode.asm b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-SelFlatCodeToRealMode.asm new file mode 100644 index 00000000..13cbcfdc --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-SelFlatCodeToRealMode.asm @@ -0,0 +1,153 @@ +; $Id: bs3-cmn-SelFlatCodeToRealMode.asm $ +;; @file +; BS3Kit - Bs3SelFlatCodeToRealMode. +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + + +;********************************************************************************************************************************* +;* Header Files * +;********************************************************************************************************************************* +%include "bs3kit-template-header.mac" + + +;********************************************************************************************************************************* +;* Global Variables * +;********************************************************************************************************************************* +BS3_EXTERN_DATA16 Bs3RmText16_EndOfSegment +BS3_EXTERN_DATA16 Bs3X0Text16_EndOfSegment +BS3_EXTERN_DATA16 Bs3X1Text16_EndOfSegment + + +; +; Make sure we can get at all the segments. +; +BS3_BEGIN_TEXT16 +BS3_BEGIN_RMTEXT16 +BS3_BEGIN_X0TEXT16 +BS3_BEGIN_X1TEXT16 +TMPL_BEGIN_TEXT + + +;; +; @cproto BS3_CMN_PROTO(uint32_t, Bs3SelRealModeCodeToProtMode,(uint32_t uFlatAddr), false); +; +; @uses Only return registers (ax:dx, eax, eax) +; +BS3_PROC_BEGIN_CMN Bs3SelFlatCodeToRealMode, BS3_PBC_NEAR + BS3_CALL_CONV_PROLOG 1 + push xBP + mov xBP, xSP + push xCX + push xBX +%if TMPL_BITS != 16 + push xDX +%endif + + ; + ; Load the real mode frame number into DX so we can compare with the + ; segment frame numbers fixed up by the linker. + ; + ; Imagine: FlatAddr = 0x054321 + ; + mov dx, [xBP + xCB + cbCurRetAddr + 1] ; dx = 0x0543 + mov al, [xBP + xCB + cbCurRetAddr + 0] ; al = 0x21 + mov cl,4 + shl dx, 4 ; dx = 0x5430 + shr al, 4 ; al = 0x02 + or dl, al ; dx = 0x5432 + + mov ax, dx + sub ax, CGROUP16 + cmp ax, 1000h + jb .bs3text16 + + mov ax, dx + sub ax, BS3GROUPRMTEXT16 + mov bx, Bs3RmText16_EndOfSegment wrt BS3GROUPRMTEXT16 + add bx, 15 + shr bx, cl + cmp ax, bx + jb .bs3rmtext16 + + mov ax, dx + sub ax, BS3GROUPX0TEXT16 + mov bx, Bs3X0Text16_EndOfSegment wrt BS3GROUPX0TEXT16 + add bx, 15 + shr bx, cl + cmp ax, bx + jb .bs3x0text16 + + mov ax, dx + sub ax, BS3GROUPX1TEXT16 + mov bx, Bs3X1Text16_EndOfSegment wrt BS3GROUPX1TEXT16 + add bx, 15 + shr bx, cl + cmp ax, bx + jb .bs3x1text16 + + extern BS3_CMN_NM(Bs3Panic) + call BS3_CMN_NM(Bs3Panic) + + ; + ; Load the real-mode frame into DX and calc the offset in AX. + ; +.bs3x1text16: + mov dx, BS3GROUPX1TEXT16 + jmp .calc_return +.bs3x0text16: + mov dx, BS3GROUPX0TEXT16 + jmp .calc_return +.bs3rmtext16: + mov dx, BS3GROUPRMTEXT16 + jmp .calc_return +.bs3text16: + mov dx, CGROUP16 +.calc_return: + ; Convert the real-mode frame into the low 16-bit base (BX). + mov bx, dx + shl bx, cl + ; Subtract the 16-bit base from the flat address. (No need to consider + ; the top half on either side.) + mov ax, [xBP + xCB + cbCurRetAddr + 0] + sub ax, bx +%if TMPL_BITS != 16 + ; Got a single 32-bit return register here. + shl edx, 16 + mov dx, ax + mov eax, edx + pop xDX +%endif + pop xBX + pop xCX + pop xBP + BS3_CALL_CONV_EPILOG 1 + BS3_HYBRID_RET +BS3_PROC_END_CMN Bs3SelFlatCodeToRealMode + +; +; We may be using the near code in some critical code paths, so don't +; penalize it. +; +BS3_CMN_FAR_STUB Bs3SelFlatCodeToRealMode, 4 + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-SelFlatDataToProtFar16.asm b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-SelFlatDataToProtFar16.asm new file mode 100644 index 00000000..f01194d5 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-SelFlatDataToProtFar16.asm @@ -0,0 +1,132 @@ +; $Id: bs3-cmn-SelFlatDataToProtFar16.asm $ +;; @file +; BS3Kit - Bs3SelFlatDataToProtFar16. +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + + +;********************************************************************************************************************************* +;* Header Files * +;********************************************************************************************************************************* +%include "bs3kit-template-header.mac" + + +;********************************************************************************************************************************* +;* External Symbols * +;********************************************************************************************************************************* +%ifdef BS3_STRICT +BS3_EXTERN_CMN Bs3Panic +%endif + +TMPL_BEGIN_TEXT +%if TMPL_BITS == 16 +CPU 8086 +%endif + + +;; +; @cproto BS3_CMN_PROTO_NOSB(uint32_t, Bs3SelFlatDataToProtFar16,(uint32_t uFlatAddr)); +; +; @uses Only return registers (ax:dx, eax, eax) +; @remarks No 20h scratch area requirements. +; +BS3_PROC_BEGIN_CMN Bs3SelFlatDataToProtFar16, BS3_PBC_NEAR ; Far stub generated by the makefile/bs3kit.h. + push xBP + mov xBP, xSP + + ; + ; Check if we can use the protected mode stack or data selector. + ; The latter ensures the usability of this function for setting SS. + ; +%if TMPL_BITS == 16 + mov ax, [xBP + xCB + cbCurRetAddr] + mov dx, [xBP + xCB + cbCurRetAddr + 2] + test dx, dx + jnz .not_stack + mov dx, BS3_SEL_R0_SS16 +%else +TNOT64 mov eax, [xBP + xCB + cbCurRetAddr] +TONLY64 mov eax, ecx + test eax, 0ffff0000h + jnz .not_stack + or eax, BS3_SEL_R0_SS16 << 16 +%endif + jmp .return + +.not_stack: +%if TMPL_BITS == 16 + sub ax, BS3_ADDR_BS3DATA16 & 0xffff + sbb dx, BS3_ADDR_BS3DATA16 >> 16 + jnz .do_tiled + mov dx, BS3_SEL_R0_DS16 +%else + sub eax, BS3_ADDR_BS3DATA16 + test eax, 0ffff0000h + jnz .do_tiled + or eax, BS3_SEL_R0_DS16 << 16 +%endif + jmp .return + + ; + ; Just translate the address to tiled. + ; +.do_tiled: +%if TMPL_BITS == 16 + ; Convert upper 16-bit to a tiled selector. + mov ax, cx ; save cx + mov dx, [xBP + xCB + cbCurRetAddr + 2] + %ifdef BS3_STRICT + cmp dx, BS3_SEL_TILED_AREA_SIZE >> 16 + jb .address_ok + call Bs3Panic +.address_ok: + %endif + mov cl, X86_SEL_SHIFT + shl dx, cl + add dx, BS3_SEL_TILED + mov cx, ax ; restore cx + + ; Load segment offset and return. + mov ax, [xBP + xCB + cbCurRetAddr] + +%else + ; Convert upper 16-bit to tiled selector. +TNOT64 mov eax, [xBP + xCB + cbCurRetAddr] +TONLY64 mov rax, rcx + %ifdef BS3_STRICT + cmp xAX, BS3_SEL_TILED_AREA_SIZE + jb .address_ok + call Bs3Panic +.address_ok: + %endif + ror eax, 16 + shl ax, X86_SEL_SHIFT + add ax, BS3_SEL_TILED + rol eax, 16 +%endif + +.return: + pop xBP + BS3_HYBRID_RET +BS3_PROC_END_CMN Bs3SelFlatDataToProtFar16 + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-SelFlatDataToRealMode.asm b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-SelFlatDataToRealMode.asm new file mode 100644 index 00000000..c923a886 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-SelFlatDataToRealMode.asm @@ -0,0 +1,94 @@ +; $Id: bs3-cmn-SelFlatDataToRealMode.asm $ +;; @file +; BS3Kit - Bs3SelFlatDataToRealMode +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + + +;********************************************************************************************************************************* +;* Header Files * +;********************************************************************************************************************************* +%include "bs3kit-template-header.mac" + + +;********************************************************************************************************************************* +;* External Symbols * +;********************************************************************************************************************************* +%ifdef BS3_STRICT +BS3_EXTERN_CMN Bs3Panic +%endif +TMPL_BEGIN_TEXT +%if TMPL_BITS == 16 +CPU 8086 +%endif + + +;; +; @cproto BS3_CMN_PROTO_NOSB(uint32_t, Bs3SelFlatDataToRealMode,(uint32_t uFlatAddr)); +; +; @uses Only return registers (ax:dx, eax, eax) +; @remarks No 20h scratch area requirements. +; +BS3_PROC_BEGIN_CMN Bs3SelFlatDataToRealMode, BS3_PBC_NEAR ; Far stub generated by the makefile/bs3kit.h. + push xBP + mov xBP, xSP + + ; + ; Take the simplest approach possible (64KB tiled). + ; +%if TMPL_BITS == 16 + mov ax, cx ; save cx + mov dx, [xBP + xCB + cbCurRetAddr + 2] + %ifdef BS3_STRICT + cmp dx, _1M >> 16 + jb .address_ok + call Bs3Panic +.address_ok: + %endif + mov cl, 12 + shl dx, cl + mov ax, cx ; restore cx + + mov ax, [xBP + xCB + cbCurRetAddr] + +%else + %if TMPL_BITS == 32 + mov eax, [xBP + xCB + cbCurRetAddr] + %else + mov rax, rcx + %endif + %ifdef BS3_STRICT + cmp xAX, _1M + jb .address_ok + call Bs3Panic +.address_ok: + %endif + ror eax, 16 + shl ax, 12 + rol eax, 16 +%endif + + pop xBP + BS3_HYBRID_RET +BS3_PROC_END_CMN Bs3SelFlatDataToRealMode + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-SelProtFar16DataToFlat.asm b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-SelProtFar16DataToFlat.asm new file mode 100644 index 00000000..83404ada --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-SelProtFar16DataToFlat.asm @@ -0,0 +1,90 @@ +; $Id: bs3-cmn-SelProtFar16DataToFlat.asm $ +;; @file +; BS3Kit - Bs3SelProtFar16DataToFlat. +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + + +;********************************************************************************************************************************* +;* Header Files * +;********************************************************************************************************************************* +%include "bs3kit-template-header.mac" + + +;********************************************************************************************************************************* +;* External Symbols * +;********************************************************************************************************************************* +BS3_EXTERN_CMN Bs3SelFar32ToFlat32NoClobber +TMPL_BEGIN_TEXT +%if TMPL_BITS == 16 +CPU 8086 +%endif + + +;; +; @cproto BS3_CMN_PROTO_NOSB(uint32_t, Bs3SelProtFar16DataToFlat,(uint32_t uFar1616)); +; +; @uses Only return registers (ax:dx, eax, eax) +; @remarks No 20h scratch area requirements. +; +BS3_PROC_BEGIN_CMN Bs3SelProtFar16DataToFlat, BS3_PBC_NEAR ; Far stub generated by the makefile/bs3kit.h. + push xBP + mov xBP, xSP + + ; + ; Just call Bs3SelFar32ToFlat32NoClobber to do the job. + ; +%if TMPL_BITS == 16 + push word [xBP + xCB + cbCurRetAddr + 2] + xor ax, ax + push ax + push word [xBP + xCB + cbCurRetAddr] + call Bs3SelFar32ToFlat32NoClobber + add sp, 6 +%else + %if TMPL_BITS == 32 + movzx eax, word [xBP + xCB + cbCurRetAddr + 2] + push eax + movzx eax, word [xBP + xCB + cbCurRetAddr] + push eax + call Bs3SelFar32ToFlat32NoClobber + add esp, 8 + %else + push xDX + push xCX + + mov edx, ecx ; arg #2: selector + shr edx, 16 + movzx ecx, cx ; arg #1: offset + call Bs3SelFar32ToFlat32NoClobber + + pop xDX + pop xCX + %endif +%endif + +.return: + pop xBP + BS3_HYBRID_RET +BS3_PROC_END_CMN Bs3SelProtFar16DataToFlat + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-SelProtFar16DataToRealMode.asm b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-SelProtFar16DataToRealMode.asm new file mode 100644 index 00000000..84524d38 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-SelProtFar16DataToRealMode.asm @@ -0,0 +1,147 @@ +; $Id: bs3-cmn-SelProtFar16DataToRealMode.asm $ +;; @file +; BS3Kit - Bs3SelProtFar16DataToRealMode. +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + + +;********************************************************************************************************************************* +;* Header Files * +;********************************************************************************************************************************* +%include "bs3kit-template-header.mac" + + +;********************************************************************************************************************************* +;* External Symbols * +;********************************************************************************************************************************* +BS3_BEGIN_DATA16 ; For real mode segment value. +BS3_BEGIN_SYSTEM16 ; Ditto. +TMPL_BEGIN_TEXT +BS3_EXTERN_CMN Bs3SelFar32ToFlat32NoClobber + +TMPL_BEGIN_TEXT +%if TMPL_BITS == 16 +CPU 8086 +%endif + + +;; +; @cproto BS3_CMN_PROTO_NOSB(uint32_t, Bs3SelProtFar16DataToRealMode,(uint32_t uFar1616)); +; +; @uses Only return registers (ax:dx, eax, eax) +; @remarks No 20h scratch area requirements. +; +BS3_PROC_BEGIN_CMN Bs3SelProtFar16DataToRealMode, BS3_PBC_NEAR ; Far stub generated by the makefile/bs3kit.h. + push xBP + mov xBP, xSP + + ; + ; See if it's our default 16-bit ring-0 data, stack or system data segment. + ; +%if TMPL_BITS == 16 + mov ax, [xBP + xCB + cbCurRetAddr + 2] +%elif TMPL_BITS == 32 + movzx eax, word [xBP + xCB + cbCurRetAddr + 2] +%else + mov eax, ecx + shr eax, 16 +%endif + cmp ax, BS3_SEL_R0_SS16 + jne .not_stack + mov ax, 0 + +.quick_return: +%if TMPL_BITS == 16 + mov dx, ax + mov ax, [xBP + xCB + cbCurRetAddr] +%elif TMPL_BITS == 32 + shl eax, 16 + mov ax, word [xBP + xCB + cbCurRetAddr] +%else + shl eax, 16 + mov ax, cx +%endif + +.return: + pop xBP + BS3_HYBRID_RET + +.not_stack: + cmp ax, BS3_SEL_R0_DS16 + jne .not_dgroup + mov ax, BS3KIT_GRPNM_DATA16 + jmp .quick_return + +.not_dgroup: + cmp ax, BS3_SEL_SYSTEM16 + jne .not_system16 + mov ax, BS3SYSTEM16 + jmp .quick_return + + ; + ; Call worker function to convert it to flat and the do tiled + ; calculation from that. + ; +.not_system16: +%if TMPL_BITS == 16 + push word [xBP + xCB + cbCurRetAddr + 2] + xor ax, ax + push ax + push word [xBP + xCB + cbCurRetAddr] + call Bs3SelFar32ToFlat32NoClobber + add sp, 6 + + ; Convert upper 16-bit of the flat address to a tiled selector. + push cx + mov cl, X86_SEL_SHIFT + shl dx, cl + add dx, BS3_SEL_TILED + pop cx +%else + %if TMPL_BITS == 32 + push eax + movzx eax, word [xBP + xCB + cbCurRetAddr] + push eax + call Bs3SelFar32ToFlat32NoClobber + add esp, 8 + %else + push xDX + push xCX + + mov edx, eax ; arg #2: selector + movzx ecx, cx ; arg #1: offset + call Bs3SelFar32ToFlat32NoClobber + + pop xDX + pop xCX + %endif + + ; Convert upper 16-bit to tiled selector. + rol eax, 16 + shl ax, X86_SEL_SHIFT + add ax, BS3_SEL_TILED + ror eax, 16 +%endif + jmp .return +BS3_PROC_END_CMN Bs3SelProtFar16DataToRealMode + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-SelProtFar32ToFlat32.c b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-SelProtFar32ToFlat32.c new file mode 100644 index 00000000..0089d779 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-SelProtFar32ToFlat32.c @@ -0,0 +1,45 @@ +/* $Id: bs3-cmn-SelProtFar32ToFlat32.c $ */ +/** @file + * BS3Kit - Bs3SelProtFar32ToFlat32 + */ + +/* + * Copyright (C) 2007-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + +#include "bs3kit-template-header.h" + + +#undef Bs3SelProtFar32ToFlat32 +BS3_CMN_DEF(uint32_t, Bs3SelProtFar32ToFlat32,(uint32_t off, uint16_t uSel)) +{ + uint32_t uRet; + PCX86DESC pEntry; + if (!(uSel & X86_SEL_LDT)) + pEntry = &Bs3Gdt[uSel >> X86_SEL_SHIFT]; + else + pEntry = &Bs3Ldt[uSel >> X86_SEL_SHIFT]; + uRet = pEntry->Gen.u16BaseLow; + uRet |= (uint32_t)pEntry->Gen.u8BaseHigh1 << 16; + uRet |= (uint32_t)pEntry->Gen.u8BaseHigh2 << 24; + uRet += off; + return uRet; +} + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-SelProtModeCodeToRealMode.asm b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-SelProtModeCodeToRealMode.asm new file mode 100644 index 00000000..f07a1300 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-SelProtModeCodeToRealMode.asm @@ -0,0 +1,112 @@ +; $Id: bs3-cmn-SelProtModeCodeToRealMode.asm $ +;; @file +; BS3Kit - Bs3SelProtModeCodeToRealMode. +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + +%include "bs3kit-template-header.mac" + +; +; Make sure we can get at all the segments. +; +BS3_BEGIN_TEXT16 +BS3_BEGIN_RMTEXT16 +BS3_BEGIN_X0TEXT16 +BS3_BEGIN_X1TEXT16 +TMPL_BEGIN_TEXT + + +;; +; @cproto BS3_CMN_PROTO(uint16_t, Bs3SelProtModeCodeToRealMode,(uint16_t uRealSel), false); +; @uses ax (return register) +; +BS3_PROC_BEGIN_CMN Bs3SelProtModeCodeToRealMode, BS3_PBC_NEAR + BS3_CALL_CONV_PROLOG 1 + push xBP + mov xBP, xSP + + ; Load it and mask off the RPL. + mov ax, [xBP + xCB + cbCurRetAddr] + and ax, X86_SEL_MASK_OFF_RPL + + ; We're allowed to use the real-mode segment value. + cmp ax, CGROUP16 + je .bs3text16 + + ; Check for typical code segments. + cmp ax, BS3_SEL_R0_CS16 + je .bs3text16 + cmp ax, BS3_SEL_RMTEXT16_CS + je .bs3rmtext16 + cmp ax, BS3_SEL_X0TEXT16_CS + je .bs3x0text16 + cmp ax, BS3_SEL_X1TEXT16_CS + je .bs3x1text16 + + ; Check for less common BS3_SEL_R*_CS16_* values. + cmp ax, BS3_SEL_R0_FIRST + jb .panic + cmp ax, BS3_SEL_R3_FIRST + (1 << BS3_SEL_RING_SHIFT) + jae .panic + + ; Since the relevant bits now are the lower 8 ones, we skip the + ; AND AX, BS3_SEL_RING_SHIFT + ; ADD AX, BS3_SEL_R0_FIRST + ; bits and compare AL with lower 8-bit of the BS3_SEL_R0_CS16* values. +AssertCompile(BS3_SEL_RING_SHIFT == 8) + cmp al, BS3_SEL_R0_CS16 & 0xff + je .bs3text16 + cmp al, BS3_SEL_R0_CS16_EO & 0xff + je .bs3text16 + cmp ax, BS3_SEL_R0_CS16_CNF & 0xff + je .bs3text16 + cmp ax, BS3_SEL_R0_CS16_CNF_EO & 0xff + je .bs3text16 +.panic: + extern BS3_CMN_NM(Bs3Panic) + call BS3_CMN_NM(Bs3Panic) + jmp .return + +.bs3x1text16: + mov ax, BS3GROUPX1TEXT16 + jmp .return +.bs3x0text16: + mov ax, BS3GROUPX0TEXT16 + jmp .return +.bs3rmtext16: + mov ax, BS3GROUPRMTEXT16 + jmp .return +.bs3text16: + mov ax, CGROUP16 +.return: + pop xBP + BS3_CALL_CONV_EPILOG 1 + BS3_HYBRID_RET +BS3_PROC_END_CMN Bs3SelProtModeCodeToRealMode + +; +; We may be using the near code in some critical code paths, so don't +; penalize it. +; +BS3_CMN_FAR_STUB Bs3SelProtModeCodeToRealMode, 2 + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-SelRealModeCodeToProtMode.asm b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-SelRealModeCodeToProtMode.asm new file mode 100644 index 00000000..4ec3a31a --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-SelRealModeCodeToProtMode.asm @@ -0,0 +1,84 @@ +; $Id: bs3-cmn-SelRealModeCodeToProtMode.asm $ +;; @file +; BS3Kit - Bs3SelRealModeCodeToProtMode. +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + +%include "bs3kit-template-header.mac" + +; +; Make sure we can get at all the segments. +; +BS3_BEGIN_TEXT16 +BS3_BEGIN_RMTEXT16 +BS3_BEGIN_X0TEXT16 +BS3_BEGIN_X1TEXT16 +TMPL_BEGIN_TEXT + + +;; +; @cproto BS3_CMN_PROTO(uint16_t, Bs3SelRealModeCodeToProtMode,(uint16_t uRealSel), false); +; @uses ax (return register) +; +BS3_PROC_BEGIN_CMN Bs3SelRealModeCodeToProtMode, BS3_PBC_NEAR + BS3_CALL_CONV_PROLOG 1 + push xBP + mov xBP, xSP + + mov ax, [xBP + xCB + cbCurRetAddr] + cmp ax, CGROUP16 + je .bs3text16 + cmp ax, BS3GROUPRMTEXT16 + je .bs3rmtext16 + cmp ax, BS3GROUPX0TEXT16 + je .bs3x0text16 + cmp ax, BS3GROUPX1TEXT16 + je .bs3x1text16 + + extern BS3_CMN_NM(Bs3Panic) + call BS3_CMN_NM(Bs3Panic) + jmp .return + +.bs3x1text16: + mov ax, BS3_SEL_X1TEXT16_CS + jmp .return +.bs3x0text16: + mov ax, BS3_SEL_X0TEXT16_CS + jmp .return +.bs3rmtext16: + mov ax, BS3_SEL_RMTEXT16_CS + jmp .return +.bs3text16: + mov ax, BS3_SEL_R0_CS16 +.return: + pop xBP + BS3_CALL_CONV_EPILOG 1 + BS3_HYBRID_RET +BS3_PROC_END_CMN Bs3SelRealModeCodeToProtMode + +; +; We may be using the near code in some critical code paths, so don't +; penalize it. +; +BS3_CMN_FAR_STUB Bs3SelRealModeCodeToProtMode, 2 + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-SelRealModeDataToFlat.asm b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-SelRealModeDataToFlat.asm new file mode 100644 index 00000000..3b8b7391 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-SelRealModeDataToFlat.asm @@ -0,0 +1,91 @@ +; $Id: bs3-cmn-SelRealModeDataToFlat.asm $ +;; @file +; BS3Kit - Bs3SelRealModeDataToFlat. +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + + +;********************************************************************************************************************************* +;* Header Files * +;********************************************************************************************************************************* +%include "bs3kit-template-header.mac" + + +;********************************************************************************************************************************* +;* External Symbols * +;********************************************************************************************************************************* +TMPL_BEGIN_TEXT +%if TMPL_BITS == 16 +CPU 8086 +%endif + + +;; +; @cproto BS3_CMN_PROTO_NOSB(uint32_t, Bs3SelRealModeDataToFlat,(uint32_t uFar1616)); +; @cproto BS3_CMN_PROTO_NOSB(uint32_t, Bs3SelRealModeCodeToFlat,(uint32_t uFar1616)); +; +; @uses Only return registers (ax:dx, eax, eax); +; @remarks No 20h scratch area requirements. +; +BS3_PROC_BEGIN_CMN Bs3SelRealModeCodeToFlat, BS3_PBC_NEAR ; Far stub generated by the makefile/bs3kit.h. +BS3_PROC_BEGIN_CMN Bs3SelRealModeDataToFlat, BS3_PBC_NEAR ; Far stub generated by the makefile/bs3kit.h. + push xBP + mov xBP, xSP + + ; Calc flat address. +%if TMPL_BITS == 16 + push cx + mov dx, [xBP + xCB + cbCurRetAddr + 2] + mov ax, dx + mov cl, 12 + shr dx, cl + mov cl, 4 + shl ax, cl + add ax, [xBP + xCB + cbCurRetAddr] + adc dx, 0 + pop cx + +%elif TMPL_BITS == 32 + movzx eax, word [xBP + xCB + cbCurRetAddr + 2] + shl eax, 4 + add ax, [xBP + xCB + cbCurRetAddr] + jnc .return + add eax, 10000h + +%elif TMPL_BITS == 64 + mov eax, ecx + shr eax, 16 + shl eax, 4 + add ax, cx + jnc .return + add eax, 10000h + +%else + %error "TMPL_BITS!" +%endif + +.return: + pop xBP + BS3_HYBRID_RET +BS3_PROC_END_CMN Bs3SelRealModeDataToFlat + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-SelRealModeDataToProtFar16.asm b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-SelRealModeDataToProtFar16.asm new file mode 100644 index 00000000..33bb358a --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-SelRealModeDataToProtFar16.asm @@ -0,0 +1,141 @@ +; $Id: bs3-cmn-SelRealModeDataToProtFar16.asm $ +;; @file +; BS3Kit - Bs3SelRealModeDataToProtFar16. +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + + +;********************************************************************************************************************************* +;* Header Files * +;********************************************************************************************************************************* +%include "bs3kit-template-header.mac" + + +;********************************************************************************************************************************* +;* External Symbols * +;********************************************************************************************************************************* +BS3_BEGIN_DATA16 ; For real mode segment value. +BS3_BEGIN_SYSTEM16 ; Ditto. + +TMPL_BEGIN_TEXT +%if TMPL_BITS == 16 +CPU 8086 +%endif + + +;; +; @cproto BS3_CMN_PROTO_NOSB(uint32_t, Bs3SelRealModeDataToProtFar16,(uint32_t uFar1616)); +; +; @uses Only return registers (ax:dx, eax, eax) +; @remarks No 20h scratch area requirements. +; +BS3_PROC_BEGIN_CMN Bs3SelRealModeDataToProtFar16, BS3_PBC_NEAR ; Far stub generated by the makefile/bs3kit.h. + push xBP + mov xBP, xSP + + ; + ; See if it's our default 16-bit data, stack or system data segment. + ; +%if TMPL_BITS == 16 + mov ax, [xBP + xCB + cbCurRetAddr + 2] +%elif TMPL_BITS == 32 + movzx eax, word [xBP + xCB + cbCurRetAddr + 2] +%else + mov eax, ecx + shr eax, 16 +%endif + cmp ax, 0 + jnz .not_stack + mov ax, BS3_SEL_R0_SS16 + +.quick_return: +%if TMPL_BITS == 16 + mov dx, ax + mov ax, [xBP + xCB + cbCurRetAddr] +%elif TMPL_BITS == 32 + shl eax, 16 + mov ax, word [xBP + xCB + cbCurRetAddr] +%else + shl eax, 16 + mov ax, cx +%endif + +.return: + pop xBP + BS3_HYBRID_RET + +.not_stack: + cmp ax, BS3KIT_GRPNM_DATA16 + jne .not_dgroup + mov ax, BS3_SEL_R0_DS16 + jmp .quick_return + +.not_dgroup: + cmp ax, BS3SYSTEM16 + jne .not_system16 + mov ax, BS3_SEL_SYSTEM16 + jmp .quick_return + + ; + ; Compute flat address and translate it to tiled. + ; +.not_system16: +%if TMPL_BITS == 16 + push cx + + ; Calc flat address. + mov dx, ax + mov cl, 12 + shr dx, cl + mov cl, 4 + shl ax, cl + add ax, [xBP + xCB + cbCurRetAddr] + adc dx, 0 + + ; Convert upper 16-bit to tiled selector. + mov cl, X86_SEL_SHIFT + shl dx, cl + add dx, BS3_SEL_TILED + + pop cx +%else + ; Calc flat address. + shl eax, 4 + %if TMPL_BITS == 32 + add ax, [xBP + xCB + cbCurRetAddr] + %else + add ax, cx + %endif + jnc .no_carry + add eax, 10000h +.no_carry: + + ; Convert upper 16-bit to tiled selector. + rol eax, 16 + shl ax, X86_SEL_SHIFT + add ax, BS3_SEL_TILED + ror eax, 16 +%endif + jmp .return +BS3_PROC_END_CMN Bs3SelRealModeDataToProtFar16 + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-SelSetup16BitCode.c b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-SelSetup16BitCode.c new file mode 100644 index 00000000..20bed88e --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-SelSetup16BitCode.c @@ -0,0 +1,51 @@ +/* $Id: bs3-cmn-SelSetup16BitCode.c $ */ +/** @file + * BS3Kit - Bs3SelSetup16BitCode + */ + +/* + * Copyright (C) 2007-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include <bs3kit.h> + + +#undef Bs3SelSetup16BitCode +BS3_CMN_DEF(void, Bs3SelSetup16BitCode,(X86DESC BS3_FAR *pDesc, uint32_t uBaseAddr, uint8_t bDpl)) +{ + pDesc->Gen.u16LimitLow = UINT16_C(0xffff); + pDesc->Gen.u16BaseLow = (uint16_t)uBaseAddr; + pDesc->Gen.u8BaseHigh1 = (uint8_t)(uBaseAddr >> 16); + pDesc->Gen.u4Type = X86_SEL_TYPE_ER_ACC; + pDesc->Gen.u1DescType = 1; /* data/code */ + pDesc->Gen.u2Dpl = bDpl & 3; + pDesc->Gen.u1Present = 1; + pDesc->Gen.u4LimitHigh = 0; + pDesc->Gen.u1Available = 0; + pDesc->Gen.u1Long = 0; + pDesc->Gen.u1DefBig = 0; + pDesc->Gen.u1Granularity = 0; + pDesc->Gen.u8BaseHigh2 = (uint8_t)(uBaseAddr >> 24); +} + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-SelSetup16BitData.c b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-SelSetup16BitData.c new file mode 100644 index 00000000..2085945d --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-SelSetup16BitData.c @@ -0,0 +1,51 @@ +/* $Id: bs3-cmn-SelSetup16BitData.c $ */ +/** @file + * BS3Kit - Bs3SelSetup16BitData + */ + +/* + * Copyright (C) 2007-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include <bs3kit.h> + + +#undef Bs3SelSetup16BitData +BS3_CMN_DEF(void, Bs3SelSetup16BitData,(X86DESC BS3_FAR *pDesc, uint32_t uBaseAddr)) +{ + pDesc->Gen.u16LimitLow = UINT16_C(0xffff); + pDesc->Gen.u16BaseLow = (uint16_t)uBaseAddr; + pDesc->Gen.u8BaseHigh1 = (uint8_t)(uBaseAddr >> 16); + pDesc->Gen.u4Type = X86_SEL_TYPE_RW_ACC; + pDesc->Gen.u1DescType = 1; /* data/code */ + pDesc->Gen.u2Dpl = 3; + pDesc->Gen.u1Present = 1; + pDesc->Gen.u4LimitHigh = 0; + pDesc->Gen.u1Available = 0; + pDesc->Gen.u1Long = 0; + pDesc->Gen.u1DefBig = 0; + pDesc->Gen.u1Granularity = 0; + pDesc->Gen.u8BaseHigh2 = (uint8_t)(uBaseAddr >> 24); +} + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-Shutdown.asm b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-Shutdown.asm new file mode 100644 index 00000000..87c2cf08 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-Shutdown.asm @@ -0,0 +1,53 @@ +; $Id: bs3-cmn-Shutdown.asm $ +;; @file +; BS3Kit - Bs3Shutdown +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + +%include "bs3kit-template-header.mac" +%include "VBox/bios.mac" + +BS3_EXTERN_CMN Bs3Panic + +BS3_PROC_BEGIN_CMN Bs3Shutdown, BS3_PBC_HYBRID_0_ARGS + cli +%ifdef TMPL_16BIT + mov ax, cs + mov ds, ax +%endif + mov bl, 64 + mov dx, VBOX_BIOS_SHUTDOWN_PORT + mov ax, VBOX_BIOS_OLD_SHUTDOWN_PORT +.retry: + mov ecx, 8 + mov esi, .s_szShutdown + rep outsb + xchg ax, dx ; alternate between the new (VBox) and old (Bochs) ports. + dec bl + jnz .retry + ; Shutdown failed! + jmp Bs3Panic +.s_szShutdown: + db 'Shutdown', 0 +BS3_PROC_END_CMN Bs3Shutdown + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-SlabAlloc.c b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-SlabAlloc.c new file mode 100644 index 00000000..dc17e734 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-SlabAlloc.c @@ -0,0 +1,54 @@ +/* $Id: bs3-cmn-SlabAlloc.c $ */ +/** @file + * BS3Kit - Bs3SlabAlloc + */ + +/* + * Copyright (C) 2007-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include "bs3kit-template-header.h" +#include <iprt/asm.h> + + +#undef Bs3SlabAlloc +BS3_CMN_DEF(void BS3_FAR *, Bs3SlabAlloc,(PBS3SLABCTL pSlabCtl)) +{ + if (pSlabCtl->cFreeChunks) + { + int32_t iBit = ASMBitFirstClear(&pSlabCtl->bmAllocated, pSlabCtl->cChunks); + if (iBit >= 0) + { + BS3_XPTR_AUTO(void, pvRet); + ASMBitSet(&pSlabCtl->bmAllocated, iBit); + pSlabCtl->cFreeChunks -= 1; + + BS3_XPTR_SET_FLAT(void, pvRet, + BS3_XPTR_GET_FLAT(uint8_t, pSlabCtl->pbStart) + ((uint32_t)iBit << pSlabCtl->cChunkShift)); + return BS3_XPTR_GET(void, pvRet); + } + } + return NULL; +} + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-SlabAllocEx.c b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-SlabAllocEx.c new file mode 100644 index 00000000..e9af001b --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-SlabAllocEx.c @@ -0,0 +1,101 @@ +/* $Id: bs3-cmn-SlabAllocEx.c $ */ +/** @file + * BS3Kit - Bs3SlabAllocEx + */ + +/* + * Copyright (C) 2007-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include "bs3kit-template-header.h" +#include <iprt/asm.h> + + +#undef Bs3SlabAllocEx +BS3_CMN_DEF(void BS3_FAR *, Bs3SlabAllocEx,(PBS3SLABCTL pSlabCtl, uint16_t cChunks, uint16_t fFlags)) +{ + BS3_ASSERT(cChunks > 0); + if (pSlabCtl->cFreeChunks >= cChunks) + { + int32_t iBit = ASMBitFirstClear(&pSlabCtl->bmAllocated, pSlabCtl->cChunks); + if (iBit >= 0) + { + BS3_ASSERT(!ASMBitTest(&pSlabCtl->bmAllocated, iBit)); + + while ((uint32_t)iBit + cChunks <= pSlabCtl->cChunks) + { + /* Check that we've got the requested number of free chunks here. */ + uint16_t i; + for (i = 1; i < cChunks; i++) + if (ASMBitTest(&pSlabCtl->bmAllocated, iBit + i)) + break; + if (i == cChunks) + { + /* Check if the chunks are all in the same tiled segment. */ + BS3_XPTR_AUTO(void, pvRet); + BS3_XPTR_SET_FLAT(void, pvRet, + BS3_XPTR_GET_FLAT(uint8_t, pSlabCtl->pbStart) + ((uint32_t)iBit << pSlabCtl->cChunkShift)); + if ( !(fFlags & BS3_SLAB_ALLOC_F_SAME_TILE) + || (BS3_XPTR_GET_FLAT(void, pvRet) >> 16) + == ((BS3_XPTR_GET_FLAT(void, pvRet) + ((uint32_t)cChunks << pSlabCtl->cChunkShift) - 1) >> 16) ) + { + /* Complete the allocation. */ + void *fpRet; + for (i = 0; i < cChunks; i++) + ASMBitSet(&pSlabCtl->bmAllocated, iBit + i); + pSlabCtl->cFreeChunks -= cChunks; + fpRet = BS3_XPTR_GET(void, pvRet); +#if ARCH_BITS == 16 + BS3_ASSERT(fpRet != NULL); +#endif + return fpRet; + } + + /* + * We're crossing a tiled segment boundrary. + * Skip to the start of the next segment and retry there. + * (We already know that the first chunk in the next tiled + * segment is free, otherwise we wouldn't have a crossing.) + */ + BS3_ASSERT(((uint32_t)cChunks << pSlabCtl->cChunkShift) <= _64K); + i = BS3_XPTR_GET_FLAT_LOW(void, pvRet); + i = UINT16_C(0) - i; + i >>= pSlabCtl->cChunkShift; + iBit += i; + } + else + { + /* + * Continue searching. + */ + iBit = ASMBitNextClear(&pSlabCtl->bmAllocated, pSlabCtl->cChunks, iBit + i); + if (iBit < 0) + break; + } + } + } + } + return NULL; +} + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-SlabFree.c b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-SlabFree.c new file mode 100644 index 00000000..c17f1659 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-SlabFree.c @@ -0,0 +1,59 @@ +/* $Id: bs3-cmn-SlabFree.c $ */ +/** @file + * BS3Kit - Bs3SlabFree + */ + +/* + * Copyright (C) 2007-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include "bs3kit-template-header.h" +#include <iprt/asm.h> + + +#undef Bs3SlabFree +BS3_CMN_DEF(uint16_t, Bs3SlabFree,(PBS3SLABCTL pSlabCtl, uint32_t uFlatChunkPtr, uint16_t cChunks)) +{ + uint16_t cFreed = 0; + BS3_ASSERT(cChunks > 0); + if (cChunks > 0) + { + uint16_t iChunk = (uint16_t)((uFlatChunkPtr - BS3_XPTR_GET_FLAT(uint8_t, pSlabCtl->pbStart)) >> pSlabCtl->cChunkShift); + BS3_ASSERT(iChunk < pSlabCtl->cChunks); + BS3_ASSERT(iChunk + cChunks <= pSlabCtl->cChunks); + + do + { + if (ASMBitTestAndClear(&pSlabCtl->bmAllocated, iChunk)) + cFreed++; + else + BS3_ASSERT(0); + iChunk++; + } while (--cChunks > 0); + + pSlabCtl->cFreeChunks += cFreed; + } + return cFreed; +} + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-SlabInit.c b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-SlabInit.c new file mode 100644 index 00000000..bf123dd1 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-SlabInit.c @@ -0,0 +1,62 @@ +/* $Id: bs3-cmn-SlabInit.c $ */ +/** @file + * BS3Kit - Bs3SlabInit + */ + +/* + * Copyright (C) 2007-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include "bs3kit-template-header.h" +#include <iprt/asm.h> + + +#undef Bs3SlabInit +BS3_CMN_DEF(void, Bs3SlabInit,(PBS3SLABCTL pSlabCtl, size_t cbSlabCtl, uint32_t uFlatSlabPtr, uint32_t cbSlab, uint16_t cbChunk)) +{ + uint16_t cBits; + BS3_ASSERT(RT_IS_POWER_OF_TWO(cbChunk)); + BS3_ASSERT(cbSlab >= cbChunk * 4); + BS3_ASSERT(!(uFlatSlabPtr & (cbChunk - 1))); + + BS3_XPTR_SET_FLAT(BS3SLABCTL, pSlabCtl->pNext, 0); + BS3_XPTR_SET_FLAT(BS3SLABCTL, pSlabCtl->pHead, 0); + BS3_XPTR_SET_FLAT(BS3SLABCTL, pSlabCtl->pbStart, uFlatSlabPtr); + pSlabCtl->cbChunk = cbChunk; + pSlabCtl->cChunkShift = ASMBitFirstSetU16(cbChunk) - 1; + pSlabCtl->cChunks = cbSlab >> pSlabCtl->cChunkShift; + pSlabCtl->cFreeChunks = pSlabCtl->cChunks; + cBits = RT_ALIGN_T(pSlabCtl->cChunks, 32, uint16_t); + BS3_ASSERT(cbSlabCtl >= RT_UOFFSETOF_DYN(BS3SLABCTL, bmAllocated[cBits >> 3])); + Bs3MemZero(&pSlabCtl->bmAllocated, cBits >> 3); + + /* Mark excess bitmap padding bits as allocated. */ + if (cBits != pSlabCtl->cChunks) + { + uint16_t iBit; + for (iBit = pSlabCtl->cChunks; iBit < cBits; iBit++) + ASMBitSet(pSlabCtl->bmAllocated, iBit); + } +} + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-SlabListAdd.c b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-SlabListAdd.c new file mode 100644 index 00000000..7018fd09 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-SlabListAdd.c @@ -0,0 +1,43 @@ +/* $Id: bs3-cmn-SlabListAdd.c $ */ +/** @file + * BS3Kit - Bs3SlabListAdd + */ + +/* + * Copyright (C) 2007-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + +#include "bs3kit-template-header.h" + + +#undef Bs3SlabListAdd +BS3_CMN_DEF(void, Bs3SlabListAdd,(PBS3SLABHEAD pHead, PBS3SLABCTL pSlabCtl)) +{ + BS3_ASSERT(pHead->cbChunk == pSlabCtl->cbChunk); + BS3_ASSERT(BS3_XPTR_IS_NULL(BS3SLABHEAD, pSlabCtl->pNext)); + + BS3_XPTR_SET_FLAT(BS3SLABCTL, pSlabCtl->pNext, BS3_XPTR_GET_FLAT(BS3SLABCTL, pHead->pFirst)); + BS3_XPTR_SET(BS3SLABCTL, pHead->pFirst, pSlabCtl); + + pHead->cSlabs += 1; + pHead->cChunks += pSlabCtl->cChunks; + pHead->cFreeChunks += pSlabCtl->cFreeChunks; +} + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-SlabListAlloc.c b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-SlabListAlloc.c new file mode 100644 index 00000000..b4bf0a0d --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-SlabListAlloc.c @@ -0,0 +1,57 @@ +/* $Id: bs3-cmn-SlabListAlloc.c $ */ +/** @file + * BS3Kit - Bs3SlabListAlloc + */ + +/* + * Copyright (C) 2007-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include "bs3kit-template-header.h" + + +#undef Bs3SlabListAlloc +BS3_CMN_DEF(void BS3_FAR *, Bs3SlabListAlloc,(PBS3SLABHEAD pHead)) +{ + if (pHead->cFreeChunks) + { + PBS3SLABCTL pCur; + for (pCur = BS3_XPTR_GET(BS3SLABCTL, pHead->pFirst); + pCur != NULL; + pCur = BS3_XPTR_GET(BS3SLABCTL, pCur->pNext)) + { + if (pCur->cFreeChunks) + { + void BS3_FAR *pvRet = Bs3SlabAlloc(pCur); + if (pvRet) + { + pHead->cFreeChunks -= 1; + return pvRet; + } + } + } + } + return NULL; +} + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-SlabListAllocEx.c b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-SlabListAllocEx.c new file mode 100644 index 00000000..ea86d8b1 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-SlabListAllocEx.c @@ -0,0 +1,58 @@ +/* $Id: bs3-cmn-SlabListAllocEx.c $ */ +/** @file + * BS3Kit - Bs3SlabListAllocEx + */ + +/* + * Copyright (C) 2007-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include "bs3kit-template-header.h" + + +#undef Bs3SlabListAllocEx +BS3_CMN_DEF(void BS3_FAR *, Bs3SlabListAllocEx,(PBS3SLABHEAD pHead, uint16_t cChunks, uint16_t fFlags)) +{ + BS3_ASSERT(!(fFlags & ~BS3_SLAB_ALLOC_F_SAME_TILE)); + if (pHead->cFreeChunks >= cChunks) + { + PBS3SLABCTL pCur; + for (pCur = BS3_XPTR_GET(BS3SLABCTL, pHead->pFirst); + pCur != NULL; + pCur = BS3_XPTR_GET(BS3SLABCTL, pCur->pNext)) + { + if (pCur->cFreeChunks >= cChunks) + { + void BS3_FAR *pvRet = Bs3SlabAllocEx(pCur, cChunks, fFlags); + if (pvRet) + { + pHead->cFreeChunks -= cChunks; + return pvRet; + } + } + } + } + return NULL; +} + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-SlabListFree.c b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-SlabListFree.c new file mode 100644 index 00000000..6f2d281e --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-SlabListFree.c @@ -0,0 +1,54 @@ +/* $Id: bs3-cmn-SlabListFree.c $ */ +/** @file + * BS3Kit - Bs3SlabListFree + */ + +/* + * Copyright (C) 2007-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + +#include "bs3kit-template-header.h" + + +#undef Bs3SlabListFree +BS3_CMN_DEF(void, Bs3SlabListFree,(PBS3SLABHEAD pHead, void BS3_FAR *pvChunks, uint16_t cChunks)) +{ + BS3_ASSERT(cChunks > 0); + if (cChunks > 0) + { + PBS3SLABCTL pCur; + BS3_XPTR_AUTO(void, pvFlatChunk); + BS3_XPTR_SET(void, pvFlatChunk, pvChunks); + + for (pCur = BS3_XPTR_GET(BS3SLABCTL, pHead->pFirst); + pCur != NULL; + pCur = BS3_XPTR_GET(BS3SLABCTL, pCur->pNext)) + { + if ( ((BS3_XPTR_GET_FLAT(void, pvFlatChunk) - BS3_XPTR_GET_FLAT(uint8_t, pCur->pbStart)) >> pCur->cChunkShift) + < pCur->cChunks) + { + pHead->cFreeChunks += Bs3SlabFree(pCur, BS3_XPTR_GET_FLAT(void, pvFlatChunk), cChunks); + return; + } + } + BS3_ASSERT(0); + } +} + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-SlabListInit.c b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-SlabListInit.c new file mode 100644 index 00000000..2256c64f --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-SlabListInit.c @@ -0,0 +1,40 @@ +/* $Id: bs3-cmn-SlabListInit.c $ */ +/** @file + * BS3Kit - Bs3SlabListInit + */ + +/* + * Copyright (C) 2007-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + +#include "bs3kit-template-header.h" + + +#undef Bs3SlabListInit +BS3_CMN_DEF(void, Bs3SlabListInit,(PBS3SLABHEAD pHead, uint16_t cbChunk)) +{ + BS3_ASSERT(RT_IS_POWER_OF_TWO(cbChunk)); + BS3_XPTR_SET(struct BS3SLABCTL, pHead->pFirst, 0); + pHead->cbChunk = cbChunk; + pHead->cSlabs = 0; + pHead->cChunks = 0; + pHead->cFreeChunks = 0; +} + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-StrCpy.c b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-StrCpy.c new file mode 100644 index 00000000..0302b616 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-StrCpy.c @@ -0,0 +1,41 @@ +/* $Id: bs3-cmn-StrCpy.c $ */ +/** @file + * BS3Kit - Bs3StrCpy + */ + +/* + * Copyright (C) 2007-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + +#include "bs3kit-template-header.h" + +#undef Bs3StrCpy +BS3_CMN_DEF(char BS3_FAR *, Bs3StrCpy,(char BS3_FAR *pszDst, const char BS3_FAR *pszSrc)) +{ + char BS3_FAR *pszRet = pszDst; + char ch; + do + { + ch = *pszSrc++; + *pszDst++ = ch; + } while (ch != '\0'); + return pszRet; +} + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-StrFormatV.c b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-StrFormatV.c new file mode 100644 index 00000000..17320873 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-StrFormatV.c @@ -0,0 +1,779 @@ +/* $Id: bs3-cmn-StrFormatV.c $ */ +/** @file + * BS3Kit - Bs3StrFormatV + */ + +/* + * Copyright (C) 2007-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include "bs3kit-template-header.h" +#include <iprt/ctype.h> + + +/********************************************************************************************************************************* +* Defined Constants And Macros * +*********************************************************************************************************************************/ +#define STR_F_CAPITAL 0x0001 +#define STR_F_LEFT 0x0002 +#define STR_F_ZEROPAD 0x0004 +#define STR_F_SPECIAL 0x0008 +#define STR_F_VALSIGNED 0x0010 +#define STR_F_PLUS 0x0020 +#define STR_F_BLANK 0x0040 +#define STR_F_WIDTH 0x0080 +#define STR_F_PRECISION 0x0100 +#define STR_F_THOUSAND_SEP 0x0200 +#define STR_F_NEGATIVE 0x0400 /**< Used to indicated '-' must be printed. */ + + +/********************************************************************************************************************************* +* Structures and Typedefs * +*********************************************************************************************************************************/ +/** Size of the temporary buffer. */ +#define BS3FMT_TMP_SIZE 64 + +/** + * BS3kit string format state. + */ +typedef struct BS3FMTSTATE +{ + /** The output function. */ + PFNBS3STRFORMATOUTPUT pfnOutput; + /** User argument for pfnOutput. */ + void BS3_FAR *pvUser; + + /** STR_F_XXX flags. */ + unsigned fFlags; + /** The width when STR_F_WIDTH is specific. */ + int cchWidth; + /** The width when STR_F_PRECISION is specific. */ + int cchPrecision; + /** The number format base. */ + unsigned uBase; + /** Temporary buffer. */ + char szTmp[BS3FMT_TMP_SIZE]; +} BS3FMTSTATE; +/** Pointer to a BS3Kit string formatter state. */ +typedef BS3FMTSTATE BS3_FAR *PBS3FMTSTATE; + + + +/********************************************************************************************************************************* +* Internal Functions * +*********************************************************************************************************************************/ +#if ARCH_BITS != 64 +static size_t bs3StrFormatU32(PBS3FMTSTATE pState, uint32_t uValue); +#endif + + + +/** + * Formats a number string. + * + * @returns Number of chars printed. + * @param pState The string formatter state. + * @param pszNumber The formatted number string. + * @param cchNumber The length of the number. + */ +static size_t bs3StrFormatNumberString(PBS3FMTSTATE pState, char const BS3_FAR *pszNumber, size_t cchNumber) +{ + /* + * Calc the length of the core number with prefixes. + */ + size_t cchActual = 0; + size_t cchRet = cchNumber; + + /* Accunt for sign char. */ + cchRet += !!(pState->fFlags & (STR_F_NEGATIVE | STR_F_PLUS | STR_F_BLANK)); + + /* Account for the hex prefix: '0x' or '0X' */ + if (pState->fFlags & STR_F_SPECIAL) + { + cchRet += 2; + BS3_ASSERT(pState->uBase == 16); + } + + /* Account for thousand separators (applied while printing). */ + if (pState->fFlags & STR_F_THOUSAND_SEP) + cchRet += (cchNumber - 1) / (pState->uBase == 10 ? 3 : 8); + + /* + * Do left blank padding. + */ + if ((pState->fFlags & (STR_F_ZEROPAD | STR_F_LEFT | STR_F_WIDTH)) == STR_F_WIDTH) + while (cchRet < pState->cchWidth) + { + cchActual += pState->pfnOutput(' ', pState->pvUser); + cchRet++; + } + + /* + * Sign indicator / space. + */ + if (pState->fFlags & (STR_F_NEGATIVE | STR_F_PLUS | STR_F_BLANK)) + { + char ch; + if (pState->fFlags & STR_F_NEGATIVE) + ch = '-'; + else if (pState->fFlags & STR_F_PLUS) + ch = '+'; + else + ch = ' '; + cchActual += pState->pfnOutput(ch, pState->pvUser); + } + + /* + * Hex prefix. + */ + if (pState->fFlags & STR_F_SPECIAL) + { + cchActual += pState->pfnOutput('0', pState->pvUser); + cchActual += pState->pfnOutput(!(pState->fFlags & STR_F_CAPITAL) ? 'x' : 'X', pState->pvUser); + } + + /* + * Zero padding. + */ + if (pState->fFlags & STR_F_ZEROPAD) + while (cchRet < pState->cchWidth) + { + cchActual += pState->pfnOutput('0', pState->pvUser); + cchRet++; + } + + /* + * Output the number. + */ + if ( !(pState->fFlags & STR_F_THOUSAND_SEP) + || cchNumber < 4) + while (cchNumber-- > 0) + cchActual += pState->pfnOutput(*pszNumber++, pState->pvUser); + else + { + char const chSep = pState->uBase == 10 ? ' ' : '\''; + unsigned const cchEvery = pState->uBase == 10 ? 3 : 8; + unsigned cchLeft = --cchNumber % cchEvery; + + cchActual += pState->pfnOutput(*pszNumber++, pState->pvUser); + while (cchNumber-- > 0) + { + if (cchLeft == 0) + { + cchActual += pState->pfnOutput(chSep, pState->pvUser); + cchLeft = cchEvery; + } + cchLeft--; + cchActual += pState->pfnOutput(*pszNumber++, pState->pvUser); + } + } + + /* + * Do right blank padding. + */ + if ((pState->fFlags & (STR_F_ZEROPAD | STR_F_LEFT | STR_F_WIDTH)) == (STR_F_WIDTH | STR_F_LEFT)) + while (cchRet < pState->cchWidth) + { + cchActual += pState->pfnOutput(' ', pState->pvUser); + cchRet++; + } + + return cchActual; +} + + +/** + * Format a 64-bit number. + * + * @returns Number of characters. + * @param pState The string formatter state. + * @param uValue The value. + */ +static size_t bs3StrFormatU64(PBS3FMTSTATE pState, uint64_t uValue) +{ +#if ARCH_BITS != 64 + /* Avoid 64-bit division by formatting 64-bit numbers as hex if they're higher than _4G. */ + if (pState->uBase == 10) + { + if (!(uValue >> 32)) /* uValue <= UINT32_MAX does not work, trouble with 64-bit compile time math! */ + return bs3StrFormatU32(pState, uValue); + pState->fFlags |= STR_F_SPECIAL; + pState->uBase = 16; + } +#endif + + { + const char BS3_FAR *pachDigits = !(pState->fFlags & STR_F_CAPITAL) ? g_achBs3HexDigits : g_achBs3HexDigitsUpper; + char BS3_FAR *psz = &pState->szTmp[BS3FMT_TMP_SIZE]; + + *--psz = '\0'; +#if ARCH_BITS == 64 + if (pState->uBase == 10) + { + do + { + *--psz = pachDigits[uValue % 10]; + uValue /= 10; + } while (uValue > 0); + } + else +#endif + { + BS3_ASSERT(pState->uBase == 16); + do + { + *--psz = pachDigits[uValue & 0xf]; + uValue >>= 4; + } while (uValue > 0); + } + return bs3StrFormatNumberString(pState, psz, &pState->szTmp[BS3FMT_TMP_SIZE - 1] - psz); + } +} + + +/** + * Format a 32-bit number. + * + * @returns Number of characters. + * @param pState The string formatter state. + * @param uValue The value. + */ +static size_t bs3StrFormatU32(PBS3FMTSTATE pState, uint32_t uValue) +{ +#if ARCH_BITS < 64 + const char BS3_FAR *pachDigits = !(pState->fFlags & STR_F_CAPITAL) ? g_achBs3HexDigits : g_achBs3HexDigitsUpper; + char BS3_FAR *psz = &pState->szTmp[BS3FMT_TMP_SIZE]; + + *--psz = '\0'; + if (pState->uBase == 10) + { + do + { + *--psz = pachDigits[uValue % 10]; + uValue /= 10; + } while (uValue > 0); + } + else + { + BS3_ASSERT(pState->uBase == 16); + do + { + *--psz = pachDigits[uValue & 0xf]; + uValue >>= 4; + } while (uValue > 0); + } + return bs3StrFormatNumberString(pState, psz, &pState->szTmp[BS3FMT_TMP_SIZE - 1] - psz); + +#else + /* We've got native 64-bit division, save space. */ + return bs3StrFormatU64(pState, uValue); +#endif +} + + +#if ARCH_BITS == 16 +/** + * Format a 16-bit number. + * + * @returns Number of characters. + * @param pState The string formatter state. + * @param uValue The value. + */ +static size_t bs3StrFormatU16(PBS3FMTSTATE pState, uint16_t uValue) +{ + if (pState->uBase == 10) + { + const char BS3_FAR *pachDigits = !(pState->fFlags & STR_F_CAPITAL) + ? g_achBs3HexDigits : g_achBs3HexDigitsUpper; + char BS3_FAR *psz = &pState->szTmp[BS3FMT_TMP_SIZE]; + + *--psz = '\0'; + do + { + *--psz = pachDigits[uValue % 10]; + uValue /= 10; + } while (uValue > 0); + return bs3StrFormatNumberString(pState, psz, &pState->szTmp[BS3FMT_TMP_SIZE - 1] - psz); + } + + /* + * 32-bit shifting is reasonably cheap and inlined, so combine with 32-bit. + */ + return bs3StrFormatU32(pState, uValue); +} +#endif + + +static size_t bs3StrFormatS64(PBS3FMTSTATE pState, int32_t iValue) +{ + if (iValue < 0) + { + iValue = -iValue; + pState->fFlags |= STR_F_NEGATIVE; + } + return bs3StrFormatU64(pState, iValue); +} + + +static size_t bs3StrFormatS32(PBS3FMTSTATE pState, int32_t iValue) +{ + if (iValue < 0) + { + iValue = -iValue; + pState->fFlags |= STR_F_NEGATIVE; + } + return bs3StrFormatU32(pState, iValue); +} + + +#if ARCH_BITS == 16 +static size_t bs3StrFormatS16(PBS3FMTSTATE pState, int16_t iValue) +{ + if (iValue < 0) + { + iValue = -iValue; + pState->fFlags |= STR_F_NEGATIVE; + } + return bs3StrFormatU16(pState, iValue); +} +#endif + + +#undef Bs3StrFormatV +BS3_CMN_DEF(size_t, Bs3StrFormatV,(const char BS3_FAR *pszFormat, va_list BS3_FAR va, + PFNBS3STRFORMATOUTPUT pfnOutput, void BS3_FAR *pvUser)) +{ + BS3FMTSTATE State; + size_t cchRet = 0; + char ch; +#if ARCH_BITS == 16 + typedef int SIZE_CHECK_TYPE1[sizeof(va) == 4 && sizeof(va[0]) == 4]; +#endif + + State.pfnOutput = pfnOutput; + State.pvUser = pvUser; + + while ((ch = *pszFormat++) != '\0') + { + char chArgSize; + + /* + * Deal with plain chars. + */ + if (ch != '%') + { + cchRet += State.pfnOutput(ch, State.pvUser); + continue; + } + + ch = *pszFormat++; + if (ch == '%') + { + cchRet += State.pfnOutput(ch, State.pvUser); + continue; + } + + /* + * Flags. + */ + State.fFlags = 0; + for (;;) + { + unsigned int fThis; + switch (ch) + { + default: fThis = 0; break; + case '#': fThis = STR_F_SPECIAL; break; + case '-': fThis = STR_F_LEFT; break; + case '+': fThis = STR_F_PLUS; break; + case ' ': fThis = STR_F_BLANK; break; + case '0': fThis = STR_F_ZEROPAD; break; + case '\'': fThis = STR_F_THOUSAND_SEP; break; + } + if (!fThis) + break; + State.fFlags |= fThis; + ch = *pszFormat++; + } + + /* + * Width. + */ + State.cchWidth = 0; + if (RT_C_IS_DIGIT(ch)) + { + do + { + State.cchWidth *= 10; + State.cchWidth += ch - '0'; + ch = *pszFormat++; + } while (RT_C_IS_DIGIT(ch)); + State.fFlags |= STR_F_WIDTH; + } + else if (ch == '*') + { + State.cchWidth = va_arg(va, int); + if (State.cchWidth < 0) + { + State.cchWidth = -State.cchWidth; + State.fFlags |= STR_F_LEFT; + } + State.fFlags |= STR_F_WIDTH; + ch = *pszFormat++; + } + + /* + * Precision + */ + State.cchPrecision = 0; + if (ch == '.') + { + ch = *pszFormat++; + if (RT_C_IS_DIGIT(ch)) + { + do + { + State.cchPrecision *= 10; + State.cchPrecision += ch - '0'; + ch = *pszFormat++; + } while (RT_C_IS_DIGIT(ch)); + State.fFlags |= STR_F_PRECISION; + } + else if (ch == '*') + { + State.cchPrecision = va_arg(va, int); + if (State.cchPrecision < 0) + State.cchPrecision = 0; + State.fFlags |= STR_F_PRECISION; + ch = *pszFormat++; + } + } + + /* + * Argument size. + */ + chArgSize = ch; + switch (ch) + { + default: + chArgSize = 0; + break; + + case 'z': + case 'L': + case 'j': + case 't': + ch = *pszFormat++; + break; + + case 'l': + ch = *pszFormat++; + if (ch == 'l') + { + chArgSize = 'L'; + ch = *pszFormat++; + } + break; + + case 'h': + ch = *pszFormat++; + if (ch == 'h') + { + chArgSize = 'H'; + ch = *pszFormat++; + } + break; + } + + /* + * The type. + */ + switch (ch) + { + /* + * Char + */ + case 'c': + { + char ch = va_arg(va, int /*char*/); + cchRet += State.pfnOutput(ch, State.pvUser); + break; + } + + /* + * String. + */ + case 's': + { + const char BS3_FAR *psz = va_arg(va, const char BS3_FAR *); + size_t cch; + if (psz != NULL) + cch = Bs3StrNLen(psz, State.fFlags & STR_F_PRECISION ? RT_ABS(State.cchPrecision) : ~(size_t)0); + else + { + psz = "<NULL>"; + cch = 6; + } + + if ((State.fFlags & (STR_F_LEFT | STR_F_WIDTH)) == STR_F_WIDTH) + while (--State.cchWidth >= cch) + cchRet += State.pfnOutput(' ', State.pvUser); + + cchRet += cch; + while (cch-- > 0) + cchRet += State.pfnOutput(*psz++, State.pvUser); + + if ((State.fFlags & (STR_F_LEFT | STR_F_WIDTH)) == (STR_F_LEFT | STR_F_WIDTH)) + while (--State.cchWidth >= cch) + cchRet += State.pfnOutput(' ', State.pvUser); + break; + } + + /* + * Signed integers. + */ + case 'i': + case 'd': + State.fFlags &= ~STR_F_SPECIAL; + State.fFlags |= STR_F_VALSIGNED; + State.uBase = 10; + switch (chArgSize) + { + case 0: + case 'h': /* signed short should be promoted to int or be the same as int */ + case 'H': /* signed char should be promoted to int. */ + { + signed int iValue = va_arg(va, signed int); +#if ARCH_BITS == 16 + cchRet += bs3StrFormatS16(&State, iValue); +#else + cchRet += bs3StrFormatS32(&State, iValue); +#endif + break; + } + case 'l': + { + signed long lValue = va_arg(va, signed long); + if (sizeof(lValue) == 4) + cchRet += bs3StrFormatS32(&State, lValue); + else + cchRet += bs3StrFormatS64(&State, lValue); + break; + } + case 'L': + { + unsigned long long ullValue = va_arg(va, unsigned long long); + cchRet += bs3StrFormatS64(&State, ullValue); + break; + } + } + break; + + /* + * Unsigned integers. + */ + case 'X': + State.fFlags |= STR_F_CAPITAL; + case 'x': + case 'u': + { + if (ch == 'u') + { + State.uBase = 10; + State.fFlags &= ~(STR_F_PLUS | STR_F_BLANK | STR_F_SPECIAL); + } + else + { + State.uBase = 16; + State.fFlags &= ~(STR_F_PLUS | STR_F_BLANK); + } + switch (chArgSize) + { + case 0: + case 'h': /* unsigned short should be promoted to int or be the same as int */ + case 'H': /* unsigned char should be promoted to int. */ + { + unsigned int uValue = va_arg(va, unsigned int); +#if ARCH_BITS == 16 + cchRet += bs3StrFormatU16(&State, uValue); +#else + cchRet += bs3StrFormatU32(&State, uValue); +#endif + break; + } + case 'l': + { + unsigned long ulValue = va_arg(va, unsigned long); + if (sizeof(ulValue) == 4) + cchRet += bs3StrFormatU32(&State, ulValue); + else + cchRet += bs3StrFormatU64(&State, ulValue); + break; + } + case 'L': + { + unsigned long long ullValue = va_arg(va, unsigned long long); + cchRet += bs3StrFormatU64(&State, ullValue); + break; + } + } + break; + } + + /* + * Our stuff. + */ + case 'R': + { + ch = *pszFormat++; + switch (ch) + { + case 'I': + State.fFlags |= STR_F_VALSIGNED; + State.uBase &= ~STR_F_SPECIAL; + State.uBase = 10; + break; + case 'U': + State.fFlags &= ~(STR_F_PLUS | STR_F_BLANK | STR_F_SPECIAL); + State.uBase = 10; + break; + case 'X': + State.fFlags &= ~(STR_F_PLUS | STR_F_BLANK); + State.uBase = 16; + break; + case 'h': + ch = *pszFormat++; + if (ch == 'x') + { + /* Hex dumping. */ + uint8_t const BS3_FAR *pbHex = va_arg(va, uint8_t const BS3_FAR *); + if (State.cchPrecision < 0) + State.cchPrecision = 16; + ch = *pszFormat++; + if (ch == 's' || ch == 'd') + { + /* %Rhxd is currently implemented as %Rhxs. */ + while (State.cchPrecision-- > 0) + { + uint8_t b = *pbHex++; + State.pfnOutput(g_achBs3HexDigits[b >> 4], State.pvUser); + State.pfnOutput(g_achBs3HexDigits[b & 0x0f], State.pvUser); + if (State.cchPrecision) + State.pfnOutput(' ', State.pvUser); + } + } + } + State.uBase = 0; + break; + default: + State.uBase = 0; + break; + } + if (State.uBase) + { + ch = *pszFormat++; + switch (ch) + { +#if ARCH_BITS != 16 + case '3': + case '1': /* Will an unsigned 16-bit value always be promoted + to a 16-bit unsigned int. It certainly will be promoted to a 32-bit int. */ + pszFormat++; /* Assumes (1)'6' or (3)'2' */ +#else + case '1': + pszFormat++; /* Assumes (1)'6' */ +#endif + case '8': /* An unsigned 8-bit value should be promoted to int, which is at least 16-bit. */ + { + unsigned int uValue = va_arg(va, unsigned int); +#if ARCH_BITS == 16 + cchRet += bs3StrFormatU16(&State, uValue); +#else + cchRet += bs3StrFormatU32(&State, uValue); +#endif + break; + } +#if ARCH_BITS == 16 + case '3': + { + uint32_t uValue = va_arg(va, uint32_t); + pszFormat++; + cchRet += bs3StrFormatU32(&State, uValue); + break; + } +#endif + case '6': + { + uint64_t uValue = va_arg(va, uint64_t); + pszFormat++; + cchRet += bs3StrFormatU64(&State, uValue); + break; + } + } + } + break; + } + + /* + * Pointers. + */ + case 'P': + State.fFlags |= STR_F_CAPITAL; + RT_FALL_THRU(); + case 'p': + { + void BS3_FAR *pv = va_arg(va, void BS3_FAR *); + State.uBase = 16; + State.fFlags &= ~(STR_F_PLUS | STR_F_BLANK); +#if ARCH_BITS == 16 + State.fFlags |= STR_F_ZEROPAD; + State.cchWidth = State.fFlags & STR_F_SPECIAL ? 6: 4; + cchRet += bs3StrFormatU16(&State, BS3_FP_SEG(pv)); + cchRet += State.pfnOutput(':', State.pvUser); + cchRet += bs3StrFormatU16(&State, BS3_FP_OFF(pv)); +#elif ARCH_BITS == 32 + State.fFlags |= STR_F_SPECIAL | STR_F_ZEROPAD; + State.cchWidth = 10; + cchRet += bs3StrFormatU32(&State, (uintptr_t)pv); +#elif ARCH_BITS == 64 + State.fFlags |= STR_F_SPECIAL | STR_F_ZEROPAD | STR_F_THOUSAND_SEP; + State.cchWidth = 19; + cchRet += bs3StrFormatU64(&State, (uintptr_t)pv); +#else +# error "Undefined or invalid ARCH_BITS." +#endif + break; + } + + } + } + + /* + * Termination call. + */ + cchRet += State.pfnOutput(0, State.pvUser); + + return cchRet; +} + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-StrLen.c b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-StrLen.c new file mode 100644 index 00000000..77f3eda8 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-StrLen.c @@ -0,0 +1,37 @@ +/* $Id: bs3-cmn-StrLen.c $ */ +/** @file + * BS3Kit - Bs3StrLen + */ + +/* + * Copyright (C) 2007-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + +#include "bs3kit-template-header.h" + +#undef Bs3StrLen +BS3_CMN_DEF(size_t, Bs3StrLen,(const char BS3_FAR *pszString)) +{ + size_t cch = 0; + while (pszString[cch] != '\0') + cch++; + return cch; +} + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-StrNLen.c b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-StrNLen.c new file mode 100644 index 00000000..8eb728f8 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-StrNLen.c @@ -0,0 +1,37 @@ +/* $Id: bs3-cmn-StrNLen.c $ */ +/** @file + * BS3Kit - Bs3StrNLen + */ + +/* + * Copyright (C) 2007-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + +#include "bs3kit-template-header.h" + +#undef Bs3StrNLen +BS3_CMN_DEF(size_t, Bs3StrNLen,(const char BS3_FAR *pszString, size_t cchMax)) +{ + size_t cch = 0; + while (cchMax-- > 0 && pszString[cch] != '\0') + cch++; + return cch; +} + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-StrPrintf.c b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-StrPrintf.c new file mode 100644 index 00000000..fb4fc7ef --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-StrPrintf.c @@ -0,0 +1,95 @@ +/* $Id: bs3-cmn-StrPrintf.c $ */ +/** @file + * BS3Kit - Bs3StrPrintf, Bs3StrPrintfV + */ + +/* + * Copyright (C) 2007-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include "bs3kit-template-header.h" +#include <iprt/ctype.h> + + +/********************************************************************************************************************************* +* Structures and Typedefs * +*********************************************************************************************************************************/ +typedef struct BS3STRPRINTFSTATE +{ + /** Current buffer position. */ + char *pchBuf; + /** Number of bytes left in the buffer. */ + size_t cchLeft; +} BS3STRPRINTFSTATE; +typedef BS3STRPRINTFSTATE BS3_FAR *PBS3STRPRINTFSTATE; + + + +static BS3_DECL_CALLBACK(size_t) bs3StrPrintfFmtOutput(char ch, void BS3_FAR *pvUser) +{ + PBS3STRPRINTFSTATE pState = (PBS3STRPRINTFSTATE)pvUser; + if (ch) + { + /* Put to the buffer if there is place for this char and a terminator. */ + if (pState->cchLeft > 1) + { + pState->cchLeft--; + *pState->pchBuf++ = ch; + } + + /* Always return 1. */ + return 1; + } + + /* Terminate the string. */ + if (pState->cchLeft) + { + pState->cchLeft--; + *pState->pchBuf++ = '\0'; + } + return 0; +} + + +#undef Bs3StrPrintfV +BS3_CMN_DEF(size_t, Bs3StrPrintfV,(char BS3_FAR *pszBuf, size_t cchBuf, const char BS3_FAR *pszFormat, va_list BS3_FAR va)) +{ + BS3STRPRINTFSTATE State; + State.pchBuf = pszBuf; + State.cchLeft = cchBuf; + return Bs3StrFormatV(pszFormat, va, bs3StrPrintfFmtOutput, &State); +} + + +#undef Bs3StrPrintf +BS3_CMN_DEF(size_t, Bs3StrPrintf,(char BS3_FAR *pszBuf, size_t cchBuf, const char BS3_FAR *pszFormat, ...)) +{ + size_t cchRet; + va_list va; + va_start(va, pszFormat); + cchRet = BS3_CMN_NM(Bs3StrPrintfV)(pszBuf, cchBuf, pszFormat, va); + va_end(va); + return cchRet; +} + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-SwitchHlpConvFlatRetToRetfProtMode.asm b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-SwitchHlpConvFlatRetToRetfProtMode.asm new file mode 100644 index 00000000..ed88bc3b --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-SwitchHlpConvFlatRetToRetfProtMode.asm @@ -0,0 +1,68 @@ +; $Id: bs3-cmn-SwitchHlpConvFlatRetToRetfProtMode.asm $ +;; @file +; BS3Kit - SwitchHlpConvFlatRetToRetfProtMode +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + +%include "bs3kit-template-header.mac" + +%if TMPL_BITS != 16 +BS3_EXTERN_CMN Bs3SelFlatCodeToProtFar16 + +;; +; SwitchToXxx helper that converts a 32-bit or 64-bit flat return address +; into a 16-bit protected mode far return. +; +; +; The caller calls this routine before switching modes. The flat return +; to be converted is immediately after our own return address on the stack. +; +; @uses Nothing. +; @remarks No 16-bit version. +; +BS3_PROC_BEGIN_CMN Bs3SwitchHlpConvFlatRetToRetfProtMode, BS3_PBC_NEAR + %if TMPL_BITS == 64 + push xAX + push xCX + sub xSP, 20h + + mov xCX, [xSP + xCB*3 + 20h] + call Bs3SelFlatCodeToProtFar16 ; well behaved assembly function, only clobbers ecx + mov [xSP + xCB*3 + 20h + 4], eax + + add xSP, 20h + pop xCX + pop xAX + ret 4 + %else + xchg eax, [xSP + xCB] + push xAX + call Bs3SelFlatCodeToProtFar16 ; well behaved assembly function, only clobbers eax + add xSP, 4 + xchg [xSP + xCB], eax + ret + %endif +BS3_PROC_END_CMN Bs3SwitchHlpConvFlatRetToRetfProtMode + +%endif ; 32 || 64 + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-SwitchHlpConvProtModeRetfPopBpDecBpAndReturn.asm b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-SwitchHlpConvProtModeRetfPopBpDecBpAndReturn.asm new file mode 100644 index 00000000..4edcba20 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-SwitchHlpConvProtModeRetfPopBpDecBpAndReturn.asm @@ -0,0 +1,116 @@ +; $Id: bs3-cmn-SwitchHlpConvProtModeRetfPopBpDecBpAndReturn.asm $ +;; @file +; BS3Kit - Bs3SwitchToPP32 +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + +%include "bs3kit-template-header.mac" + + +%if TMPL_BITS == 16 +BS3_EXTERN_CMN Bs3SelProtModeCodeToRealMode +%else +BS3_EXTERN_CMN Bs3SelFar32ToFlat32 +%endif + + +;; +; SwitchToXxx helper that converts a 16-bit protected mode far return +; into something suitable for the current mode and performs the return. +; +; The caller jmps to this routine. The stack holds an incremented BP (odd is +; far indicator) and a 16-bit far return address. +; +; @uses Nothing. +; @remarks 16-bit ASSUMES we're returning to protected mode!! +; +%if TMPL_BITS == 16 +BS3_BEGIN_TEXT16_FARSTUBS +%endif +BS3_PROC_BEGIN_CMN Bs3SwitchHlpConvProtModeRetfPopBpDecBpAndReturn, BS3_PBC_NEAR +%if TMPL_BITS == 16 + ; Convert the selector of the 16:16 protected mode return address to the + ; corresponding 16-bit real mode segment. + push ax + + mov ax, [bp + 2 + 2] + push ax + call Bs3SelProtModeCodeToRealMode ; This doesn't trash any registers (except AX). + add sp, 2 + mov [bp + 2 + 2], ax + + pop ax + + pop bp + dec bp + retf + +%elif TMPL_BITS == 32 + push eax + push ecx + push edx + + movzx eax, word [esp + 4*3 + 2] ; return offset + movzx edx, word [esp + 4*3 + 2 + 2] ; return selector + push eax + push edx + call Bs3SelFar32ToFlat32 + add esp, 8 + mov [esp + 4*3 + 2], eax + + pop edx + pop ecx + pop eax + pop bp + dec bp + ret +%else + push rax + push rcx + push rdx + push r8 + push r9 + push r10 + push r11 + + movzx ecx, word [rsp + 8*7 + 2] ; return offset + movzx edx, word [rsp + 8*7 + 2 + 2] ; return selector + sub rsp, 20h + call Bs3SelFar32ToFlat32 + add rsp, 20h + mov [rsp + 8*7 + 2], eax + + pop r11 + pop r10 + pop r9 + pop r8 + pop rdx + pop rcx + pop rax + mov bp, [rsp] + add rsp, 2h + dec bp + o32 ret +%endif +BS3_PROC_END_CMN Bs3SwitchHlpConvProtModeRetfPopBpDecBpAndReturn + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-SwitchHlpConvRealModeRetfPopBpDecBpAndReturn.asm b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-SwitchHlpConvRealModeRetfPopBpDecBpAndReturn.asm new file mode 100644 index 00000000..77b010b5 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-SwitchHlpConvRealModeRetfPopBpDecBpAndReturn.asm @@ -0,0 +1,99 @@ +; $Id: bs3-cmn-SwitchHlpConvRealModeRetfPopBpDecBpAndReturn.asm $ +;; @file +; BS3Kit - SwitchHlpConvRealModeRetfPopBpDecBpAndReturn +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + +%include "bs3kit-template-header.mac" + +BS3_EXTERN_CMN Bs3SelFar32ToFlat32 + +;; +; SwitchToXxx helper that converts a 16-bit real mode far return +; into something suitable for the current mode and performs the return. +; +; The caller jmps to this routine. The stack holds an incremented BP (odd is +; far indicator) and a 16-bit far return address. +; +; @uses Nothing. +; @remarks 16-bit ASSUMES we're returning to protected mode!! +; +%if TMPL_BITS == 16 +BS3_BEGIN_TEXT16_FARSTUBS +%endif +BS3_PROC_BEGIN_CMN Bs3SwitchHlpConvRealModeRetfPopBpDecBpAndReturn, BS3_PBC_NEAR +%if TMPL_BITS == 16 + ; Convert the selector of the 16:16 real mode return address to the + ; corresponding 16-bit protected mode selector. + push ax + + mov ax, [bp + 2 + 2] + push ax + BS3_EXTERN_CMN Bs3SelRealModeCodeToProtMode + call Bs3SelRealModeCodeToProtMode ; This doesn't trash any registers (except AX). + add sp, 2 + mov [bp + 2 + 2], ax + + pop ax + + pop bp + dec bp + retf + +%elif TMPL_BITS == 32 + push xAX + push xDX + + movzx eax, word [xSP + xCB*2 + 2 + 2] ; return segment + movzx edx, word [xSP + xCB*2 + 2] ; return offset + shl eax, 4 + add eax, edx + mov [xSP + xCB*2 + 2], eax + + pop xDX + pop xAX + pop bp + dec bp + ret +%else + sub rsp, 2h + + push xAX + push xDX + + movzx eax, word [xSP + xCB*2 + 4 + 2] ; return segment + movzx edx, word [xSP + xCB*2 + 4] ; return offset + shl eax, 4 + add eax, edx + + mov bp, [xSP + xCB*2 + 2] + dec bp + + mov [xSP + xCB*2], rax + + pop xDX + pop xAX + ret +%endif +BS3_PROC_END_CMN Bs3SwitchHlpConvRealModeRetfPopBpDecBpAndReturn + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-SwitchTo16Bit.asm b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-SwitchTo16Bit.asm new file mode 100644 index 00000000..28c17268 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-SwitchTo16Bit.asm @@ -0,0 +1,120 @@ +; $Id: bs3-cmn-SwitchTo16Bit.asm $ +;; @file +; BS3Kit - Bs3SwitchTo16Bit +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + +%include "bs3kit-template-header.mac" + +BS3_EXTERN_DATA16 g_bBs3CurrentMode +%if TMPL_BITS == 16 +BS3_EXTERN_CMN Bs3Syscall +%endif +TMPL_BEGIN_TEXT + + +;; +; @cproto BS3_DECL(void) Bs3SwitchTo16Bit(void); +; @remarks Does not require 20h of parameter scratch space in 64-bit mode. +; +BS3_PROC_BEGIN_CMN Bs3SwitchTo16Bit, BS3_PBC_NEAR +%if TMPL_BITS == 16 + push ax + push ds + + ; Check g_bBs3CurrentMode whether we're in v8086 mode or not. + mov al, [BS3_DATA16_WRT(g_bBs3CurrentMode)] + test al, BS3_MODE_CODE_V86 + jz .ret_16bit + + ; Switch to ring-0 if v8086 mode. + mov ax, BS3_SYSCALL_TO_RING0 + call Bs3Syscall + +.ret_16bit: + pop ds + pop ax + ret + +%else + push xAX + push xBX + xPUSHF + cli + + ; Calc new CS. + mov ax, cs + and xAX, 3 + shl xAX, BS3_SEL_RING_SHIFT ; ring addend. + add xAX, BS3_SEL_R0_CS16 + + ; Construct a far return for switching to 16-bit code. + push xAX + push .sixteen_bit + xRETF + +BS3_BEGIN_TEXT16 +BS3_GLOBAL_LOCAL_LABEL .sixteen_bit + + ; Load 16-bit segment registers. + add ax, BS3_SEL_R0_SS16 - BS3_SEL_R0_CS16 + mov ss, ax + + add ax, BS3_SEL_R0_DS16 - BS3_SEL_R0_SS16 + mov ds, ax + mov es, ax + + ; Thunk the stack if necessary. + mov ebx, esp + shr ebx, 16 + jz .stack_ok +int3 ; This is for later, just remove this int3 once needed. + test ax, X86_SEL_RPL + jnz .stack_rpl_must_be_0_for_custom_stacks + shl bx, X86_SEL_SHIFT + add bx, BS3_SEL_TILED + mov ss, bx + movzx esp, sp +.stack_ok: + + ; Update globals. + and byte [BS3_DATA16_WRT(g_bBs3CurrentMode)], ~BS3_MODE_CODE_MASK + or byte [BS3_DATA16_WRT(g_bBs3CurrentMode)], BS3_MODE_CODE_16 + + popfd +TONLY64 pop ebx + pop ebx +TONLY64 pop eax + pop eax +TONLY64 add sp, 4 + ret (TMPL_BITS - 16) / 8 ; Return and pop 2 or 6 bytes of "parameters" (unused return value) + +.stack_rpl_must_be_0_for_custom_stacks: + int3 + jmp .stack_rpl_must_be_0_for_custom_stacks +TMPL_BEGIN_TEXT +%endif +BS3_PROC_END_CMN Bs3SwitchTo16Bit + +;; @todo far 16-bit variant. + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-SwitchTo16BitV86.asm b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-SwitchTo16BitV86.asm new file mode 100644 index 00000000..67adc037 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-SwitchTo16BitV86.asm @@ -0,0 +1,123 @@ +; $Id: bs3-cmn-SwitchTo16BitV86.asm $ +;; @file +; BS3Kit - Bs3SwitchTo16BitV86 +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + +%include "bs3kit-template-header.mac" + +%if TMPL_BITS != 64 + +BS3_EXTERN_DATA16 g_bBs3CurrentMode +BS3_EXTERN_CMN Bs3SwitchToRing0 +BS3_EXTERN_CMN Bs3SelProtFar32ToFlat32 +TMPL_BEGIN_TEXT + + +;; +; @cproto BS3_DECL(void) Bs3SwitchTo16BitV86(void); +; @uses No general registers modified. Regment registers loaded with specific +; values and the stack register converted to real mode (not ebp). +; +BS3_PROC_BEGIN_CMN Bs3SwitchTo16BitV86, BS3_PBC_NEAR + ; Construct basic v8086 return frame. +BONLY16 movzx esp, sp + push dword 0 ; +0x20: GS + push dword 0 ; +0x1c: FS + push dword BS3_SEL_DATA16 ; +0x18: ES + push dword BS3_SEL_DATA16 ; +0x14: DS + push dword 0 ; +0x10: SS - later + push dword 0 ; +0x0c: return ESP, later. + pushfd + or dword [esp], X86_EFL_VM | X86_EFL_IOPL ; +0x08: Set IOPL=3 and the VM flag (EFLAGS). + push dword BS3_SEL_TEXT16 ; +0x04 + push word 0 + push word [esp + 24h - 2] ; +0x00 + ; Save registers and stuff. + push eax + push edx + push ecx + push ebx + %if TMPL_BITS == 16 + push ds + + ; Check g_bBs3CurrentMode whether we're in v8086 mode or not. + mov ax, seg g_bBs3CurrentMode + mov ds, ax + mov al, [BS3_DATA16_WRT(g_bBs3CurrentMode)] + test al, BS3_MODE_CODE_V86 + jz .not_v8086 + + pop ds + pop ebx + pop ecx + pop edx + pop eax + add xSP, 0x24 + ret + +.not_v8086: + pop ax ; Drop the push ds so the stacks are identical. Keep DS = BS3KIT_GRPNM_DATA16 though. + %endif + + ; Ensure that we're in ring-0. + mov ax, ss + test ax, 3 + jz .is_ring0 + call Bs3SwitchToRing0 + %if TMPL_BITS == 16 + mov ax, seg g_bBs3CurrentMode + mov ds, ax ; parnoia + %endif +.is_ring0: + + ; Update globals. + and byte [BS3_DATA16_WRT(g_bBs3CurrentMode)], ~BS3_MODE_CODE_MASK + or byte [BS3_DATA16_WRT(g_bBs3CurrentMode)], BS3_MODE_CODE_V86 + + ; Thunk return SS:ESP to real-mode address via 32-bit flat. + lea eax, [esp + 4*4 + 24h + xCB] + push ss + push eax + BS3_CALL Bs3SelProtFar32ToFlat32, 2 + add esp, sCB + xCB + mov [esp + 4*4 + 0ch], ax ; high word is already zero + %if TMPL_BITS == 16 + mov [esp + 4*4 + 10h], dx + %else + shr eax, 16 + mov [esp + 4*4 + 10h], ax + %endif + + ; Return to v8086 mode. + pop ebx + pop ecx + pop edx + pop eax + iretd +BS3_PROC_END_CMN Bs3SwitchTo16BitV86 + +;; @todo far 16-bit variant. + +%endif ; ! 64-bit + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-SwitchTo32Bit.asm b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-SwitchTo32Bit.asm new file mode 100644 index 00000000..cec1b0da --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-SwitchTo32Bit.asm @@ -0,0 +1,152 @@ +; $Id: bs3-cmn-SwitchTo32Bit.asm $ +;; @file +; BS3Kit - Bs3SwitchTo32Bit +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + +%include "bs3kit-template-header.mac" + + +%if TMPL_BITS == 16 +BS3_EXTERN_CMN Bs3SelProtFar32ToFlat32 +BS3_EXTERN_CMN Bs3Syscall +%endif +%if TMPL_BITS != 32 +BS3_EXTERN_DATA16 g_bBs3CurrentMode +TMPL_BEGIN_TEXT +%endif + + +;; +; @cproto BS3_DECL(void) Bs3SwitchTo32Bit(void); +; +; @remarks Does not require 20h of parameter scratch space in 64-bit mode. +; +BS3_PROC_BEGIN_CMN Bs3SwitchTo32Bit, BS3_PBC_NEAR +%if TMPL_BITS == 32 + ret +%else + %if TMPL_BITS == 16 + push ax ; Reserve space for larger return value (adjusted in 32-bit code). + push eax + pushfd + push edx + %else + pushfq + mov [rsp + 4], eax + %endif + cli + + %if TMPL_BITS == 16 + ; Check for v8086 mode, we need to exit it to enter 32-bit mode. + mov ax, seg g_bBs3CurrentMode + mov ds, ax + mov al, [BS3_DATA16_WRT(g_bBs3CurrentMode)] + test al, BS3_MODE_CODE_V86 + jz .not_v8086 + + ; Calc flat stack into edx. + mov dx, ss + movzx edx, dx + shl edx, 4 + add dx, sp + adc edx, 0 ; edx = flat stack address corresponding to ss:sp + + ; Switch to 16-bit ring0 and go on to do the far jump to 32-bit code. + mov ax, BS3_SYSCALL_TO_RING0 + call Bs3Syscall + + mov xAX, BS3_SEL_R0_CS32 + jmp .do_far_jump + %endif + +.not_v8086: + %if TMPL_BITS == 16 + ; Calc flat stack into edx. + movzx eax, sp + push ecx + push ebx + push ss + push eax + call Bs3SelProtFar32ToFlat32 + add sp, 6 + shl edx, 16 + mov dx, ax ; edx = flat stack address corresponding to ss:sp + pop ebx + pop ecx + %endif + + ; Calc ring addend. + mov ax, cs + and xAX, 3 + shl xAX, BS3_SEL_RING_SHIFT + add xAX, BS3_SEL_R0_CS32 + + ; Create far return for switching to 32-bit mode. +.do_far_jump: + push sAX + %if TMPL_BITS == 16 + push dword .thirty_two_bit wrt FLAT + o32 retf + %else + push .thirty_two_bit + o64 retf + %endif + +BS3_SET_BITS 32 +.thirty_two_bit: + ; Load 32-bit segment registers. + add eax, BS3_SEL_R0_SS32 - BS3_SEL_R0_CS32 + mov ss, ax + %if TMPL_BITS == 16 + mov esp, edx ; Load flat stack address. + %endif + + add eax, BS3_SEL_R0_DS32 - BS3_SEL_R0_SS32 + mov ds, ax + mov es, ax + + ; Update globals. + and byte [BS3_DATA16_WRT(g_bBs3CurrentMode)], ~BS3_MODE_CODE_MASK + or byte [BS3_DATA16_WRT(g_bBs3CurrentMode)], BS3_MODE_CODE_32 + + %if TMPL_BITS == 16 + ; Adjust the return address. + movzx eax, word [esp + 4*3 + 2] + add eax, BS3_ADDR_BS3TEXT16 + mov [esp + 4*3], eax + %endif + + ; Restore and return. + %if TMPL_BITS == 16 + pop edx + %endif + popfd + pop eax +TONLY64 ret 4 +TNOT64 ret +%endif +BS3_PROC_END_CMN Bs3SwitchTo32Bit + +;; @todo far 16-bit variant. + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-SwitchTo64Bit.asm b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-SwitchTo64Bit.asm new file mode 100644 index 00000000..1192c46d --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-SwitchTo64Bit.asm @@ -0,0 +1,110 @@ +; $Id: bs3-cmn-SwitchTo64Bit.asm $ +;; @file +; BS3Kit - Bs3SwitchTo64Bit +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + +%include "bs3kit-template-header.mac" + +%if TMPL_BITS != 64 +BS3_EXTERN_DATA16 g_bBs3CurrentMode +TMPL_BEGIN_TEXT +%endif + + +;; +; @cproto BS3_DECL(void) Bs3SwitchTo64Bit(void); +; +; @remarks Does not require 20h of parameter scratch space in 64-bit mode. +; @uses No GPRs. +; +BS3_PROC_BEGIN_CMN Bs3SwitchTo64Bit, BS3_PBC_NEAR +%if TMPL_BITS == 64 + ret + +%else + %if TMPL_BITS == 16 + sub sp, 6 ; Space for extended return value (corrected in 64-bit mode). + %else + push xPRE [xSP] ; Duplicate the return address. + and dword [xSP + xCB], 0 ; Clear the high dword or it. + %endif + push dword 0 + push sAX + push dword 0 + pushfd + cli + + %if TMPL_BITS == 16 + ; Check that this is LM16 + mov ax, seg g_bBs3CurrentMode + cmp byte [BS3_DATA16_WRT(g_bBs3CurrentMode)], BS3_MODE_LM16 + je .ok_lm16 + int3 + .ok_lm16: + %endif + + ; Calc ring addend. + mov ax, cs + and xAX, 3 + shl xAX, BS3_SEL_RING_SHIFT + add xAX, BS3_SEL_R0_CS64 + + ; setup far return. + push sAX + %if TMPL_BITS == 16 + push dword .sixty_four_bit wrt FLAT + o32 retf + %else + push .sixty_four_bit + retf + %endif + +BS3_SET_BITS 64 +.sixty_four_bit: + + ; Load 64-bit segment registers (SS64==DS64). + add eax, BS3_SEL_R0_DS64 - BS3_SEL_R0_CS64 + mov ss, ax + mov ds, ax + mov es, ax + + ; Update globals. + and byte [BS3_DATA16_WRT(g_bBs3CurrentMode)], ~BS3_MODE_CODE_MASK + or byte [BS3_DATA16_WRT(g_bBs3CurrentMode)], BS3_MODE_CODE_64 + + %if TMPL_BITS == 16 + movzx eax, word [rsp + 8*2+6] + add eax, BS3_ADDR_BS3TEXT16 + mov [rsp + 8*2], rax + %endif + + popfq + pop rax + ret +%endif +BS3_PROC_END_CMN Bs3SwitchTo64Bit + + +;; @todo far 16-bit variant. + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-SwitchToRing0.asm b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-SwitchToRing0.asm new file mode 100644 index 00000000..d83e451e --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-SwitchToRing0.asm @@ -0,0 +1,63 @@ +; $Id: bs3-cmn-SwitchToRing0.asm $ +;; @file +; BS3Kit - Bs3SwitchToRing0 +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + +;********************************************************************************************************************************* +;* Header Files * +;********************************************************************************************************************************* +%include "bs3kit-template-header.mac" + + +;********************************************************************************************************************************* +;* External Symbols * +;********************************************************************************************************************************* +BS3_EXTERN_CMN_FAR Bs3SwitchToRingX +TMPL_BEGIN_TEXT + + +;; +; @cproto BS3_DECL(void) Bs3SwitchToRing0(void); +; +; @remarks Does not require 20h of parameter scratch space in 64-bit mode. +; @uses No GPRs. +; +BS3_PROC_BEGIN_CMN Bs3SwitchToRing0, BS3_PBC_HYBRID_0_ARGS +%if TMPL_BITS == 64 + push rcx + sub rsp, 20h + mov ecx, 0 + mov [rsp], rcx + call Bs3SwitchToRingX + add rsp, 20h + pop rcx +%else + push 0 +TONLY16 push cs + call Bs3SwitchToRingX + add xSP, xCB +%endif + BS3_HYBRID_RET +BS3_PROC_END_CMN Bs3SwitchToRing0 + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-SwitchToRing1.asm b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-SwitchToRing1.asm new file mode 100644 index 00000000..e8867ef1 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-SwitchToRing1.asm @@ -0,0 +1,63 @@ +; $Id: bs3-cmn-SwitchToRing1.asm $ +;; @file +; BS3Kit - Bs3SwitchToRing1 +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + +;********************************************************************************************************************************* +;* Header Files * +;********************************************************************************************************************************* +%include "bs3kit-template-header.mac" + + +;********************************************************************************************************************************* +;* External Symbols * +;********************************************************************************************************************************* +BS3_EXTERN_CMN_FAR Bs3SwitchToRingX +TMPL_BEGIN_TEXT + + +;; +; @cproto BS3_DECL(void) Bs3SwitchToRing1(void); +; +; @remarks Does not require 20h of parameter scratch space in 64-bit mode. +; @uses No GPRs. +; +BS3_PROC_BEGIN_CMN Bs3SwitchToRing1, BS3_PBC_HYBRID_0_ARGS +%if TMPL_BITS == 64 + push rcx + sub rsp, 20h + mov ecx, 1 + mov [rsp], rcx + call Bs3SwitchToRingX + add rsp, 20h + pop rcx +%else + push 1 +TONLY16 push cs + call Bs3SwitchToRingX + add xSP, xCB +%endif + BS3_HYBRID_RET +BS3_PROC_END_CMN Bs3SwitchToRing1 + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-SwitchToRing2.asm b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-SwitchToRing2.asm new file mode 100644 index 00000000..0d3460c6 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-SwitchToRing2.asm @@ -0,0 +1,63 @@ +; $Id: bs3-cmn-SwitchToRing2.asm $ +;; @file +; BS3Kit - Bs3SwitchToRing2 +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + +;********************************************************************************************************************************* +;* Header Files * +;********************************************************************************************************************************* +%include "bs3kit-template-header.mac" + + +;********************************************************************************************************************************* +;* External Symbols * +;********************************************************************************************************************************* +BS3_EXTERN_CMN_FAR Bs3SwitchToRingX +TMPL_BEGIN_TEXT + + +;; +; @cproto BS3_DECL(void) Bs3SwitchToRing2(void); +; +; @remarks Does not require 20h of parameter scratch space in 64-bit mode. +; @uses No GPRs. +; +BS3_PROC_BEGIN_CMN Bs3SwitchToRing2, BS3_PBC_HYBRID_0_ARGS +%if TMPL_BITS == 64 + push rcx + sub rsp, 20h + mov ecx, 2 + mov [rsp], rcx + call Bs3SwitchToRingX + add rsp, 20h + pop rcx +%else + push 2 +TONLY16 push cs + call Bs3SwitchToRingX + add xSP, xCB +%endif + BS3_HYBRID_RET +BS3_PROC_END_CMN Bs3SwitchToRing2 + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-SwitchToRing3.asm b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-SwitchToRing3.asm new file mode 100644 index 00000000..5ffc5438 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-SwitchToRing3.asm @@ -0,0 +1,63 @@ +; $Id: bs3-cmn-SwitchToRing3.asm $ +;; @file +; BS3Kit - Bs3SwitchToRing3 +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + +;********************************************************************************************************************************* +;* Header Files * +;********************************************************************************************************************************* +%include "bs3kit-template-header.mac" + + +;********************************************************************************************************************************* +;* External Symbols * +;********************************************************************************************************************************* +BS3_EXTERN_CMN_FAR Bs3SwitchToRingX +TMPL_BEGIN_TEXT + + +;; +; @cproto BS3_DECL(void) Bs3SwitchToRing3(void); +; +; @remarks Does not require 20h of parameter scratch space in 64-bit mode. +; @uses No GPRs. +; +BS3_PROC_BEGIN_CMN Bs3SwitchToRing3, BS3_PBC_HYBRID_0_ARGS +%if TMPL_BITS == 64 + push rcx + sub rsp, 20h + mov ecx, 3 + mov [rsp], rcx + call Bs3SwitchToRingX + add rsp, 20h + pop rcx +%else + push 3 +TONLY16 push cs + call Bs3SwitchToRingX + add xSP, xCB +%endif + BS3_HYBRID_RET +BS3_PROC_END_CMN Bs3SwitchToRing3 + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-SwitchToRingX.asm b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-SwitchToRingX.asm new file mode 100644 index 00000000..84caf01e --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-SwitchToRingX.asm @@ -0,0 +1,93 @@ +; $Id: bs3-cmn-SwitchToRingX.asm $ +;; @file +; BS3Kit - Bs3SwitchToRingX +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + +%include "bs3kit-template-header.mac" + + +BS3_EXTERN_CMN Bs3Syscall +%if TMPL_BITS == 16 +BS3_EXTERN_DATA16 g_bBs3CurrentMode +%endif +TMPL_BEGIN_TEXT + + +;; +; @cproto BS3_DECL(void) Bs3SwitchToRingX(uint8_t bRing); +; +; @param bRing The target ring (0..3). +; @remarks Does not require 20h of parameter scratch space in 64-bit mode. +; +; @uses No GPRs. +; +BS3_PROC_BEGIN_CMN Bs3SwitchToRingX, BS3_PBC_HYBRID_SAFE + BS3_CALL_CONV_PROLOG 1 + push xBP + mov xBP, xSP + push xAX + +%if TMPL_BITS == 16 + ; Check the current mode. + mov al, [BS3_DATA16_WRT(g_bBs3CurrentMode)] + + ; If real mode: Nothing we can do, but we'll bitch if the request isn't for ring-0. + cmp al, BS3_MODE_RM + je .return_real_mode + + ; If V8086 mode: Always do syscall and add a lock prefix to make sure it gets to the VMM. + test al, BS3_MODE_CODE_V86 + jnz .just_do_it +%endif + + ; In protected mode: Check the CPL we're currently at skip syscall if ring-0 already. + mov ax, cs + and al, 3 + cmp al, byte [xBP + xCB + cbCurRetAddr] + je .return + +.just_do_it: + mov xAX, BS3_SYSCALL_TO_RING0 + add al, [xBP + xCB + cbCurRetAddr] + call Bs3Syscall + +%ifndef BS3_STRICT +.return_real_mode: +%endif +.return: + pop xAX + pop xBP + BS3_CALL_CONV_EPILOG 1 + BS3_HYBRID_RET + +%ifdef BS3_STRICT +; In real mode, only ring-0 makes any sense. +.return_real_mode: + cmp byte [xBP + xCB + cbCurRetAddr], 0 + je .return + int3 + jmp .return +%endif +BS3_PROC_END_CMN Bs3SwitchToRingX + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-Syscall.asm b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-Syscall.asm new file mode 100644 index 00000000..e4facb9b --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-Syscall.asm @@ -0,0 +1,84 @@ +; $Id: bs3-cmn-Syscall.asm $ +;; @file +; BS3Kit - Bs3Syscall. +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + + +;********************************************************************************************************************************* +;* Header Files * +;********************************************************************************************************************************* +%include "bs3kit-template-header.mac" + + +;********************************************************************************************************************************* +;* External Symbols * +;********************************************************************************************************************************* +%if TMPL_BITS == 16 +BS3_EXTERN_DATA16 g_bBs3CurrentMode +%endif +BS3_EXTERN_DATA16 g_uBs3TrapEipHint +TMPL_BEGIN_TEXT + + +;; +; Worker for doing a syscall - Assembly only. +; +; This worker deals with the needing to use a different opcode +; sequence in v8086 mode as well as the high EIP word hint for +; the weird PE16_32, PP16_32 and PAE16_32 modes. +; +; @uses Whatever the syscall modified (xBX and XBP are always saved). +; +BS3_PROC_BEGIN_CMN Bs3Syscall, BS3_PBC_HYBRID_0_ARGS ; (all parameters are in registers) + push xBP + mov xBP, xSP + push xBX + +%if TMPL_BITS == 32 + mov ebx, .return + xchg ebx, [BS3_DATA16_WRT(g_uBs3TrapEipHint)] +%elif TMPL_BITS == 16 + test byte [BS3_DATA16_WRT(g_bBs3CurrentMode)], BS3_MODE_CODE_V86 + mov bx, 0 + xchg bx, [2 + BS3_DATA16_WRT(g_uBs3TrapEipHint)] + jz .normal + + db 0xf0 ; Lock prefix for causing #UD in V8086 mode. +%endif +.normal: + int BS3_TRAP_SYSCALL + +.return: + ; Restore the EIP hint so the testcase code doesn't need to set it all the time. +%if TMPL_BITS == 32 + mov [BS3_DATA16_WRT(g_uBs3TrapEipHint)], ebx +%elif TMPL_BITS == 16 + mov [2 + BS3_DATA16_WRT(g_uBs3TrapEipHint)], bx +%endif + + pop xBX + pop xBP + BS3_HYBRID_RET +BS3_PROC_END_CMN Bs3Syscall + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-TestCheckRegCtxEx.c b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-TestCheckRegCtxEx.c new file mode 100644 index 00000000..3d89a615 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-TestCheckRegCtxEx.c @@ -0,0 +1,97 @@ +/* $Id: bs3-cmn-TestCheckRegCtxEx.c $ */ +/** @file + * BS3Kit - TestCheckRegCtxEx + */ + +/* + * Copyright (C) 2007-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include "bs3kit-template-header.h" + + +#undef Bs3TestCheckRegCtxEx +BS3_CMN_DEF(bool, Bs3TestCheckRegCtxEx,(PCBS3REGCTX pActualCtx, PCBS3REGCTX pExpectedCtx, uint16_t cbPcAdjust, int16_t cbSpAcjust, + uint32_t fExtraEfl, const char *pszMode, uint16_t idTestStep)) +{ + uint16_t const cErrorsBefore = Bs3TestSubErrorCount(); + uint8_t const fbFlags = pActualCtx->fbFlags | pExpectedCtx->fbFlags; + +#define CHECK_MEMBER(a_szName, a_szFmt, a_Actual, a_Expected) \ + do { \ + if ((a_Actual) == (a_Expected)) { /* likely */ } \ + else Bs3TestFailedF("%u - %s: " a_szName "=" a_szFmt " expected " a_szFmt, idTestStep, pszMode, (a_Actual), (a_Expected)); \ + } while (0) + + CHECK_MEMBER("rax", "%08RX64", pActualCtx->rax.u, pExpectedCtx->rax.u); + CHECK_MEMBER("rcx", "%08RX64", pActualCtx->rcx.u, pExpectedCtx->rcx.u); + CHECK_MEMBER("rdx", "%08RX64", pActualCtx->rdx.u, pExpectedCtx->rdx.u); + CHECK_MEMBER("rbx", "%08RX64", pActualCtx->rbx.u, pExpectedCtx->rbx.u); + CHECK_MEMBER("rsp", "%08RX64", pActualCtx->rsp.u, pExpectedCtx->rsp.u + cbSpAcjust); + CHECK_MEMBER("rbp", "%08RX64", pActualCtx->rbp.u, pExpectedCtx->rbp.u); + CHECK_MEMBER("rsi", "%08RX64", pActualCtx->rsi.u, pExpectedCtx->rsi.u); + CHECK_MEMBER("rdi", "%08RX64", pActualCtx->rdi.u, pExpectedCtx->rdi.u); + if (!(fbFlags & BS3REG_CTX_F_NO_AMD64)) + { + CHECK_MEMBER("r8", "%08RX64", pActualCtx->r8.u, pExpectedCtx->r8.u); + CHECK_MEMBER("r9", "%08RX64", pActualCtx->r9.u, pExpectedCtx->r9.u); + CHECK_MEMBER("r10", "%08RX64", pActualCtx->r10.u, pExpectedCtx->r10.u); + CHECK_MEMBER("r11", "%08RX64", pActualCtx->r11.u, pExpectedCtx->r11.u); + CHECK_MEMBER("r12", "%08RX64", pActualCtx->r12.u, pExpectedCtx->r12.u); + CHECK_MEMBER("r13", "%08RX64", pActualCtx->r13.u, pExpectedCtx->r13.u); + CHECK_MEMBER("r14", "%08RX64", pActualCtx->r14.u, pExpectedCtx->r14.u); + CHECK_MEMBER("r15", "%08RX64", pActualCtx->r15.u, pExpectedCtx->r15.u); + } + CHECK_MEMBER("rflags", "%08RX64", pActualCtx->rflags.u, pExpectedCtx->rflags.u | fExtraEfl); + CHECK_MEMBER("rip", "%08RX64", pActualCtx->rip.u, pExpectedCtx->rip.u + cbPcAdjust); + CHECK_MEMBER("cs", "%04RX16", pActualCtx->cs, pExpectedCtx->cs); + CHECK_MEMBER("ds", "%04RX16", pActualCtx->ds, pExpectedCtx->ds); + CHECK_MEMBER("es", "%04RX16", pActualCtx->es, pExpectedCtx->es); + CHECK_MEMBER("fs", "%04RX16", pActualCtx->fs, pExpectedCtx->fs); + CHECK_MEMBER("gs", "%04RX16", pActualCtx->gs, pExpectedCtx->gs); + + if (!(fbFlags & BS3REG_CTX_F_NO_TR_LDTR)) + { + CHECK_MEMBER("tr", "%04RX16", pActualCtx->tr, pExpectedCtx->tr); + CHECK_MEMBER("ldtr", "%04RX16", pActualCtx->ldtr, pExpectedCtx->ldtr); + } + CHECK_MEMBER("bMode", "%#04x", pActualCtx->bMode, pExpectedCtx->bMode); + CHECK_MEMBER("bCpl", "%u", pActualCtx->bCpl, pExpectedCtx->bCpl); + + if (!(fbFlags & BS3REG_CTX_F_NO_CR0_IS_MSW)) + CHECK_MEMBER("cr0", "%08RX64", pActualCtx->cr0.u, pExpectedCtx->cr0.u); + else + CHECK_MEMBER("msw", "%08RX16", pActualCtx->cr0.u16, pExpectedCtx->cr0.u16); + if (!(fbFlags & BS3REG_CTX_F_NO_CR2_CR3)) + { + CHECK_MEMBER("cr2", "%08RX64", pActualCtx->cr2.u, pExpectedCtx->cr2.u); + CHECK_MEMBER("cr3", "%08RX64", pActualCtx->cr3.u, pExpectedCtx->cr3.u); + } + if (!(fbFlags & BS3REG_CTX_F_NO_CR4)) + CHECK_MEMBER("cr4", "%08RX64", pActualCtx->cr4.u, pExpectedCtx->cr4.u); +#undef CHECK_MEMBER + + return Bs3TestSubErrorCount() == cErrorsBefore; +} + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-TestData.c b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-TestData.c new file mode 100644 index 00000000..81534eab --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-TestData.c @@ -0,0 +1,111 @@ +/* $Id: bs3-cmn-TestData.c $ */ +/** @file + * BS3Kit - Test Data. + */ + +/* + * Copyright (C) 2007-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include "bs3kit-template-header.h" +#include "bs3-cmn-test.h" + + +/********************************************************************************************************************************* +* Global Variables * +*********************************************************************************************************************************/ +#if ARCH_BITS == 16 + +/** Indicates whether the VMMDev is operational. */ +bool g_fbBs3VMMDevTesting = true; + +/** Alignment padding. */ +bool g_fTestDataPadding0 = true; + +/** The number of tests that have failed. */ +uint16_t g_cusBs3TestErrors = 0; + +/** The start error count of the current subtest. */ +uint16_t g_cusBs3SubTestAtErrors = 0; + +/** Whether we've reported the sub-test result or not. */ +bool g_fbBs3SubTestReported = true; +/** Whether the sub-test has been skipped or not. */ +bool g_fbBs3SubTestSkipped = false; + +/** The number of sub tests. */ +uint16_t g_cusBs3SubTests = 0; + +/** The number of sub tests that failed. */ +uint16_t g_cusBs3SubTestsFailed = 0; + +/** VMMDEV_TESTING_UNIT_XXX -> string */ +char const g_aszBs3TestUnitNames[][16] = +{ + "inv", + "%", + "bytes", + "bytes/s", + "KB", + "KB/s", + "MB", + "MB/s", + "packets", + "packets/s", + "frames", + "frames/", + "occ", + "occ/s", + "rndtrp", + "calls", + "calls/s", + "s", + "ms", + "ns", + "ns/call", + "ns/frame", + "ns/occ", + "ns/packet", + "ns/rndtrp", + "ins", + "ins/s", + "", /* none */ + "pp1k", + "pp10k", + "ppm", + "ppb", +}; + + +/** The subtest name. */ +char g_szBs3SubTest[64]; + +/** The current test step. */ +uint16_t g_usBs3TestStep; + +#endif /* ARCH_BITS == 16 */ + +/** The test name. */ +const char BS3_FAR *BS3_CMN_NM(g_pszBs3Test) = NULL; + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-TestDoModesByOneHlp.asm b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-TestDoModesByOneHlp.asm new file mode 100644 index 00000000..84ca06ea --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-TestDoModesByOneHlp.asm @@ -0,0 +1,243 @@ +; $Id: bs3-cmn-TestDoModesByOneHlp.asm $ +;; @file +; BS3Kit - Bs3TestDoModesByOne Helpers for switching to the bit-count of the worker function. +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + + +;********************************************************************************************************************************* +;* Header Files * +;********************************************************************************************************************************* +%include "bs3kit-template-header.mac" + + +;********************************************************************************************************************************* +;* Global Variables * +;********************************************************************************************************************************* +BS3_BEGIN_DATA16 +BS3_GLOBAL_NAME_EX BS3_CMN_NM(g_pfnBs3TestDoModesByOneCurrent),,0 + RTCCPTR_DEF 0 + + +;********************************************************************************************************************************* +;* Exported Symbols * +;********************************************************************************************************************************* +%ifdef BS3_STRICT +BS3_EXTERN_DATA16 g_bBs3CurrentMode +%endif + +%if TMPL_BITS == 16 +BS3_BEGIN_TEXT16 +extern _Bs3SelRealModeCodeToProtMode_c16 +%endif + + +;; +; @cproto FNBS3TESTDOMODE +; +; @param bMode The current mode +; @uses What allowed by calling convention and possibly mode, caller deals with it. +; + +%if TMPL_BITS == 16 + ; + ; For 16-bit workers. + ; +BS3_BEGIN_TEXT16 + +BS3_SET_BITS 32 +BS3_PROC_BEGIN _Bs3TestCallDoerTo16_c32 + push xBP + mov xBP, xSP + + ; Load bMode into eax. + movzx eax, byte [xBP + xCB*2] + %ifdef BS3_STRICT + cmp al, [BS3_DATA16_WRT(g_bBs3CurrentMode)] + je .ok_mode + int3 +.ok_mode: + %endif + ; Switch to 16-bit. + extern _Bs3SwitchTo16Bit_c32 + call _Bs3SwitchTo16Bit_c32 + BS3_SET_BITS 16 + + push ax ; Worker bMode argument. + + ; Assuming real mode far pointer, convert protected mode before calling it. + push word [2 + BS3_DATA16_WRT(BS3_CMN_NM(g_pfnBs3TestDoModesByOneCurrent))] + call _Bs3SelRealModeCodeToProtMode_c16 + add sp, 2 + + push cs ; return selector + push word .return ; return address + + push ax ; call converted selector + push word [BS3_DATA16_WRT(BS3_CMN_NM(g_pfnBs3TestDoModesByOneCurrent))] ; call offset + retf + +.return: + ; Switch back to 32-bit mode. + extern _Bs3SwitchTo32Bit_c16 + call _Bs3SwitchTo32Bit_c16 + BS3_SET_BITS 32 + + leave + ret +BS3_PROC_END _Bs3TestCallDoerTo16_c32 + + +BS3_SET_BITS 64 +BS3_PROC_BEGIN _Bs3TestCallDoerTo16_c64 + push xBP + mov xBP, xSP + + ; Load bMode into eax. + movzx eax, cl + %ifdef BS3_STRICT + cmp al, [BS3_DATA16_WRT(g_bBs3CurrentMode)] + je .ok_mode + int3 +.ok_mode: + %endif + ; Switch to 16-bit. + extern _Bs3SwitchTo16Bit_c64 + call _Bs3SwitchTo16Bit_c64 + BS3_SET_BITS 16 + + push ax ; Worker bMode argument. + + ; Assuming real mode far pointer, convert protected mode before calling it. + push word [2 + BS3_DATA16_WRT(BS3_CMN_NM(g_pfnBs3TestDoModesByOneCurrent))] + call _Bs3SelRealModeCodeToProtMode_c16 + add sp, 2 + + push cs ; return selector + push word .return ; return address + push ax ; call converted selector + push word [BS3_DATA16_WRT(BS3_CMN_NM(g_pfnBs3TestDoModesByOneCurrent))] ; call offset + retf + +.return: + ; Switch back to 64-bit mode. + extern _Bs3SwitchTo64Bit_c16 + call _Bs3SwitchTo64Bit_c16 + BS3_SET_BITS 64 + + leave + ret +BS3_PROC_END _Bs3TestCallDoerTo16_c64 + + +%elif TMPL_BITS == 32 + ; + ; For 32-bit workers. + ; + +BS3_BEGIN_TEXT16 +BS3_SET_BITS 16 +BS3_PROC_BEGIN _Bs3TestCallDoerTo32_f16 + push xBP + mov xBP, xSP + + ; Load bMode into eax. + movzx eax, byte [xBP + xCB + sCB] + %ifdef BS3_STRICT + cmp al, [BS3_DATA16_WRT(g_bBs3CurrentMode)] + je .ok_mode + int3 +.ok_mode: + %endif + ; Switch to 32-bit. + extern _Bs3SwitchTo32Bit_c16 + call _Bs3SwitchTo32Bit_c16 + BS3_SET_BITS 32 + + push eax ; Worker bMode argument. + + test al, BS3_MODE_CODE_V86 + jnz .return_to_v86 ; Need to figure this while we still have the mode value. + + call [BS3_DATA16_WRT(BS3_CMN_NM(g_pfnBs3TestDoModesByOneCurrent))] + + ; Switch back to 16-bit mode. + extern _Bs3SwitchTo16Bit_c32 + call _Bs3SwitchTo16Bit_c32 + BS3_SET_BITS 16 +.return: + leave + retf + + BS3_SET_BITS 32 +.return_to_v86: + call [BS3_DATA16_WRT(BS3_CMN_NM(g_pfnBs3TestDoModesByOneCurrent))] + + ; Switch back to v8086 mode. + extern _Bs3SwitchTo16BitV86_c32 + call _Bs3SwitchTo16BitV86_c32 + BS3_SET_BITS 16 + jmp .return +BS3_PROC_END _Bs3TestCallDoerTo32_f16 + + +BS3_BEGIN_TEXT32 +BS3_SET_BITS 64 +BS3_PROC_BEGIN _Bs3TestCallDoerTo32_c64 + push xBP + mov xBP, xSP + + ; Load bMode into eax. + movzx eax, cl + %ifdef BS3_STRICT + cmp al, [BS3_DATA16_WRT(g_bBs3CurrentMode)] + je .ok_mode + int3 +.ok_mode: + %endif + ; Switch to 32-bit. + extern _Bs3SwitchTo32Bit_c64 + call _Bs3SwitchTo32Bit_c64 + BS3_SET_BITS 32 + + push eax ; Worker bMode argument. + call [BS3_DATA16_WRT(BS3_CMN_NM(g_pfnBs3TestDoModesByOneCurrent))] + + ; Switch back to 64-bit mode. + extern _Bs3SwitchTo64Bit_c32 + call _Bs3SwitchTo64Bit_c32 + BS3_SET_BITS 64 + + leave + ret +BS3_PROC_END _Bs3TestCallDoerTo32_c64 + + +%elif TMPL_BITS == 64 +; +; 64-bit workers makes no sense, so skip that. +; +%else + %error "TMPL_BITS!" +%endif + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-TestFailed.c b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-TestFailed.c new file mode 100644 index 00000000..80ff3fdd --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-TestFailed.c @@ -0,0 +1,141 @@ +/* $Id: bs3-cmn-TestFailed.c $ */ +/** @file + * BS3Kit - Bs3TestFailed, Bs3TestFailedF, Bs3TestFailedV. + */ + +/* + * Copyright (C) 2007-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include "bs3kit-template-header.h" +#include "bs3-cmn-test.h" +#include <iprt/asm-amd64-x86.h> + + +/** + * @callback_method_impl{FNBS3STRFORMATOUTPUT, + * Used by Bs3TestFailedV and Bs3TestSkippedV.} + */ +BS3_DECL_CALLBACK(size_t) bs3TestFailedStrOutput(char ch, void BS3_FAR *pvUser) +{ + PBS3TESTFAILEDBUF pBuf = (PBS3TESTFAILEDBUF)pvUser; + + /* + * VMMDev first. We postpone newline processing here so we can strip one + * trailing newline. + */ + if (g_fbBs3VMMDevTesting) + { + if (pBuf->fNewLine && ch != '\0') + ASMOutU8(VMMDEV_TESTING_IOPORT_DATA, '\n'); + pBuf->fNewLine = ch == '\n'; + if (ch != '\n') + ASMOutU8(VMMDEV_TESTING_IOPORT_DATA, ch); + } + + /* + * Console next. + */ + if (ch != '\0') + { + BS3_ASSERT(pBuf->cchBuf < RT_ELEMENTS(pBuf->achBuf)); + pBuf->achBuf[pBuf->cchBuf++] = ch; + + /* Whether to flush the buffer. We do line flushing here to avoid + dropping too much info when the formatter crashes on bad input. */ + if ( pBuf->cchBuf < RT_ELEMENTS(pBuf->achBuf) + && ch != '\n') + { + pBuf->fNewLine = false; + return 1; + } + pBuf->fNewLine = '\n'; + } + /* Try fit missing newline into the buffer. */ + else if (!pBuf->fNewLine && pBuf->cchBuf < RT_ELEMENTS(pBuf->achBuf)) + { + pBuf->fNewLine = true; + pBuf->achBuf[pBuf->cchBuf++] = '\n'; + } + + BS3_ASSERT(pBuf->cchBuf <= RT_ELEMENTS(pBuf->achBuf)); + Bs3PrintStrN(&pBuf->achBuf[0], pBuf->cchBuf); + pBuf->cchBuf = 0; + + /* In case we failed to add trailing new line, print one separately. */ + if (!pBuf->fNewLine) + Bs3PrintChr('\n'); + + return ch != '\0'; +} + + +/** + * Equivalent to RTTestIFailedV. + */ +#undef Bs3TestFailedV +BS3_CMN_DEF(bool, Bs3TestFailedV,(const char *pszFormat, va_list BS3_FAR va)) +{ + BS3TESTFAILEDBUF Buf; + + if (!++g_cusBs3TestErrors) + g_cusBs3TestErrors++; + + if (g_fbBs3VMMDevTesting) +#if ARCH_BITS == 16 + ASMOutU16(VMMDEV_TESTING_IOPORT_CMD, (uint16_t)VMMDEV_TESTING_CMD_FAILED); +#else + ASMOutU32(VMMDEV_TESTING_IOPORT_CMD, VMMDEV_TESTING_CMD_FAILED); +#endif + + Buf.fNewLine = false; + Buf.cchBuf = 0; + Bs3StrFormatV(pszFormat, va, bs3TestFailedStrOutput, &Buf); + return false; +} + + +/** + * Equivalent to RTTestIFailedF. + */ +#undef Bs3TestFailedF +BS3_CMN_DEF(bool, Bs3TestFailedF,(const char *pszFormat, ...)) +{ + va_list va; + va_start(va, pszFormat); + BS3_CMN_NM(Bs3TestFailedV)(pszFormat, va); + va_end(va); + return false; +} + + +/** + * Equivalent to RTTestIFailed. + */ +#undef Bs3TestFailed +BS3_CMN_DEF(bool, Bs3TestFailed,(const char *pszMessage)) +{ + return BS3_CMN_NM(Bs3TestFailedF)("%s", pszMessage); +} + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-TestHostPrintf.c b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-TestHostPrintf.c new file mode 100644 index 00000000..be4666ef --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-TestHostPrintf.c @@ -0,0 +1,104 @@ +/* $Id: bs3-cmn-TestHostPrintf.c $ */ +/** @file + * BS3Kit - BS3TestPrintf, BS3TestPrintfV + */ + +/* + * Copyright (C) 2007-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include "bs3kit-template-header.h" +#include "bs3-cmn-test.h" + +#include <iprt/asm-amd64-x86.h> + + +/********************************************************************************************************************************* +* Structures and Typedefs * +*********************************************************************************************************************************/ +/** Output state for Bs3TestHostPrintfV. */ +typedef struct BS3TESTHOSTPRINTF +{ + bool fNewCmd; +} BS3TESTHOSTPRINTF; + + +/** + * @callback_method_impl{FNBS3STRFORMATOUTPUT, Prints to screen and VMMDev} + */ +static BS3_DECL_CALLBACK(size_t) bs3TestPrintfStrOutput(char ch, void BS3_FAR *pvUser) +{ + BS3TESTHOSTPRINTF BS3_FAR *pState = (BS3TESTHOSTPRINTF BS3_FAR *)pvUser; + + /* + * VMMDev first. We do line by line processing to avoid running out of + * string buffer on the host side. + */ + if (g_fbBs3VMMDevTesting) + { + if (ch != '\n' && !pState->fNewCmd) + ASMOutU8(VMMDEV_TESTING_IOPORT_DATA, ch); + else if (ch != '\0') + { + if (pState->fNewCmd) + { +#if ARCH_BITS == 16 + ASMOutU16(VMMDEV_TESTING_IOPORT_CMD, (uint16_t)VMMDEV_TESTING_CMD_PRINT); +#else + ASMOutU32(VMMDEV_TESTING_IOPORT_CMD, VMMDEV_TESTING_CMD_PRINT); +#endif + pState->fNewCmd = false; + } + ASMOutU8(VMMDEV_TESTING_IOPORT_DATA, ch); + if (ch == '\n') + { + ASMOutU8(VMMDEV_TESTING_IOPORT_DATA, '\0'); + pState->fNewCmd = true; + } + } + } + + return ch != '\0'; +} + + +#undef Bs3TestHostPrintfV +BS3_CMN_DEF(void, Bs3TestHostPrintfV,(const char BS3_FAR *pszFormat, va_list BS3_FAR va)) +{ + BS3TESTHOSTPRINTF State; + State.fNewCmd = true; + Bs3StrFormatV(pszFormat, va, bs3TestPrintfStrOutput, &State); +} + + + +#undef Bs3TestHostPrintf +BS3_CMN_DEF(void, Bs3TestHostPrintf,(const char BS3_FAR *pszFormat, ...)) +{ + va_list va; + va_start(va, pszFormat); + BS3_CMN_NM(Bs3TestHostPrintfV)(pszFormat, va); + va_end(va); +} + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-TestInit.c b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-TestInit.c new file mode 100644 index 00000000..f31f6fe1 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-TestInit.c @@ -0,0 +1,67 @@ +/* $Id: bs3-cmn-TestInit.c $ */ +/** @file + * BS3Kit - Bs3TestInit + */ + +/* + * Copyright (C) 2007-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include "bs3kit-template-header.h" +#include "bs3-cmn-test.h" + + +/** + * Equivalent to RTTestCreate + RTTestBanner. + * + * @param pszTest The test name. + */ +#undef Bs3TestInit +BS3_CMN_DEF(void, Bs3TestInit,(const char BS3_FAR *pszTest)) +{ + /* + * Initialize the globals. + */ + BS3_CMN_NM(g_pszBs3Test) = pszTest; + g_szBs3SubTest[0] = '\0'; + g_cusBs3TestErrors = 0; + g_cusBs3SubTestAtErrors = 0; + g_fbBs3SubTestReported = true; + g_fbBs3SubTestSkipped = false; + g_cusBs3SubTests = 0; + g_cusBs3SubTestsFailed = 0; + g_fbBs3VMMDevTesting = bs3TestIsVmmDevTestingPresent(); + + /* + * Print the name - RTTestBanner. + */ + Bs3PrintStr(pszTest); + Bs3PrintStr(": TESTING...\n"); + + /* + * Report it to the VMMDev. + */ + bs3TestSendCmdWithStr(VMMDEV_TESTING_CMD_INIT, pszTest); +} + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-TestIsVmmDevTestingPresent.asm b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-TestIsVmmDevTestingPresent.asm new file mode 100644 index 00000000..9232550d --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-TestIsVmmDevTestingPresent.asm @@ -0,0 +1,68 @@ +; $Id: bs3-cmn-TestIsVmmDevTestingPresent.asm $ +;; @file +; BS3Kit - bs3TestIsVmmDevTestingPresent +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + +%include "bs3kit-template-header.mac" +%include "VBox/VMMDevTesting.mac" + +;********************************************************************************************************************************* +;* External Symbols * +;********************************************************************************************************************************* +BS3_EXTERN_DATA16 g_uBs3CpuDetected +TMPL_BEGIN_TEXT + + +;; +; @cproto BS3_DECL(bool) bs3TestIsVmmDevTestingPresent_c16(void); +; +BS3_PROC_BEGIN_CMN bs3TestIsVmmDevTestingPresent, BS3_PBC_HYBRID_0_ARGS + BS3_CALL_CONV_PROLOG 2 + push xBP + mov xBP, xSP + push xDX + + ; Check the response from the NOP port. + mov dx, VMMDEV_TESTING_IOPORT_NOP + cmp byte [g_uBs3CpuDetected], BS3CPU_80386 + jb .ancient_cpu + in eax, dx + cmp eax, VMMDEV_TESTING_NOP_RET +.set_ax_and_return: + mov ax, 0 + jne .return + mov ax, 1 + +.return: + pop xDX + pop xBP + BS3_CALL_CONV_EPILOG 2 + BS3_HYBRID_RET + +.ancient_cpu: + in ax, dx + cmp ax, (VMMDEV_TESTING_NOP_RET & 0xffff) + jmp .set_ax_and_return +BS3_PROC_END_CMN bs3TestIsVmmDevTestingPresent + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-TestPrintf.c b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-TestPrintf.c new file mode 100644 index 00000000..f6af17c6 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-TestPrintf.c @@ -0,0 +1,136 @@ +/* $Id: bs3-cmn-TestPrintf.c $ */ +/** @file + * BS3Kit - BS3TestPrintf, BS3TestPrintfV + */ + +/* + * Copyright (C) 2007-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include "bs3kit-template-header.h" +#include "bs3-cmn-test.h" + +#include <iprt/asm-amd64-x86.h> + + +/********************************************************************************************************************************* +* Defined Constants And Macros * +*********************************************************************************************************************************/ +#define SMALL_BUFFER 1 + + +/********************************************************************************************************************************* +* Structures and Typedefs * +*********************************************************************************************************************************/ +/** Output buffering for Bs3TestPrintfV. */ +typedef struct BS3TESTPRINTBUF +{ + bool fNewCmd; +#if SMALL_BUFFER + uint8_t cchBuf; + char achBuf[78]; +#else + uint16_t cchBuf; + char achBuf[512]; +#endif +} BS3TESTPRINTBUF; + + +/** + * @callback_method_impl{FNBS3STRFORMATOUTPUT, Prints to screen and VMMDev} + */ +static BS3_DECL_CALLBACK(size_t) bs3TestPrintfStrOutput(char ch, void BS3_FAR *pvUser) +{ + BS3TESTPRINTBUF BS3_FAR *pBuf = (BS3TESTPRINTBUF BS3_FAR *)pvUser; + + /* + * VMMDev first. We do line by line processing to avoid running out of + * string buffer on the host side. + */ + if (g_fbBs3VMMDevTesting) + { + if (ch != '\n' && !pBuf->fNewCmd) + ASMOutU8(VMMDEV_TESTING_IOPORT_DATA, ch); + else if (ch != '\0') + { + if (pBuf->fNewCmd) + { +#if ARCH_BITS == 16 + ASMOutU16(VMMDEV_TESTING_IOPORT_CMD, (uint16_t)VMMDEV_TESTING_CMD_PRINT); +#else + ASMOutU32(VMMDEV_TESTING_IOPORT_CMD, VMMDEV_TESTING_CMD_PRINT); +#endif + pBuf->fNewCmd = false; + } + ASMOutU8(VMMDEV_TESTING_IOPORT_DATA, ch); + if (ch == '\n') + { + ASMOutU8(VMMDEV_TESTING_IOPORT_DATA, '\0'); + pBuf->fNewCmd = true; + } + } + } + + /* + * Console next. + */ + if (ch != '\0') + { + BS3_ASSERT(pBuf->cchBuf < RT_ELEMENTS(pBuf->achBuf)); + pBuf->achBuf[pBuf->cchBuf++] = ch; + + /* Whether to flush the buffer. We do line flushing here to avoid + dropping too much info when the formatter crashes on bad input. */ + if ( pBuf->cchBuf < RT_ELEMENTS(pBuf->achBuf) + && (!SMALL_BUFFER || ch != '\n') ) + return 1; + } + BS3_ASSERT(pBuf->cchBuf <= RT_ELEMENTS(pBuf->achBuf)); + Bs3PrintStrN(&pBuf->achBuf[0], pBuf->cchBuf); + pBuf->cchBuf = 0; + return ch != '\0'; +} + + + +#undef Bs3TestPrintfV +BS3_CMN_DEF(void, Bs3TestPrintfV,(const char BS3_FAR *pszFormat, va_list BS3_FAR va)) +{ + BS3TESTPRINTBUF Buf; + Buf.fNewCmd = true; + Buf.cchBuf = 0; + Bs3StrFormatV(pszFormat, va, bs3TestPrintfStrOutput, &Buf); +} + + + +#undef Bs3TestPrintf +BS3_CMN_DEF(void, Bs3TestPrintf,(const char BS3_FAR *pszFormat, ...)) +{ + va_list va; + va_start(va, pszFormat); + BS3_CMN_NM(Bs3TestPrintfV)(pszFormat, va); + va_end(va); +} + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-TestSendCmdWithStr.asm b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-TestSendCmdWithStr.asm new file mode 100644 index 00000000..8e8067ee --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-TestSendCmdWithStr.asm @@ -0,0 +1,80 @@ +; $Id: bs3-cmn-TestSendCmdWithStr.asm $ +;; @file +; BS3Kit - bs3TestSendStrCmd. +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + +%include "bs3kit-template-header.mac" +%include "VBox/VMMDevTesting.mac" + +BS3_EXTERN_DATA16 g_fbBs3VMMDevTesting +TMPL_BEGIN_TEXT + +;; +; @cproto BS3_DECL(void) bs3TestSendCmdWithStr_c16(uint32_t uCmd, const char BS3_FAR *pszString); +; +BS3_PROC_BEGIN_CMN bs3TestSendCmdWithStr, BS3_PBC_HYBRID + BS3_CALL_CONV_PROLOG 2 + push xBP + mov xBP, xSP + push xAX + push xDX + push xSI +BONLY16 push ds + + cmp byte [BS3_DATA16_WRT(g_fbBs3VMMDevTesting)], 0 + je .no_vmmdev + + ; The command (uCmd). + mov dx, VMMDEV_TESTING_IOPORT_CMD +%if TMPL_BITS == 16 + mov ax, [xBP + xCB + cbCurRetAddr] ; We ignore the top bits in 16-bit mode. + out dx, ax +%else + mov eax, [xBP + xCB + cbCurRetAddr] + out dx, eax +%endif + + ; The string. + mov dx, VMMDEV_TESTING_IOPORT_DATA +%if TMPL_BITS == 16 + lds si, [xBP + xCB + cbCurRetAddr + sCB] +%else + mov xSI, [xBP + xCB + cbCurRetAddr + sCB] +%endif +.next_char: + lodsb + out dx, al + test al, al + jnz .next_char + +.no_vmmdev: +BONLY16 pop ds + pop xSI + pop xDX + pop xAX + pop xBP + BS3_CALL_CONV_EPILOG 2 + BS3_HYBRID_RET +BS3_PROC_END_CMN bs3TestSendCmdWithStr + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-TestSendCmdWithU32.asm b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-TestSendCmdWithU32.asm new file mode 100644 index 00000000..e9cfd8c8 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-TestSendCmdWithU32.asm @@ -0,0 +1,78 @@ +; $Id: bs3-cmn-TestSendCmdWithU32.asm $ +;; @file +; BS3Kit - bs3TestSendCmdWithU32. +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + +%include "bs3kit-template-header.mac" +%include "VBox/VMMDevTesting.mac" + +BS3_EXTERN_DATA16 g_fbBs3VMMDevTesting +TMPL_BEGIN_TEXT + +;; +; @cproto BS3_DECL(void) bs3TestSendCmdWithU32_c16(uint32_t uCmd, uint32_t uValue); +; +BS3_PROC_BEGIN_CMN bs3TestSendCmdWithU32, BS3_PBC_HYBRID + BS3_CALL_CONV_PROLOG 2 + push xBP + mov xBP, xSP + push xAX + push xDX + push xSI + + cmp byte [BS3_DATA16_WRT(g_fbBs3VMMDevTesting)], 0 + je .no_vmmdev + + ; The command (uCmd) - + mov dx, VMMDEV_TESTING_IOPORT_CMD +%if TMPL_BITS == 16 + mov ax, [xBP + xCB + cbCurRetAddr] ; We ignore the top bits in 16-bit mode. + out dx, ax +%else + mov eax, [xBP + xCB*2] + out dx, eax +%endif + + + ; The value (uValue). + mov dx, VMMDEV_TESTING_IOPORT_DATA +%if TMPL_BITS == 16 + mov ax, [xBP + xCB + cbCurRetAddr + sCB] + out dx, ax + mov ax, [xBP + xCB + cbCurRetAddr + sCB + 2] + out dx, ax +%else + mov eax, [xBP + xCB*2 + sCB] + out dx, eax +%endif + +.no_vmmdev: + pop xSI + pop xDX + pop xAX + pop xBP + BS3_CALL_CONV_EPILOG 2 + BS3_HYBRID_RET +BS3_PROC_END_CMN bs3TestSendCmdWithU32 + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-TestSkipped.c b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-TestSkipped.c new file mode 100644 index 00000000..6ece707f --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-TestSkipped.c @@ -0,0 +1,90 @@ +/* $Id: bs3-cmn-TestSkipped.c $ */ +/** @file + * BS3Kit - Bs3TestSkipped + */ + +/* + * Copyright (C) 2007-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include "bs3kit-template-header.h" +#include "bs3-cmn-test.h" +#include <iprt/asm-amd64-x86.h> + + +/** + * Equivalent to RTTestSkippedV. + */ +#undef Bs3TestSkippedV +BS3_CMN_DEF(void, Bs3TestSkippedV,(const char *pszFormat, va_list BS3_FAR va)) +{ + if (g_cusBs3TestErrors == g_cusBs3SubTestAtErrors) + { + /* Just mark it as skipped and deal with it when the sub-test is done. */ + g_fbBs3SubTestSkipped = true; + + /* Tell VMMDev */ + if (g_fbBs3VMMDevTesting) +#if ARCH_BITS == 16 + ASMOutU16(VMMDEV_TESTING_IOPORT_CMD, (uint16_t)VMMDEV_TESTING_CMD_SKIPPED); +#else + ASMOutU32(VMMDEV_TESTING_IOPORT_CMD, VMMDEV_TESTING_CMD_SKIPPED); +#endif + + /* The reason why it was skipped is optional. */ + if (pszFormat) + { + BS3TESTFAILEDBUF Buf; + Buf.fNewLine = false; + Buf.cchBuf = 0; + Bs3StrFormatV(pszFormat, va, bs3TestFailedStrOutput, &Buf); + } + else if (g_fbBs3VMMDevTesting) + ASMOutU8(VMMDEV_TESTING_IOPORT_DATA, 0); + } +} + + +/** + * Equivalent to RTTestSkipped. + */ +#undef Bs3TestSkippedF +BS3_CMN_DEF(void, Bs3TestSkippedF,(const char *pszFormat, ...)) +{ + va_list va; + va_start(va, pszFormat); + BS3_CMN_NM(Bs3TestSkippedV)(pszFormat, va); + va_end(va); +} + + +/** + * Equivalent to RTTestSkipped. + */ +#undef Bs3TestSkipped +BS3_CMN_DEF(void, Bs3TestSkipped,(const char *pszWhy)) +{ + BS3_CMN_NM(Bs3TestSkippedF)(pszWhy ? "%s" : NULL, pszWhy); +} + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-TestSub.c b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-TestSub.c new file mode 100644 index 00000000..cc3a7dcc --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-TestSub.c @@ -0,0 +1,95 @@ +/* $Id: bs3-cmn-TestSub.c $ */ +/** @file + * BS3Kit - Bs3TestSub, Bs3TestSubF, Bs3TestSubV. + */ + +/* + * Copyright (C) 2007-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include "bs3kit-template-header.h" +#include "bs3-cmn-test.h" + + + +/** + * Equivalent to RTTestISubV. + */ +#undef Bs3TestSubV +BS3_CMN_DEF(void, Bs3TestSubV,(const char *pszFormat, va_list BS3_FAR va)) +{ + size_t cch; + + /* + * Cleanup any previous sub-test. + */ + bs3TestSubCleanup(); + + /* + * Format the sub-test name and update globals. + */ + cch = Bs3StrPrintfV(g_szBs3SubTest, sizeof(g_szBs3SubTest), pszFormat, va); + g_cusBs3SubTestAtErrors = g_cusBs3TestErrors; + BS3_ASSERT(!g_fbBs3SubTestSkipped); + g_cusBs3SubTests++; + + /* + * Tell VMMDev and output to the console. + */ + bs3TestSendCmdWithStr(VMMDEV_TESTING_CMD_SUB_NEW, g_szBs3SubTest); + + Bs3PrintStr(g_szBs3SubTest); + Bs3PrintChr(':'); + do + Bs3PrintChr(' '); + while (cch++ < 49); + Bs3PrintStr(" TESTING\n"); + + /* The sub-test result is not yet reported. */ + g_fbBs3SubTestReported = false; +} + + +/** + * Equivalent to RTTestIFailedF. + */ +#undef Bs3TestSubF +BS3_CMN_DEF(void, Bs3TestSubF,(const char *pszFormat, ...)) +{ + va_list va; + va_start(va, pszFormat); + BS3_CMN_NM(Bs3TestSubV)(pszFormat, va); + va_end(va); +} + + +/** + * Equivalent to RTTestISub. + */ +#undef Bs3TestSub +BS3_CMN_DEF(void, Bs3TestSub,(const char *pszMessage)) +{ + BS3_CMN_NM(Bs3TestSubF)("%s", pszMessage); +} + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-TestSubDone.c b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-TestSubDone.c new file mode 100644 index 00000000..0967677d --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-TestSubDone.c @@ -0,0 +1,44 @@ +/* $Id: bs3-cmn-TestSubDone.c $ */ +/** @file + * BS3Kit - Bs3TestSubDone. + */ + +/* + * Copyright (C) 2007-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include "bs3kit-template-header.h" +#include "bs3-cmn-test.h" + + + +/** + * Equivalent to RTTestISubDone. + */ +#undef Bs3TestSubDone +BS3_CMN_DEF(void, Bs3TestSubDone,(void)) +{ + bs3TestSubCleanup(); +} + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-TestSubErrorCount.c b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-TestSubErrorCount.c new file mode 100644 index 00000000..e160e0fb --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-TestSubErrorCount.c @@ -0,0 +1,44 @@ +/* $Id: bs3-cmn-TestSubErrorCount.c $ */ +/** @file + * BS3Kit - Bs3TestSubErrorCount. + */ + +/* + * Copyright (C) 2007-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include "bs3kit-template-header.h" +#include "bs3-cmn-test.h" + + + +/** + * Equivalent to RTTestSubErrorCount. + */ +#undef Bs3TestSubErrorCount +BS3_CMN_DEF(uint16_t, Bs3TestSubErrorCount,(void)) +{ + return g_cusBs3TestErrors - g_cusBs3SubTestAtErrors; +} + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-TestTerm.c b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-TestTerm.c new file mode 100644 index 00000000..e96d2f0c --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-TestTerm.c @@ -0,0 +1,107 @@ +/* $Id: bs3-cmn-TestTerm.c $ */ +/** @file + * BS3Kit - Bs3TestTerm + */ + +/* + * Copyright (C) 2007-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include "bs3kit-template-header.h" +#include "bs3-cmn-test.h" + + + +/** + * Equivalent to rtTestSubCleanup + rtTestSubTestReport. + */ +BS3_DECL(void) bs3TestSubCleanup(void) +{ + if (g_szBs3SubTest[0] != '\0') + { + if (!g_fbBs3SubTestReported) + { + size_t cch; + uint16_t cErrors = g_cusBs3TestErrors - g_cusBs3SubTestAtErrors; + + /* Tell VMMDev. */ + bs3TestSendCmdWithU32(VMMDEV_TESTING_CMD_SUB_DONE, cErrors); + + /* Print result to the console. */ + Bs3PrintStr(g_szBs3SubTest); + Bs3PrintChr(':'); + cch = Bs3StrLen(g_szBs3SubTest); + do + Bs3PrintChr(' '); + while (cch++ < 49); + + if (!cErrors) + Bs3PrintStr(!g_fbBs3SubTestSkipped ? "PASSED\n" : "SKIPPED\n"); + else + { + g_cusBs3SubTestsFailed++; + Bs3Printf("FAILED (%u errors)\n", g_szBs3SubTest, cErrors); + } + } + + /* Reset the sub-test. */ + g_fbBs3SubTestReported = true; + g_fbBs3SubTestSkipped = false; + g_szBs3SubTest[0] = '\0'; + } +} + + +/** + * Equivalent to RTTestSummaryAndDestroy. + */ +#undef Bs3TestTerm +BS3_CMN_DEF(void, Bs3TestTerm,(void)) +{ + /* + * Close any current sub-test. + */ + bs3TestSubCleanup(); + + /* + * Report summary. + */ + if (BS3_CMN_NM(g_pszBs3Test)) + { + Bs3PrintStr(BS3_CMN_NM(g_pszBs3Test)); + if (g_cusBs3TestErrors == 0) + Bs3Printf(": SUCCESS (%u tests)\n", g_cusBs3SubTests); + else + Bs3Printf(": FAILURE - %u (%u of %u tests)\n", + g_cusBs3TestErrors, g_cusBs3SubTestsFailed, g_cusBs3SubTests); + } + + /* + * Tell VMMDev. + */ + bs3TestSendCmdWithU32(VMMDEV_TESTING_CMD_TERM, g_cusBs3TestErrors); + + BS3_CMN_NM(g_pszBs3Test) = NULL; +} + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-Trap16Init.c b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-Trap16Init.c new file mode 100644 index 00000000..6e8c3b96 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-Trap16Init.c @@ -0,0 +1,119 @@ +/* $Id: bs3-cmn-Trap16Init.c $ */ +/** @file + * BS3Kit - Bs3Trap16Init + */ + +/* + * Copyright (C) 2007-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include "bs3kit-template-header.h" + + +/********************************************************************************************************************************* +* Global Variables * +*********************************************************************************************************************************/ +/* We ASSUME that BS3CLASS16CODE is 64KB aligned, so the low 16-bit of the + flat address matches. Also, these symbols are defined both with + and without underscore prefixes. */ +extern BS3_DECL(void) BS3_FAR_CODE Bs3Trap16DoubleFaultHandler80386(void); +extern BS3_DECL(void) BS3_FAR_CODE Bs3Trap16DoubleFaultHandler80286(void); +extern BS3_DECL(void) BS3_FAR_CODE Bs3Trap16GenericEntries(void); + +/* These two are ugly. Need data access for patching purposes. */ +extern uint8_t BS3_FAR_DATA bs3Trap16GenericTrapOrInt[]; + + +#undef Bs3Trap16InitEx +BS3_CMN_DEF(void, Bs3Trap16InitEx,(bool f386Plus)) +{ + X86TSS16 BS3_FAR *pTss; + unsigned iIdt; + + /* + * If 386 or later, patch the trap handler code to not jump to the 80286 + * code but continue with the next instruction (the 386+ code). + */ + if (f386Plus) + { + uint8_t BS3_FAR_DATA *pbFunction = &bs3Trap16GenericTrapOrInt[0]; +#if ARCH_BITS == 16 + if (g_bBs3CurrentMode != BS3_MODE_RM) + pbFunction = (uint8_t BS3_FAR_DATA *)BS3_FP_MAKE(BS3_SEL_TILED + 1, BS3_FP_OFF(pbFunction)); +#endif + pbFunction[1] = 0; + pbFunction[2] = 0; + } + + /* + * IDT entries, except the system call gate. + */ + for (iIdt = 0; iIdt < 256; iIdt++) + if (iIdt != BS3_TRAP_SYSCALL) + Bs3Trap16SetGate(iIdt, X86_SEL_TYPE_SYS_286_INT_GATE, 0 /*bDpl*/, + BS3_SEL_R0_CS16, (uint16_t)(uintptr_t)Bs3Trap16GenericEntries + iIdt * 8, 0 /*cParams*/); + + /* + * Initialize the normal TSS so we can do ring transitions via the IDT. + */ + pTss = &Bs3Tss16; + Bs3MemZero(pTss, sizeof(*pTss)); + pTss->sp0 = BS3_ADDR_STACK_R0; + pTss->ss0 = BS3_SEL_R0_SS16; + pTss->sp1 = BS3_ADDR_STACK_R1; + pTss->ss1 = BS3_SEL_R1_SS16 | 1; + pTss->sp2 = BS3_ADDR_STACK_R2; + pTss->ss2 = BS3_SEL_R2_SS16 | 2; + + /* + * Initialize the double fault TSS. + * cr3 is filled in by switcher code, when needed. + */ + pTss = &Bs3Tss16DoubleFault; + Bs3MemZero(pTss, sizeof(*pTss)); + pTss->sp0 = BS3_ADDR_STACK_R0; + pTss->ss0 = BS3_SEL_R0_SS16; + pTss->sp1 = BS3_ADDR_STACK_R1; + pTss->ss1 = BS3_SEL_R1_SS16 | 1; + pTss->sp2 = BS3_ADDR_STACK_R2; + pTss->ss2 = BS3_SEL_R2_SS16 | 2; + pTss->ip = (uint16_t)(uintptr_t)(f386Plus ? &Bs3Trap16DoubleFaultHandler80386 : &Bs3Trap16DoubleFaultHandler80286); + pTss->flags = X86_EFL_1; + pTss->sp = BS3_ADDR_STACK_R0_IST1; + pTss->es = BS3_SEL_R0_DS16; + pTss->ds = BS3_SEL_R0_DS16; + pTss->cs = BS3_SEL_R0_CS16; + pTss->ss = BS3_SEL_R0_SS16; + pTss->dx = f386Plus; + + Bs3Trap16SetGate(X86_XCPT_DF, X86_SEL_TYPE_SYS_TASK_GATE, 0 /*bDpl*/, BS3_SEL_TSS16_DF, 0, 0 /*cParams*/); +} + + +#undef Bs3Trap16Init +BS3_CMN_DEF(void, Bs3Trap16Init,(void)) +{ + BS3_CMN_NM(Bs3Trap16InitEx)((g_uBs3CpuDetected & BS3CPU_TYPE_MASK) >= BS3CPU_80386); +} + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-Trap16SetGate.c b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-Trap16SetGate.c new file mode 100644 index 00000000..e940b01c --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-Trap16SetGate.c @@ -0,0 +1,52 @@ +/* $Id: bs3-cmn-Trap16SetGate.c $ */ +/** @file + * BS3Kit - Bs3Trap16SetGate + */ + +/* + * Copyright (C) 2007-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include "bs3kit-template-header.h" + + +#undef Bs3Trap16SetGate +BS3_CMN_DEF(void, Bs3Trap16SetGate,(uint8_t iIdt, uint8_t bType, uint8_t bDpl, uint16_t uSel, uint16_t off, uint8_t cParams)) +{ + X86DESC BS3_FAR *pIdte = &Bs3Idt16[iIdt]; + + BS3_ASSERT(bDpl <= 3); + BS3_ASSERT(bType <= 15); + BS3_ASSERT(cParams <= 15); + pIdte->Gate.u16OffsetLow = (uint16_t)off; + pIdte->Gate.u16OffsetHigh = 0; + pIdte->Gate.u16Sel = uSel; + pIdte->Gate.u5ParmCount = cParams; + pIdte->Gate.u4Type = bType; + pIdte->Gate.u2Dpl = bDpl; + pIdte->Gate.u3Reserved = 0; + pIdte->Gate.u1DescType = 0; /* system */ + pIdte->Gate.u1Present = 1; +} + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-Trap32Init.c b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-Trap32Init.c new file mode 100644 index 00000000..ce0a1840 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-Trap32Init.c @@ -0,0 +1,91 @@ +/* $Id: bs3-cmn-Trap32Init.c $ */ +/** @file + * BS3Kit - Bs3Trap32Init + */ + +/* + * Copyright (C) 2007-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include "bs3kit-template-header.h" + + +/********************************************************************************************************************************* +* External Symbols * +*********************************************************************************************************************************/ +#define g_Bs3Trap32DoubleFaultHandlerFlatAddr BS3_DATA_NM(g_Bs3Trap32DoubleFaultHandlerFlatAddr) +extern uint32_t g_Bs3Trap32DoubleFaultHandlerFlatAddr; + + +#undef Bs3Trap32Init +BS3_CMN_DEF(void, Bs3Trap32Init,(void)) +{ + X86TSS32 BS3_FAR *pTss; + unsigned iIdt; + + /* + * IDT entries, except the system call gate. + */ + for (iIdt = 0; iIdt < BS3_TRAP_SYSCALL; iIdt++) + Bs3Trap32SetGate(iIdt, X86_SEL_TYPE_SYS_386_INT_GATE, 0 /*bDpl*/, + BS3_SEL_R0_CS32, g_Bs3Trap32GenericEntriesFlatAddr + iIdt * 10, 0 /*cParams*/); + for (iIdt = BS3_TRAP_SYSCALL + 1; iIdt < 256; iIdt++) + Bs3Trap32SetGate(iIdt, X86_SEL_TYPE_SYS_386_INT_GATE, 0 /*bDpl*/, + BS3_SEL_R0_CS32, g_Bs3Trap32GenericEntriesFlatAddr + iIdt * 10, 0 /*cParams*/); + + /* + * Initialize the normal TSS so we can do ring transitions via the IDT. + */ + pTss = &Bs3Tss32; + Bs3MemZero(pTss, sizeof(*pTss)); + pTss->esp0 = BS3_ADDR_STACK_R0; + pTss->ss0 = BS3_SEL_R0_SS32; + pTss->esp1 = BS3_ADDR_STACK_R1; + pTss->ss1 = BS3_SEL_R1_SS32 | 1; + pTss->esp2 = BS3_ADDR_STACK_R2; + pTss->ss2 = BS3_SEL_R2_SS32 | 2; + + /* + * Initialize the double fault TSS. + * cr3 is filled in by switcher code, when needed. + */ + pTss = &Bs3Tss32DoubleFault; + Bs3MemZero(pTss, sizeof(*pTss)); + pTss->esp0 = BS3_ADDR_STACK_R0; + pTss->ss0 = BS3_SEL_R0_SS32; + pTss->esp1 = BS3_ADDR_STACK_R1; + pTss->ss1 = BS3_SEL_R1_SS32 | 1; + pTss->esp2 = BS3_ADDR_STACK_R2; + pTss->ss2 = BS3_SEL_R2_SS32 | 2; + pTss->eip = g_Bs3Trap32DoubleFaultHandlerFlatAddr; + pTss->eflags = X86_EFL_1; + pTss->esp = BS3_ADDR_STACK_R0_IST1; + pTss->es = BS3_SEL_R0_DS32; + pTss->ds = BS3_SEL_R0_DS32; + pTss->cs = BS3_SEL_R0_CS32; + pTss->ss = BS3_SEL_R0_SS32; + + Bs3Trap32SetGate(X86_XCPT_DF, X86_SEL_TYPE_SYS_TASK_GATE, 0 /*bDpl*/, BS3_SEL_TSS32_DF, 0, 0 /*cParams*/); +} + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-Trap32SetGate.c b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-Trap32SetGate.c new file mode 100644 index 00000000..9f9b4dff --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-Trap32SetGate.c @@ -0,0 +1,52 @@ +/* $Id: bs3-cmn-Trap32SetGate.c $ */ +/** @file + * BS3Kit - Bs3Trap32SetGate + */ + +/* + * Copyright (C) 2007-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include "bs3kit-template-header.h" + + +#undef Bs3Trap32SetGate +BS3_CMN_DEF(void, Bs3Trap32SetGate,(uint8_t iIdt, uint8_t bType, uint8_t bDpl, uint16_t uSel, uint32_t off, uint8_t cParams)) +{ + X86DESC BS3_FAR *pIdte = &Bs3Idt32[iIdt]; + + BS3_ASSERT(bDpl <= 3); + BS3_ASSERT(bType <= 15); + BS3_ASSERT(cParams <= 15); + pIdte->Gate.u16OffsetLow = (uint16_t)off; + pIdte->Gate.u16OffsetHigh = (uint16_t)(off >> 16); + pIdte->Gate.u16Sel = uSel; + pIdte->Gate.u5ParmCount = cParams; + pIdte->Gate.u4Type = bType; + pIdte->Gate.u2Dpl = bDpl; + pIdte->Gate.u3Reserved = 0; + pIdte->Gate.u1DescType = 0; /* system */ + pIdte->Gate.u1Present = 1; +} + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-Trap64Init.c b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-Trap64Init.c new file mode 100644 index 00000000..56d49730 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-Trap64Init.c @@ -0,0 +1,67 @@ +/* $Id: bs3-cmn-Trap64Init.c $ */ +/** @file + * BS3Kit - Bs3Trap64Init + */ + +/* + * Copyright (C) 2007-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include "bs3kit-template-header.h" + + +#undef Bs3Trap64Init +BS3_CMN_DEF(void, Bs3Trap64Init,(void)) +{ + X86TSS64 BS3_FAR *pTss; + unsigned iIdt; + + /* + * IDT entries, except the system call gate. + * The #DF entry get IST=1, all others IST=0. + */ + for (iIdt = 0; iIdt < BS3_TRAP_SYSCALL; iIdt++) + Bs3Trap64SetGate(iIdt, AMD64_SEL_TYPE_SYS_INT_GATE, 0 /*bDpl*/, + BS3_SEL_R0_CS64, g_Bs3Trap64GenericEntriesFlatAddr + iIdt * 8, iIdt == X86_XCPT_DF /*bIst*/); + for (iIdt = BS3_TRAP_SYSCALL + 1; iIdt < 256; iIdt++) + Bs3Trap64SetGate(iIdt, AMD64_SEL_TYPE_SYS_INT_GATE, 0 /*bDpl*/, + BS3_SEL_R0_CS64, g_Bs3Trap64GenericEntriesFlatAddr + iIdt * 8, 0 /*bIst*/); + + /* + * Initialize the normal TSS so we can do ring transitions via the IDT. + */ + pTss = &Bs3Tss64; + Bs3MemZero(pTss, sizeof(*pTss)); + pTss->rsp0 = BS3_ADDR_STACK_R0; + pTss->rsp1 = BS3_ADDR_STACK_R1; + pTss->rsp2 = BS3_ADDR_STACK_R2; + pTss->ist1 = BS3_ADDR_STACK_R0_IST1; + pTss->ist2 = BS3_ADDR_STACK_R0_IST2; + pTss->ist3 = BS3_ADDR_STACK_R0_IST3; + pTss->ist4 = BS3_ADDR_STACK_R0_IST4; + pTss->ist5 = BS3_ADDR_STACK_R0_IST5; + pTss->ist6 = BS3_ADDR_STACK_R0_IST6; + pTss->ist7 = BS3_ADDR_STACK_R0_IST7; +} + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-Trap64SetGate.c b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-Trap64SetGate.c new file mode 100644 index 00000000..bce0116f --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-Trap64SetGate.c @@ -0,0 +1,55 @@ +/* $Id: bs3-cmn-Trap64SetGate.c $ */ +/** @file + * BS3Kit - Bs3Trap64SetGate + */ + +/* + * Copyright (C) 2007-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include "bs3kit-template-header.h" + + +#undef Bs3Trap64SetGate +BS3_CMN_DEF(void, Bs3Trap64SetGate,(uint8_t iIdt, uint8_t bType, uint8_t bDpl, uint16_t uSel, uint64_t off, uint8_t bIst)) +{ + X86DESC64 BS3_FAR *pIdte = &Bs3Idt64[iIdt]; + + BS3_ASSERT(bDpl <= 3); + BS3_ASSERT(bType <= 15); + BS3_ASSERT(bIst <= 7); + pIdte->Gate.u16OffsetLow = (uint16_t)off; + pIdte->Gate.u16OffsetHigh = (uint16_t)((uint32_t)off >> 16); + pIdte->Gate.u32OffsetTop = (uint32_t)(off >> 32); + pIdte->Gate.u16Sel = uSel; + pIdte->Gate.u3IST = bIst; + pIdte->Gate.u4Type = bType; + pIdte->Gate.u2Dpl = bDpl; + pIdte->Gate.u5Reserved = 0; + pIdte->Gate.u1DescType = 0; /* system */ + pIdte->Gate.u1Present = 1; + pIdte->Gate.u32Reserved = 0; + +} + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-TrapDefaultHandler.c b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-TrapDefaultHandler.c new file mode 100644 index 00000000..af6c150b --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-TrapDefaultHandler.c @@ -0,0 +1,313 @@ +/* $Id: bs3-cmn-TrapDefaultHandler.c $ */ +/** @file + * BS3Kit - Bs3TrapDefaultHandler + */ + +/* + * Copyright (C) 2007-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include "bs3kit-template-header.h" +#if TMPL_BITS != 64 +# include <VBox/VMMDevTesting.h> +# include <iprt/asm-amd64-x86.h> +#endif + + +/********************************************************************************************************************************* +* Global Variables * +*********************************************************************************************************************************/ +#define g_pBs3TrapSetJmpFrame BS3_DATA_NM(g_pBs3TrapSetJmpFrame) +extern uint32_t g_pBs3TrapSetJmpFrame; + +#define g_Bs3TrapSetJmpCtx BS3_DATA_NM(g_Bs3TrapSetJmpCtx) +extern BS3REGCTX g_Bs3TrapSetJmpCtx; + + +#if TMPL_BITS != 64 +/** + * V86 syscall handler. + */ +static void bs3TrapDefaultHandlerV8086Syscall(PBS3TRAPFRAME pTrapFrame) +{ + /* Minimal syscall. */ + uint16_t uSyscallNo = pTrapFrame->Ctx.rax.u16; + if (uSyscallNo == BS3_SYSCALL_PRINT_CHR) + Bs3PrintChr(pTrapFrame->Ctx.rcx.u8); + else if (uSyscallNo == BS3_SYSCALL_PRINT_STR) + Bs3PrintStrN(Bs3XptrFlatToCurrent(((uint32_t)pTrapFrame->Ctx.rcx.u16 << 4) + pTrapFrame->Ctx.rsi.u16), + pTrapFrame->Ctx.rdx.u16); + else if (uSyscallNo == BS3_SYSCALL_RESTORE_CTX) + Bs3RegCtxRestore(Bs3XptrFlatToCurrent(((uint32_t)pTrapFrame->Ctx.rcx.u16 << 4) + pTrapFrame->Ctx.rsi.u16), + pTrapFrame->Ctx.rdx.u16); + else if ( uSyscallNo == BS3_SYSCALL_TO_RING0 + || uSyscallNo == BS3_SYSCALL_TO_RING1 + || uSyscallNo == BS3_SYSCALL_TO_RING2 + || uSyscallNo == BS3_SYSCALL_TO_RING3) + { + Bs3RegCtxConvertToRingX(&pTrapFrame->Ctx, pTrapFrame->Ctx.rax.u16 - BS3_SYSCALL_TO_RING0); + } + else if (uSyscallNo == BS3_SYSCALL_SET_DRX) + { + uint32_t uValue = pTrapFrame->Ctx.rsi.u32; + switch (pTrapFrame->Ctx.rdx.u8) + { + case 0: ASMSetDR0(uValue); break; + case 1: ASMSetDR1(uValue); break; + case 2: ASMSetDR2(uValue); break; + case 3: ASMSetDR3(uValue); break; + case 6: ASMSetDR6(uValue); break; + case 7: ASMSetDR7(uValue); break; + default: Bs3Panic(); + } + } + else if (uSyscallNo == BS3_SYSCALL_GET_DRX) + { + uint32_t uValue; + switch (pTrapFrame->Ctx.rdx.u8) + { + case 0: uValue = ASMGetDR0(); break; + case 1: uValue = ASMGetDR1(); break; + case 2: uValue = ASMGetDR2(); break; + case 3: uValue = ASMGetDR3(); break; + case 6: uValue = ASMGetDR6(); break; + case 7: uValue = ASMGetDR7(); break; + default: uValue = 0; Bs3Panic(); + } + pTrapFrame->Ctx.rax.u32 = uValue; + pTrapFrame->Ctx.rdx.u32 = uValue >> 16; + } + else if (uSyscallNo == BS3_SYSCALL_SET_CRX) + { + uint32_t uValue = pTrapFrame->Ctx.rsi.u32; + switch (pTrapFrame->Ctx.rdx.u8) + { + case 0: ASMSetCR0(uValue); pTrapFrame->Ctx.cr0.u32 = uValue; break; + case 2: ASMSetCR2(uValue); pTrapFrame->Ctx.cr2.u32 = uValue; break; + case 3: ASMSetCR3(uValue); pTrapFrame->Ctx.cr3.u32 = uValue; break; + case 4: ASMSetCR4(uValue); pTrapFrame->Ctx.cr4.u32 = uValue; break; + default: Bs3Panic(); + } + } + else if (uSyscallNo == BS3_SYSCALL_GET_CRX) + { + uint32_t uValue; + switch (pTrapFrame->Ctx.rdx.u8) + { + case 0: uValue = ASMGetDR0(); break; + case 2: uValue = ASMGetCR2(); break; + case 3: uValue = ASMGetCR3(); break; + case 4: uValue = ASMGetCR4(); break; + default: uValue = 0; Bs3Panic(); + } + pTrapFrame->Ctx.rax.u32 = uValue; + pTrapFrame->Ctx.rdx.u32 = uValue >> 16; + } + else if (uSyscallNo == BS3_SYSCALL_SET_TR) + { + Bs3RegSetTr(pTrapFrame->Ctx.rdx.u16); + pTrapFrame->Ctx.tr = pTrapFrame->Ctx.rdx.u16; + } + else if (uSyscallNo == BS3_SYSCALL_GET_TR) + pTrapFrame->Ctx.rax.u16 = ASMGetTR(); + else if (uSyscallNo == BS3_SYSCALL_SET_LDTR) + { + Bs3RegSetLdtr(pTrapFrame->Ctx.rdx.u16); + pTrapFrame->Ctx.ldtr = pTrapFrame->Ctx.rdx.u16; + } + else if (uSyscallNo == BS3_SYSCALL_GET_LDTR) + pTrapFrame->Ctx.rax.u16 = ASMGetLDTR(); + else + Bs3Panic(); +} +#endif + +#undef Bs3TrapDefaultHandler +BS3_CMN_DEF(void, Bs3TrapDefaultHandler,(PBS3TRAPFRAME pTrapFrame)) +{ +#if TMPL_BITS != 64 + /* + * v8086 VMM tasks. + */ + //Bs3TestHostPrintf("Bs3____DefaultHandler: %02xh %04RX16:%08RX32 %08RX32 %04RX16:%08RX32 %d %d\n", pTrapFrame->bXcpt, + // pTrapFrame->Ctx.cs, pTrapFrame->Ctx.rip.u32, pTrapFrame->Ctx.rflags.u32, pTrapFrame->Ctx.ss, + // pTrapFrame->Ctx.rsp.u32, g_fBs3TrapNoV86Assist, 42); + if ((pTrapFrame->Ctx.rflags.u32 & X86_EFL_VM)) + { + bool fHandled = true; + uint8_t cBitsOpcode = 16; + uint8_t bOpCode; + uint8_t const BS3_FAR *pbCodeStart; + uint8_t const BS3_FAR *pbCode; + uint16_t BS3_FAR *pusStack; + + pusStack = (uint16_t BS3_FAR *)BS3_MAKE_PROT_R0PTR_FROM_REAL(pTrapFrame->Ctx.ss, pTrapFrame->Ctx.rsp.u16); + pbCode = (uint8_t const BS3_FAR *)BS3_MAKE_PROT_R0PTR_FROM_REAL(pTrapFrame->Ctx.cs, pTrapFrame->Ctx.rip.u16); + pbCodeStart = pbCode; + + /* + * Deal with GPs in V8086 mode. + */ + if ( pTrapFrame->bXcpt == X86_XCPT_GP + && !g_fBs3TrapNoV86Assist) + { + bOpCode = *pbCode++; + if (bOpCode == 0x66) + { + cBitsOpcode = 32; + bOpCode = *pbCode++; + } + + /* INT xx: Real mode behaviour, but intercepting and implementing most of our syscall interface. */ + if (bOpCode == 0xcd) + { + uint8_t bVector = *pbCode++; + if (bVector == BS3_TRAP_SYSCALL) + bs3TrapDefaultHandlerV8086Syscall(pTrapFrame); + else + { + /* Real mode behaviour. */ + uint16_t BS3_FAR *pusIvte = (uint16_t BS3_FAR *)BS3_MAKE_PROT_R0PTR_FROM_REAL(0, 0); + pusIvte += (uint16_t)bVector *2; + + pusStack[0] = pTrapFrame->Ctx.rflags.u16; + pusStack[1] = pTrapFrame->Ctx.cs; + pusStack[2] = pTrapFrame->Ctx.rip.u16 + (uint16_t)(pbCode - pbCodeStart); + + pTrapFrame->Ctx.rip.u16 = pusIvte[0]; + pTrapFrame->Ctx.cs = pusIvte[1]; + pTrapFrame->Ctx.rflags.u16 &= ~X86_EFL_IF; /** @todo this isn't all, but it'll do for now, I hope. */ + Bs3RegCtxRestore(&pTrapFrame->Ctx, 0/*fFlags*/); /* does not return. */ + } + } + /* PUSHF: Real mode behaviour. */ + else if (bOpCode == 0x9c) + { + if (cBitsOpcode == 32) + *pusStack++ = pTrapFrame->Ctx.rflags.au16[1] & ~(X86_EFL_VM | X86_EFL_RF); + *pusStack++ = pTrapFrame->Ctx.rflags.u16; + pTrapFrame->Ctx.rsp.u16 += cBitsOpcode / 8; + } + /* POPF: Real mode behaviour. */ + else if (bOpCode == 0x9d) + { + if (cBitsOpcode == 32) + { + pTrapFrame->Ctx.rflags.u32 &= ~X86_EFL_POPF_BITS; + pTrapFrame->Ctx.rflags.u32 |= X86_EFL_POPF_BITS & *(uint32_t const *)pusStack; + } + else + { + pTrapFrame->Ctx.rflags.u32 &= ~(X86_EFL_POPF_BITS | UINT32_C(0xffff0000)) & ~X86_EFL_RF; + pTrapFrame->Ctx.rflags.u16 |= (uint16_t)X86_EFL_POPF_BITS & *pusStack; + } + pTrapFrame->Ctx.rsp.u16 -= cBitsOpcode / 8; + } + /* CLI: Real mode behaviour. */ + else if (bOpCode == 0xfa) + pTrapFrame->Ctx.rflags.u16 &= ~X86_EFL_IF; + /* STI: Real mode behaviour. */ + else if (bOpCode == 0xfb) + pTrapFrame->Ctx.rflags.u16 |= X86_EFL_IF; + /* OUT: byte I/O to VMMDev. */ + else if ( bOpCode == 0xee + && ((unsigned)(pTrapFrame->Ctx.rdx.u16 - VMMDEV_TESTING_IOPORT_BASE) < (unsigned)VMMDEV_TESTING_IOPORT_COUNT)) + ASMOutU8(pTrapFrame->Ctx.rdx.u16, pTrapFrame->Ctx.rax.u8); + /* OUT: [d]word I/O to VMMDev. */ + else if ( bOpCode == 0xef + && ((unsigned)(pTrapFrame->Ctx.rdx.u16 - VMMDEV_TESTING_IOPORT_BASE) < (unsigned)VMMDEV_TESTING_IOPORT_COUNT)) + { + if (cBitsOpcode != 32) + ASMOutU16(pTrapFrame->Ctx.rdx.u16, pTrapFrame->Ctx.rax.u16); + else + ASMOutU32(pTrapFrame->Ctx.rdx.u16, pTrapFrame->Ctx.rax.u32); + } + /* IN: byte I/O to VMMDev. */ + else if ( bOpCode == 0xec + && ((unsigned)(pTrapFrame->Ctx.rdx.u16 - VMMDEV_TESTING_IOPORT_BASE) < (unsigned)VMMDEV_TESTING_IOPORT_COUNT)) + pTrapFrame->Ctx.rax.u8 = ASMInU8(pTrapFrame->Ctx.rdx.u16); + /* IN: [d]word I/O to VMMDev. */ + else if ( bOpCode == 0xed + && ((unsigned)(pTrapFrame->Ctx.rdx.u16 - VMMDEV_TESTING_IOPORT_BASE) < (unsigned)VMMDEV_TESTING_IOPORT_COUNT)) + { + if (cBitsOpcode != 32) + pTrapFrame->Ctx.rax.u16 = ASMInU16(pTrapFrame->Ctx.rdx.u16); + else + pTrapFrame->Ctx.rax.u32 = ASMInU32(pTrapFrame->Ctx.rdx.u32); + } + /* Unexpected. */ + else + fHandled = false; + } + /* + * Deal with lock prefixed int xxh syscall in v8086 mode. + */ + else if ( pTrapFrame->bXcpt == X86_XCPT_UD + && pTrapFrame->Ctx.cs == BS3_SEL_TEXT16 + && pTrapFrame->Ctx.rax.u16 <= BS3_SYSCALL_LAST + && pbCode[0] == 0xf0 + && pbCode[1] == 0xcd + && pbCode[2] == BS3_TRAP_SYSCALL) + { + pbCode += 3; + bs3TrapDefaultHandlerV8086Syscall(pTrapFrame); + } + else + { + fHandled = false; + } + if (fHandled) + { + pTrapFrame->Ctx.rip.u16 += (uint16_t)(pbCode - pbCodeStart); +# if 0 + Bs3Printf("Calling Bs3RegCtxRestore\n"); + Bs3RegCtxPrint(&pTrapFrame->Ctx); +# endif + Bs3RegCtxRestore(&pTrapFrame->Ctx, 0 /*fFlags*/); /* does not return. */ + return; + } + } +#endif + + /* + * Any pending setjmp? + */ + if (g_pBs3TrapSetJmpFrame != 0) + { + PBS3TRAPFRAME pSetJmpFrame = (PBS3TRAPFRAME)Bs3XptrFlatToCurrent(g_pBs3TrapSetJmpFrame); + //Bs3Printf("Calling longjmp: pSetJmpFrame=%p (%#lx)\n", pSetJmpFrame, g_pBs3TrapSetJmpFrame); + g_pBs3TrapSetJmpFrame = 0; + Bs3MemCpy(pSetJmpFrame, pTrapFrame, sizeof(*pSetJmpFrame)); + //Bs3RegCtxPrint(&g_Bs3TrapSetJmpCtx); + Bs3RegCtxRestore(&g_Bs3TrapSetJmpCtx, 0 /*fFlags*/); + } + + /* + * Fatal. + */ + Bs3TestPrintf("*** GURU ***\n"); + Bs3TrapPrintFrame(pTrapFrame); + Bs3Panic(); +} + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-TrapHandlersData.asm b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-TrapHandlersData.asm new file mode 100644 index 00000000..bd814da7 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-TrapHandlersData.asm @@ -0,0 +1,40 @@ +; $Id: bs3-cmn-TrapHandlersData.asm $ +;; @file +; BS3Kit - Per bit-count trap data. +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + +;********************************************************************************************************************************* +;* Header Files * +;********************************************************************************************************************************* +%include "bs3kit-template-header.mac" + + + +BS3_BEGIN_DATA16 +;; Pointer C trap handlers. +;; Note! The 16-bit ones are all near so we can share them between real, v86 and prot mode. +;; Note! Must be in 16-bit data because of BS3TrapSetHandlerEx. +BS3_GLOBAL_NAME_EX BS3_CMN_NM(g_apfnBs3TrapHandlers), , 256 * xCB + resb 256 * xCB + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-TrapPrintFrame.c b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-TrapPrintFrame.c new file mode 100644 index 00000000..4854723e --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-TrapPrintFrame.c @@ -0,0 +1,79 @@ +/* $Id: bs3-cmn-TrapPrintFrame.c $ */ +/** @file + * BS3Kit - Bs3TrapPrintFrame + */ + +/* + * Copyright (C) 2007-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include "bs3kit-template-header.h" + + +#undef Bs3TrapPrintFrame +BS3_CMN_DEF(void, Bs3TrapPrintFrame,(PCBS3TRAPFRAME pTrapFrame)) +{ +#if 1 + Bs3TestPrintf("Trap %#04x errcd=%#06RX64 at %04x:%016RX64 - test step %d (%#x)\n" + "Handler: ss:rsp=%04x:%08RX64 cs=%04x cbIret=%#x rflags=%#06RX64\n" + , + pTrapFrame->bXcpt, + pTrapFrame->uErrCd, + pTrapFrame->Ctx.cs, + pTrapFrame->Ctx.rip.u64, + g_usBs3TestStep, g_usBs3TestStep, + pTrapFrame->uHandlerSs, + pTrapFrame->uHandlerRsp, + pTrapFrame->uHandlerCs, + pTrapFrame->cbIretFrame, + pTrapFrame->fHandlerRfl); + Bs3RegCtxPrint(&pTrapFrame->Ctx); +#else + /* This is useful if having trouble returning from real mode. */ + PCBS3REGCTX pRegCtx = &pTrapFrame->Ctx; + Bs3TestPrintf("Trap %#04x errcd=%#06RX64 at %04x:%016RX64 - test step %d (%#x)\n" + "eax=%08RX32 ebx=%08RX32 ecx=%08RX32 edx=%08RX32 esi=%08RX32 edi=%08RX32\n" + "eip=%08RX32 esp=%08RX32 ebp=%08RX32 efl=%08RX32 cr0=%08RX32 cr2=%08RX32\n" + "cs=%04RX16 ds=%04RX16 es=%04RX16 fs=%04RX16 gs=%04RX16 ss=%04RX16 cr3=%08RX32 cr4=%08RX32\n" + "tr=%04RX16 ldtr=%04RX16 cpl=%d mode=%#x fbFlags=%#x\n" + , + pTrapFrame->bXcpt, + pTrapFrame->uErrCd, + pTrapFrame->Ctx.cs, + pTrapFrame->Ctx.rip.u64, + g_usBs3TestStep, g_usBs3TestStep + , + pRegCtx->rax.u32, pRegCtx->rbx.u32, pRegCtx->rcx.u32, pRegCtx->rdx.u32, pRegCtx->rsi.u32, pRegCtx->rdi.u32 + , + pRegCtx->rip.u32, pRegCtx->rsp.u32, pRegCtx->rbp.u32, pRegCtx->rflags.u32, + pRegCtx->cr0.u32, pRegCtx->cr2.u32 + , + pRegCtx->cs, pRegCtx->ds, pRegCtx->es, pRegCtx->fs, pRegCtx->gs, pRegCtx->ss, + pRegCtx->cr3.u32, pRegCtx->cr4.u32 + , + pRegCtx->tr, pRegCtx->ldtr, pRegCtx->bCpl, pRegCtx->bMode, pRegCtx->fbFlags); + +#endif +} + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-TrapReInit.c b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-TrapReInit.c new file mode 100644 index 00000000..421c44d8 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-TrapReInit.c @@ -0,0 +1,55 @@ +/* $Id: bs3-cmn-TrapReInit.c $ */ +/** @file + * BS3Kit - Bs3TrapReInit + */ + +/* + * Copyright (C) 2007-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include "bs3kit-template-header.h" + + +#undef Bs3TrapReInit +BS3_CMN_DEF(void, Bs3TrapReInit,(void)) +{ + if (BS3_MODE_IS_RM_SYS(g_bBs3CurrentMode)) + Bs3TrapRmV86Init(); + else if (BS3_MODE_IS_16BIT_SYS(g_bBs3CurrentMode)) + { + Bs3TrapRmV86Init(); + Bs3Trap16Init(); + } + else if (BS3_MODE_IS_32BIT_SYS(g_bBs3CurrentMode)) + { + Bs3TrapRmV86Init(); + Bs3Trap32Init(); + } + else + { + BS3_ASSERT(BS3_MODE_IS_64BIT_SYS(g_bBs3CurrentMode)); + Bs3Trap64Init(); + } +} + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-TrapRmV86Init.c b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-TrapRmV86Init.c new file mode 100644 index 00000000..ec341e94 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-TrapRmV86Init.c @@ -0,0 +1,110 @@ +/* $Id: bs3-cmn-TrapRmV86Init.c $ */ +/** @file + * BS3Kit - Bs3TrapRmV86Init + */ + +/* + * Copyright (C) 2007-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include "bs3kit-template-header.h" + + +/********************************************************************************************************************************* +* Global Variables * +*********************************************************************************************************************************/ +/* We ASSUME that BS3CLASS16CODE is 64KB aligned, so the low 16-bit of the + flat address matches. Also, these symbols are defined both with + and without underscore prefixes. */ +extern BS3_DECL(void) BS3_FAR_CODE Bs3TrapRmV86GenericEntries(void); + +/* These two are ugly. Need data access for patching purposes. */ +extern uint8_t BS3_FAR_DATA bs3TrapRmV86GenericTrapOrInt[]; + +/* bs3-cmn-TrapRmV86Data.c: */ +#define g_fBs3RmIvtCopied BS3_DATA_NM(g_fBs3RmIvtCopied) +extern bool g_fBs3RmIvtCopied; + + +#undef Bs3TrapRmV86InitEx +BS3_CMN_DEF(void, Bs3TrapRmV86InitEx,(bool f386Plus)) +{ + RTFAR16 BS3_FAR *paIvt = Bs3XptrFlatToCurrent(0); + unsigned iIvt; + + /* + * Copy the real mode IVT the first time we are here. + */ + if (!g_fBs3RmIvtCopied) + { + Bs3MemCpy(g_aBs3RmIvtOriginal, paIvt, sizeof(g_aBs3RmIvtOriginal)); + g_fBs3RmIvtCopied = true; + } + /* + * The rest of the times, we copy back the original and modify it. + */ + else + Bs3MemCpy(paIvt, g_aBs3RmIvtOriginal, sizeof(g_aBs3RmIvtOriginal)); + + + /* + * If 386 or later, patch the trap handler code to not jump to the 80286 + * code but continue with the next instruction (the 386+ code). + */ + if (f386Plus) + { + uint8_t BS3_FAR_DATA *pbFunction = &bs3TrapRmV86GenericTrapOrInt[0]; +#if ARCH_BITS == 16 + if (g_bBs3CurrentMode != BS3_MODE_RM) + pbFunction = (uint8_t BS3_FAR_DATA *)BS3_FP_MAKE(BS3_SEL_TILED + 1, BS3_FP_OFF(pbFunction)); +#endif + pbFunction[1] = 0; + pbFunction[2] = 0; + } + + /* + * Since we want to play with V86 mode as well as 8086 and 186 CPUs, we + * cannot move the IVT from its default location. So, modify it in place. + * + * Note! We must keep INT 10h working, which is easy since the CPU does + * use it (well, it's been reserved for 30+ years). + * Turns out we must not hook INT 6Dh either then, as some real VGA + * BIOS installs their INT 10h handler there as well, and seemingly + * must be using it internally or something. + */ + for (iIvt = 0; iIvt < 256; iIvt++) + if (iIvt != 0x10 && iIvt != 0x6d && iIvt != BS3_TRAP_SYSCALL) + { + paIvt[iIvt].off = (uint16_t)(uintptr_t)Bs3TrapRmV86GenericEntries + iIvt * 8; + paIvt[iIvt].sel = BS3_SEL_TEXT16; + } +} + + +#undef Bs3TrapRmV86Init +BS3_CMN_DEF(void, Bs3TrapRmV86Init,(void)) +{ + BS3_CMN_NM(Bs3TrapRmV86InitEx)((g_uBs3CpuDetected & BS3CPU_TYPE_MASK) >= BS3CPU_80386); +} + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-TrapRmV86SetGate.c b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-TrapRmV86SetGate.c new file mode 100644 index 00000000..fb6a1917 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-TrapRmV86SetGate.c @@ -0,0 +1,41 @@ +/* $Id: bs3-cmn-TrapRmV86SetGate.c $ */ +/** @file + * BS3Kit - Bs3TrapRmV86SetGate + */ + +/* + * Copyright (C) 2007-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include "bs3kit-template-header.h" + + +#undef Bs3TrapRmV86SetGate +BS3_CMN_DEF(void, Bs3TrapRmV86SetGate,(uint8_t iIvt, uint16_t uSeg, uint16_t off)) +{ + RTFAR16 BS3_FAR *paIvt = Bs3XptrFlatToCurrent(0); + paIvt[iIvt].off = off; + paIvt[iIvt].sel = uSeg; +} + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-TrapSetDpl.c b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-TrapSetDpl.c new file mode 100644 index 00000000..e04dda48 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-TrapSetDpl.c @@ -0,0 +1,47 @@ +/* $Id: bs3-cmn-TrapSetDpl.c $ */ +/** @file + * BS3Kit - Bs3TrapSetDpl + */ + +/* + * Copyright (C) 2007-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include "bs3kit-template-header.h" + + +#undef Bs3TrapSetDpl +BS3_CMN_DEF(uint8_t, Bs3TrapSetDpl,(uint8_t iIdt, uint8_t bDpl)) +{ + uint8_t bRet; + BS3_ASSERT(bDpl <= 3); + + Bs3Idt16[iIdt].Gate.u2Dpl = bDpl; + Bs3Idt32[iIdt].Gate.u2Dpl = bDpl; + bRet = Bs3Idt64[iIdt].Gate.u2Dpl; + Bs3Idt64[iIdt].Gate.u2Dpl = bDpl; + + return bRet; +} + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-TrapSetHandler.c b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-TrapSetHandler.c new file mode 100644 index 00000000..91f4cc3e --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-TrapSetHandler.c @@ -0,0 +1,47 @@ +/* $Id: bs3-cmn-TrapSetHandler.c $ */ +/** @file + * BS3Kit - Bs3Trap32SetHandler + */ + +/* + * Copyright (C) 2007-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include "bs3kit-template-header.h" + + +/********************************************************************************************************************************* +* External Symbols * +*********************************************************************************************************************************/ +extern PFNBS3TRAPHANDLER BS3_DATA_NM(BS3_CMN_NM(g_apfnBs3TrapHandlers))[256]; + + +#undef Bs3TrapSetHandler +BS3_CMN_DEF(PFNBS3TRAPHANDLER, Bs3TrapSetHandler,(uint8_t iIdt, PFNBS3TRAPHANDLER pfnHandler)) +{ + PFNBS3TRAPHANDLER pfnOld = BS3_DATA_NM(BS3_CMN_NM(g_apfnBs3TrapHandlers))[iIdt]; + BS3_DATA_NM(BS3_CMN_NM(g_apfnBs3TrapHandlers))[iIdt] = pfnHandler; + return pfnOld; +} + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-TrapSetHandlerEx.c b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-TrapSetHandlerEx.c new file mode 100644 index 00000000..dc567520 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-TrapSetHandlerEx.c @@ -0,0 +1,61 @@ +/* $Id: bs3-cmn-TrapSetHandlerEx.c $ */ +/** @file + * BS3Kit - Bs3Trap32SetHandlerEx + */ + +/* + * Copyright (C) 2007-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include "bs3kit-template-header.h" +#include <iprt/asm-amd64-x86.h> + + +/********************************************************************************************************************************* +* External Symbols * +*********************************************************************************************************************************/ +extern uint16_t BS3_DATA_NM(g_apfnBs3TrapHandlers_c16)[256]; +extern uint32_t BS3_DATA_NM(g_apfnBs3TrapHandlers_c32)[256]; +extern uint64_t BS3_DATA_NM(g_apfnBs3TrapHandlers_c64)[256]; + + +#undef Bs3TrapSetHandlerEx +BS3_CMN_DEF(void, Bs3TrapSetHandlerEx,(uint8_t iIdt, PFNBS3TRAPHANDLER16 pfnHandler16, + PFNBS3TRAPHANDLER32 pfnHandler32, PFNBS3TRAPHANDLER64 pfnHandler64)) +{ + RTCCUINTREG fFlags = ASMIntDisableFlags(); +#if ARCH_BITS == 16 + /* Far real mode pointers as input. */ + g_apfnBs3TrapHandlers_c16[iIdt] = (uint16_t)pfnHandler16; + g_apfnBs3TrapHandlers_c32[iIdt] = Bs3SelRealModeCodeToFlat((PFNBS3FARADDRCONV)pfnHandler32); + g_apfnBs3TrapHandlers_c64[iIdt] = Bs3SelRealModeCodeToFlat((PFNBS3FARADDRCONV)pfnHandler64); +#else + /* Flat pointers as input. */ + g_apfnBs3TrapHandlers_c16[iIdt] = (uint16_t)Bs3SelFlatCodeToProtFar16((uintptr_t)pfnHandler16); + g_apfnBs3TrapHandlers_c32[iIdt] = (uint32_t)(uintptr_t)pfnHandler32; + g_apfnBs3TrapHandlers_c64[iIdt] = (uintptr_t)pfnHandler64; +#endif + ASMSetFlags(fFlags); +} + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-TrapSetJmp.asm b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-TrapSetJmp.asm new file mode 100644 index 00000000..c4a90c6e --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-TrapSetJmp.asm @@ -0,0 +1,133 @@ +; $Id: bs3-cmn-TrapSetJmp.asm $ +;; @file +; BS3Kit - Bs3TrapSetJmp. +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + + +;********************************************************************************************************************************* +;* Header Files * +;********************************************************************************************************************************* +%include "bs3kit-template-header.mac" + + +;********************************************************************************************************************************* +;* External Symbols * +;********************************************************************************************************************************* +BS3_EXTERN_CMN Bs3RegCtxSave +%if TMPL_BITS == 16 +BS3_EXTERN_CMN_FAR Bs3SelFar32ToFlat32 +%endif +BS3_EXTERN_DATA16 g_Bs3TrapSetJmpCtx +BS3_EXTERN_DATA16 g_pBs3TrapSetJmpFrame +TMPL_BEGIN_TEXT + + +;; +; Sets up a one-shot set-jmp-on-trap. +; +; @uses See, applicable C calling convention. +; +BS3_PROC_BEGIN_CMN Bs3TrapSetJmp, BS3_PBC_HYBRID + BS3_CALL_CONV_PROLOG 1 + push xBP + mov xBP, xSP + push xBX +BONLY64 sub xSP, 20h + + ; + ; Save the current register context. + ; +BONLY16 push ds + BS3_LEA_MOV_WRT_RIP(xAX, BS3_DATA16_WRT(g_Bs3TrapSetJmpCtx)) + push xAX + BS3_CALL Bs3RegCtxSave, 1 + add xSP, sCB + + ; + ; Adjust the return context a little. + ; + BS3_LEA_MOV_WRT_RIP(xBX, BS3_DATA16_WRT(g_Bs3TrapSetJmpCtx)) + mov xAX, [xBP + xCB] ; The return address of this function + mov [xBX + BS3REGCTX.rip], xAX +%if TMPL_BITS == 16 + mov xAX, [xBP + xCB+2] ; The return address CS of this function. + mov [xBX + BS3REGCTX.cs], xAX +%endif + mov xAX, [xBP] + mov [xBX + BS3REGCTX.rbp], xAX + lea xAX, [xBP + xCB + cbCurRetAddr] + mov [xBX + BS3REGCTX.rsp], xAX + mov xAX, [xBP - xCB] + mov [xBX + BS3REGCTX.rbx], xAX + xor xAX, xAX + mov [xBX + BS3REGCTX.rax], xAX ; the return value. + + ; + ; Fill the trap frame return structure. + ; + push xDI +%if TMPL_BITS == 16 + push es + les di, [xBP + xCB + cbCurRetAddr] + mov cx, BS3TRAPFRAME_size / 2 + mov ax, 0faceh + rep stosw + pop es +%else + mov xDI, [xBP + xCB*2] + mov ecx, BS3TRAPFRAME_size / 4 + mov xAX, 0feedfaceh + rep stosd +%endif + pop xDI + + ; + ; Save the (flat) pointer to the trap frame return structure. + ; +%if TMPL_BITS == 16 + xor ax, ax + push word [xBP + xCB + cbCurRetAddr + 2] + push ax + push word [xBP + xCB + cbCurRetAddr] + push cs + call Bs3SelFar32ToFlat32 + add sp, 6h + mov [BS3_DATA16_WRT(g_pBs3TrapSetJmpFrame)], ax + mov [2 + BS3_DATA16_WRT(g_pBs3TrapSetJmpFrame)], dx +%else + mov xAX, [xBP + xCB*2] + mov [BS3_DATA16_WRT(g_pBs3TrapSetJmpFrame)], eax +%endif + + ; + ; Return 'true'. + ; + mov xAX, 1 +BONLY64 add xSP, 20h + pop xBX + pop xBP + BS3_CALL_CONV_EPILOG 1 + BS3_HYBRID_RET +BS3_PROC_END_CMN Bs3TrapSetJmp + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-TrapSetJmpAndRestore.c b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-TrapSetJmpAndRestore.c new file mode 100644 index 00000000..64027aa4 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-TrapSetJmpAndRestore.c @@ -0,0 +1,46 @@ +/* $Id: bs3-cmn-TrapSetJmpAndRestore.c $ */ +/** @file + * BS3Kit - Bs3TrapSetJmpAndRestore + */ + +/* + * Copyright (C) 2007-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include "bs3kit-template-header.h" + + +#undef Bs3TrapSetJmpAndRestore +BS3_CMN_DEF(void, Bs3TrapSetJmpAndRestore,(PCBS3REGCTX pCtxRestore, PBS3TRAPFRAME pTrapFrame)) +{ + if (Bs3TrapSetJmp(pTrapFrame)) + { +#if TMPL_BITS == 32 + g_uBs3TrapEipHint = pCtxRestore->rip.u32; +#endif + Bs3RegCtxRestore(pCtxRestore, BS3REGCTXRESTORE_F_NO_V86_ASSIST); + } + g_fBs3TrapNoV86Assist = false; +} + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-TrapUnsetJmp.c b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-TrapUnsetJmp.c new file mode 100644 index 00000000..921f3ed8 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-TrapUnsetJmp.c @@ -0,0 +1,48 @@ +/* $Id: bs3-cmn-TrapUnsetJmp.c $ */ +/** @file + * BS3Kit - Bs3TrapUnsetJmp + */ + +/* + * Copyright (C) 2007-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include "bs3kit-template-header.h" + + +/********************************************************************************************************************************* +* Global Variables * +*********************************************************************************************************************************/ +#ifndef DOXYGEN_RUNNING +# define g_pBs3TrapSetJmpFrame BS3_DATA_NM(g_pBs3TrapSetJmpFrame) +#endif +extern uint32_t g_pBs3TrapSetJmpFrame; + + +#undef Bs3TrapUnsetJmp +BS3_CMN_DEF(void, Bs3TrapUnsetJmp,(void)) +{ + g_pBs3TrapSetJmpFrame = 0; +} + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-UInt32Div.c b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-UInt32Div.c new file mode 100644 index 00000000..14f45d17 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-UInt32Div.c @@ -0,0 +1,40 @@ +/* $Id: bs3-cmn-UInt32Div.c $ */ +/** @file + * BS3Kit - Unsigned 32-bit division (compiler support routine helper). + */ + +/* + * Copyright (C) 2007-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include <bs3kit.h> +#include <iprt/uint32.h> + + +#undef Bs3UInt32Div +BS3_CMN_DEF(void, Bs3UInt32Div,(RTUINT32U uDividend, RTUINT32U uDivisor, RTUINT32U BS3_FAR *paQuotientReminder)) +{ + RTUInt32DivRem(&paQuotientReminder[0], &paQuotientReminder[1], &uDividend, &uDivisor); +} + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-UInt64Div.c b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-UInt64Div.c new file mode 100644 index 00000000..dd7a9b3a --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-UInt64Div.c @@ -0,0 +1,40 @@ +/* $Id: bs3-cmn-UInt64Div.c $ */ +/** @file + * BS3Kit - Unsigned 64-bit division (compiler support routine helper). + */ + +/* + * Copyright (C) 2007-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include <bs3kit.h> +#include <iprt/uint64.h> + + +#undef Bs3UInt64Div +BS3_CMN_DEF(void, Bs3UInt64Div,(RTUINT64U uDividend, RTUINT64U uDivisor, RTUINT64U BS3_FAR *paQuotientReminder)) +{ + RTUInt64DivRem(&paQuotientReminder[0], &paQuotientReminder[1], &uDividend, &uDivisor); +} + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-UtilSetFullGdtr.asm b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-UtilSetFullGdtr.asm new file mode 100644 index 00000000..aff470da --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-UtilSetFullGdtr.asm @@ -0,0 +1,185 @@ +; $Id: bs3-cmn-UtilSetFullGdtr.asm $ +;; @file +; BS3Kit - Bs3UtilSetFullGdtr +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + + +;********************************************************************************************************************************* +;* Header Files * +;********************************************************************************************************************************* +%include "bs3kit-template-header.mac" + + +;********************************************************************************************************************************* +;* External Symbols * +;********************************************************************************************************************************* +%if TMPL_BITS == 16 +BS3_EXTERN_DATA16 g_uBs3CpuDetected +%endif +%if TMPL_BITS != 64 +BS3_EXTERN_DATA16 g_bBs3CurrentMode +%endif +TMPL_BEGIN_TEXT + + + +;; +; @cproto BS3_CMN_PROTO_NOSB(void, Bs3UtilSetFullGdtr,(uint16_t cbLimit, uint64_t uBase)); +; +; @remarks Does not require 20h of parameter scratch space in 64-bit mode. +; @uses eax/rax; cbLimit on stack in 32-bit mode. +; +BS3_PROC_BEGIN_CMN Bs3UtilSetFullGdtr, BS3_PBC_HYBRID +TONLY16 inc xBP + push xBP + mov xBP, xSP + +%if TMPL_BITS == 64 + ; + ; It doesn't (currently) get any better than 64-bit mode. + ; + push rdx + mov rax, rcx + shl rax, 48 + push rax + lgdt [rsp + 6] + add rsp, 10h + + +%elif TMPL_BITS == 32 + ; + ; Move the limit up two bytes so we can use it directly. + ; + shl dword [xBP + xCB + cbCurRetAddr], 16 + + ; + ; If the system is currently running in long mode, we have to switch to + ; it in order to do the job with the highest precision. + ; + mov al, [BS3_DATA16_WRT(g_bBs3CurrentMode)] + and al, BS3_MODE_SYS_MASK + cmp al, BS3_MODE_SYS_LM + je .do_64bit + + ; 32-bit is the best we can do. +.do_32bit: + lgdt [xBP + xCB + cbCurRetAddr + 2] + jmp .return + + ; Must switch to long mode and do it there. +.do_64bit: + jmp BS3_SEL_R0_CS64:.in_64bit wrt FLAT +.in_64bit: + BS3_SET_BITS 64 + lgdt [xSP + 4 + cbCurRetAddr + 2] + push BS3_SEL_R0_CS32 + push .return wrt FLAT + o64 retf + BS3_SET_BITS 32 + + +%elif TMPL_BITS == 16 + ; + ; All options are open here, we can be in any 16-bit mode, + ; including real mode. + ; + mov al, [BS3_DATA16_WRT(g_bBs3CurrentMode)] + test al, BS3_MODE_CODE_V86 + jnz .do_v8086 + and al, BS3_MODE_SYS_MASK + cmp al, BS3_MODE_SYS_LM + je .do_64bit + cmp al, BS3_MODE_SYS_RM + je .do_16bit + cmp byte [ BS3_DATA16_WRT(g_uBs3CpuDetected)], BS3CPU_80386 + jae .do_32bit + + ; + ; We're in real mode or in 16-bit protected mode on a 286. + ; +.do_16bit: ;ba x 1 127f5 + lgdt [xBP + xCB + cbCurRetAddr] + jmp .return + + ; + ; We're in some kind of protected mode on a 386 or better. + ; +.do_32bit: + jmp dword BS3_SEL_R0_CS32:.in_32bit wrt FLAT +.in_32bit: + BS3_SET_BITS 32 + lgdt [bp + 2 + cbCurRetAddr] + jmp BS3_SEL_R0_CS16:.return wrt CGROUP16 + BS3_SET_BITS 16 + + ; + ; V8086 mode - need to switch to 32-bit kernel code to do stuff here. + ; +.do_v8086: + BS3_EXTERN_CMN Bs3SwitchTo32Bit + call Bs3SwitchTo32Bit + BS3_SET_BITS 32 + + lgdt [xSP + 2 + cbCurRetAddr] + + extern _Bs3SwitchTo16BitV86_c32 + call _Bs3SwitchTo16BitV86_c32 + BS3_SET_BITS 16 + jmp .return + + ; + ; System is in long mode, so we can switch to 64-bit mode and do the job there. + ; +.do_64bit: + push edx ; save + push ss + push 0 + push bp + BS3_EXTERN_CMN Bs3SelFar32ToFlat32NoClobber + call Bs3SelFar32ToFlat32NoClobber + add sp, 6 + shl edx, 16 + mov dx, ax + mov eax, edx ; eax = flattened ss:bp + pop edx ; restore + jmp dword BS3_SEL_R0_CS64:.in_64bit wrt FLAT +.in_64bit: + BS3_SET_BITS 64 + lgdt [rax + 2 + cbCurRetAddr] + + push BS3_SEL_R0_CS16 + push .return wrt CGROUP16 + o64 retf + BS3_SET_BITS 16 + +%else + %error "TMPL_BITS!" +%endif + +.return: + pop xBP +TONLY16 dec xBP + BS3_HYBRID_RET +BS3_PROC_END_CMN Bs3UtilSetFullGdtr + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-UtilSetFullIdtr.asm b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-UtilSetFullIdtr.asm new file mode 100644 index 00000000..8141b702 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-UtilSetFullIdtr.asm @@ -0,0 +1,185 @@ +; $Id: bs3-cmn-UtilSetFullIdtr.asm $ +;; @file +; BS3Kit - Bs3UtilSetFullIdtr +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + + +;********************************************************************************************************************************* +;* Header Files * +;********************************************************************************************************************************* +%include "bs3kit-template-header.mac" + + +;********************************************************************************************************************************* +;* External Symbols * +;********************************************************************************************************************************* +%if TMPL_BITS == 16 +BS3_EXTERN_DATA16 g_uBs3CpuDetected +%endif +%if TMPL_BITS != 64 +BS3_EXTERN_DATA16 g_bBs3CurrentMode +%endif +TMPL_BEGIN_TEXT + + + +;; +; @cproto BS3_CMN_PROTO_NOSB(void, Bs3UtilSetFullIdtr,(uint16_t cbLimit, uint64_t uBase)); +; +; @remarks Does not require 20h of parameter scratch space in 64-bit mode. +; @uses eax/rax; cbLimit on stack in 32-bit mode. +; +BS3_PROC_BEGIN_CMN Bs3UtilSetFullIdtr, BS3_PBC_HYBRID +TONLY16 inc xBP + push xBP + mov xBP, xSP + +%if TMPL_BITS == 64 + ; + ; It doesn't (currently) get any better than 64-bit mode. + ; + push rdx + mov rax, rcx + shl rax, 48 + push rax + lidt [rsp + 6] + add rsp, 10h + + +%elif TMPL_BITS == 32 + ; + ; Move the limit up two bytes so we can use it directly. + ; + shl dword [xBP + xCB + cbCurRetAddr], 16 + + ; + ; If the system is currently running in long mode, we have to switch to + ; it in order to do the job with the highest precision. + ; + mov al, [BS3_DATA16_WRT(g_bBs3CurrentMode)] + and al, BS3_MODE_SYS_MASK + cmp al, BS3_MODE_SYS_LM + je .do_64bit + + ; 32-bit is the best we can do. +.do_32bit: + lidt [xBP + xCB + cbCurRetAddr + 2] + jmp .return + + ; Must switch to long mode and do it there. +.do_64bit: + jmp BS3_SEL_R0_CS64:.in_64bit wrt FLAT +.in_64bit: + BS3_SET_BITS 64 + lidt [xSP + 4 + cbCurRetAddr + 2] + push BS3_SEL_R0_CS32 + push .return wrt FLAT + o64 retf + BS3_SET_BITS 32 + + +%elif TMPL_BITS == 16 + ; + ; All options are open here, we can be in any 16-bit mode, + ; including real mode. + ; + mov al, [BS3_DATA16_WRT(g_bBs3CurrentMode)] + test al, BS3_MODE_CODE_V86 + jnz .do_v8086 + and al, BS3_MODE_SYS_MASK + cmp al, BS3_MODE_SYS_LM + je .do_64bit + cmp al, BS3_MODE_SYS_RM + je .do_16bit + cmp byte [ BS3_DATA16_WRT(g_uBs3CpuDetected)], BS3CPU_80386 + jae .do_32bit + + ; + ; We're in real mode or in 16-bit protected mode on a 286. + ; +.do_16bit: ;ba x 1 127f5 + lidt [xBP + xCB + cbCurRetAddr] + jmp .return + + ; + ; We're in some kind of protected mode on a 386 or better. + ; +.do_32bit: + jmp dword BS3_SEL_R0_CS32:.in_32bit wrt FLAT +.in_32bit: + BS3_SET_BITS 32 + lidt [bp + 2 + cbCurRetAddr] + jmp BS3_SEL_R0_CS16:.return wrt CGROUP16 + BS3_SET_BITS 16 + + ; + ; V8086 mode - need to switch to 32-bit kernel code to do stuff here. + ; +.do_v8086: + BS3_EXTERN_CMN Bs3SwitchTo32Bit + call Bs3SwitchTo32Bit + BS3_SET_BITS 32 + + lidt [xSP + 2 + cbCurRetAddr] + + extern _Bs3SwitchTo16BitV86_c32 + call _Bs3SwitchTo16BitV86_c32 + BS3_SET_BITS 16 + jmp .return + + ; + ; System is in long mode, so we can switch to 64-bit mode and do the job there. + ; +.do_64bit: + push edx ; save + push ss + push 0 + push bp + BS3_EXTERN_CMN Bs3SelFar32ToFlat32NoClobber + call Bs3SelFar32ToFlat32NoClobber + add sp, 6 + shl edx, 16 + mov dx, ax + mov eax, edx ; eax = flattened ss:bp + pop edx ; restore + jmp dword BS3_SEL_R0_CS64:.in_64bit wrt FLAT +.in_64bit: + BS3_SET_BITS 64 + lidt [rax + 2 + cbCurRetAddr] + + push BS3_SEL_R0_CS16 + push .return wrt CGROUP16 + o64 retf + BS3_SET_BITS 16 + +%else + %error "TMPL_BITS!" +%endif + +.return: + pop xBP +TONLY16 dec xBP + BS3_HYBRID_RET +BS3_PROC_END_CMN Bs3UtilSetFullIdtr + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-hexdigits.c b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-hexdigits.c new file mode 100644 index 00000000..28cee380 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-hexdigits.c @@ -0,0 +1,32 @@ +/* $Id: bs3-cmn-hexdigits.c $ */ +/** @file + * BS3Kit - Hex digits constants. + */ + +/* + * Copyright (C) 2007-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + +#include "bs3kit-template-header.h" + + +char const g_achBs3HexDigits[16+1] = "0123456789abcdef"; +char const g_achBs3HexDigitsUpper[16+1] = "0123456789ABCDEF"; + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-instantiate-common.h b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-instantiate-common.h new file mode 100644 index 00000000..33a809f7 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-instantiate-common.h @@ -0,0 +1,204 @@ +/* $Id: bs3-cmn-instantiate-common.h $ */ +/** @file + * BS3Kit - Common template instantiator body. + */ + +/* + * Copyright (C) 2007-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + + +/* + * Instantiating common code (c16, c32, c64). + * This must be done first. + */ + +/** @def BS3_INSTANTIATING_CMN + * @ingroup grp_bs3kit_tmpl + * Indicates that we're instantiating common code (c16, c32, c64). + */ +#define BS3_INSTANTIATING_CMN + +#ifdef BS3_CMN_INSTANTIATE_FILE1 + +# define BS3_CMN_INSTANTIATE_FILE1_B <BS3_CMN_INSTANTIATE_FILE1> + +# if ARCH_BITS == 16 /* 16-bit - real mode. */ +# define TMPL_MODE BS3_MODE_RM +# include <bs3kit/bs3kit-template-header.h> +# include BS3_CMN_INSTANTIATE_FILE1_B +# include <bs3kit/bs3kit-template-footer.h> +# endif + +# if ARCH_BITS == 32 /* 32-bit - paged protected mode. */ +# define TMPL_MODE BS3_MODE_PP32 +# include <bs3kit/bs3kit-template-header.h> +# include BS3_CMN_INSTANTIATE_FILE1_B +# include <bs3kit/bs3kit-template-footer.h> +# endif + +# if ARCH_BITS == 64 /* 64-bit. */ +# define TMPL_MODE BS3_MODE_LM64 +# include <bs3kit/bs3kit-template-header.h> +# include BS3_CMN_INSTANTIATE_FILE1_B +# include <bs3kit/bs3kit-template-footer.h> +# endif + +#endif + +#undef BS3_INSTANTIATING_CMN + + +/* + * Instantiating code for each individual mode (rm, pe16, pe16_32, ...). + */ + +/** @def BS3_INSTANTIATING_MODE + * @ingroup grp_bs3kit_tmpl + * Indicates that we're instantiating mode specific code (rm, pe16, ...). + */ +#define BS3_INSTANTIATING_MODE + +#ifdef BS3_MODE_INSTANTIATE_FILE1 + +# define BS3_MODE_INSTANTIATE_FILE1_B <BS3_MODE_INSTANTIATE_FILE1> + +# if ARCH_BITS == 16 /* 16-bit */ + +# define TMPL_MODE BS3_MODE_RM +# include <bs3kit/bs3kit-template-header.h> +# include BS3_MODE_INSTANTIATE_FILE1_B +# include <bs3kit/bs3kit-template-footer.h> + +# define TMPL_MODE BS3_MODE_PE16 +# include <bs3kit/bs3kit-template-header.h> +# include BS3_MODE_INSTANTIATE_FILE1_B +# include <bs3kit/bs3kit-template-footer.h> + +# define TMPL_MODE BS3_MODE_PE16_V86 +# include <bs3kit/bs3kit-template-header.h> +# include BS3_MODE_INSTANTIATE_FILE1_B +# include <bs3kit/bs3kit-template-footer.h> + +# define TMPL_MODE BS3_MODE_PE32_16 +# include <bs3kit/bs3kit-template-header.h> +# include BS3_MODE_INSTANTIATE_FILE1_B +# include <bs3kit/bs3kit-template-footer.h> + +# define TMPL_MODE BS3_MODE_PEV86 +# include <bs3kit/bs3kit-template-header.h> +# include BS3_MODE_INSTANTIATE_FILE1_B +# include <bs3kit/bs3kit-template-footer.h> + +# define TMPL_MODE BS3_MODE_PP16 +# include <bs3kit/bs3kit-template-header.h> +# include BS3_MODE_INSTANTIATE_FILE1_B +# include <bs3kit/bs3kit-template-footer.h> + +# define TMPL_MODE BS3_MODE_PP16_V86 +# include <bs3kit/bs3kit-template-header.h> +# include BS3_MODE_INSTANTIATE_FILE1_B +# include <bs3kit/bs3kit-template-footer.h> + +# define TMPL_MODE BS3_MODE_PP32_16 +# include <bs3kit/bs3kit-template-header.h> +# include BS3_MODE_INSTANTIATE_FILE1_B +# include <bs3kit/bs3kit-template-footer.h> + +# define TMPL_MODE BS3_MODE_PPV86 +# include <bs3kit/bs3kit-template-header.h> +# include BS3_MODE_INSTANTIATE_FILE1_B +# include <bs3kit/bs3kit-template-footer.h> + +# define TMPL_MODE BS3_MODE_PAE16 +# include <bs3kit/bs3kit-template-header.h> +# include BS3_MODE_INSTANTIATE_FILE1_B +# include <bs3kit/bs3kit-template-footer.h> + +# define TMPL_MODE BS3_MODE_PAE16_V86 +# include <bs3kit/bs3kit-template-header.h> +# include BS3_MODE_INSTANTIATE_FILE1_B +# include <bs3kit/bs3kit-template-footer.h> + +# define TMPL_MODE BS3_MODE_PAE32_16 +# include <bs3kit/bs3kit-template-header.h> +# include BS3_MODE_INSTANTIATE_FILE1_B +# include <bs3kit/bs3kit-template-footer.h> + +# define TMPL_MODE BS3_MODE_PAEV86 +# include <bs3kit/bs3kit-template-header.h> +# include BS3_MODE_INSTANTIATE_FILE1_B +# include <bs3kit/bs3kit-template-footer.h> + +# define TMPL_MODE BS3_MODE_LM16 +# include <bs3kit/bs3kit-template-header.h> +# include BS3_MODE_INSTANTIATE_FILE1_B +# include <bs3kit/bs3kit-template-footer.h> + +# endif + +# if ARCH_BITS == 32 /* 32-bit */ + +# define TMPL_MODE BS3_MODE_PE16_32 +# include <bs3kit/bs3kit-template-header.h> +# include BS3_MODE_INSTANTIATE_FILE1_B +# include <bs3kit/bs3kit-template-footer.h> + +# define TMPL_MODE BS3_MODE_PE32 +# include <bs3kit/bs3kit-template-header.h> +# include BS3_MODE_INSTANTIATE_FILE1_B +# include <bs3kit/bs3kit-template-footer.h> + +# define TMPL_MODE BS3_MODE_PP16_32 +# include <bs3kit/bs3kit-template-header.h> +# include BS3_MODE_INSTANTIATE_FILE1_B +# include <bs3kit/bs3kit-template-footer.h> + +# define TMPL_MODE BS3_MODE_PP32 +# include <bs3kit/bs3kit-template-header.h> +# include BS3_MODE_INSTANTIATE_FILE1_B +# include <bs3kit/bs3kit-template-footer.h> + +# define TMPL_MODE BS3_MODE_PAE16_32 +# include <bs3kit/bs3kit-template-header.h> +# include BS3_MODE_INSTANTIATE_FILE1_B +# include <bs3kit/bs3kit-template-footer.h> + +# define TMPL_MODE BS3_MODE_PAE32 +# include <bs3kit/bs3kit-template-header.h> +# include BS3_MODE_INSTANTIATE_FILE1_B +# include <bs3kit/bs3kit-template-footer.h> + +# define TMPL_MODE BS3_MODE_LM32 +# include <bs3kit/bs3kit-template-header.h> +# include BS3_MODE_INSTANTIATE_FILE1_B +# include <bs3kit/bs3kit-template-footer.h> + +# endif + +# if ARCH_BITS == 64 /* 64-bit. */ +# define TMPL_MODE BS3_MODE_LM64 +# include <bs3kit/bs3kit-template-header.h> +# include BS3_MODE_INSTANTIATE_FILE1_B +# include <bs3kit/bs3kit-template-footer.h> +# endif + +#endif + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-instantiate-x0.c16 b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-instantiate-x0.c16 new file mode 100644 index 00000000..0af63357 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-instantiate-x0.c16 @@ -0,0 +1,29 @@ +/* $Id: bs3-cmn-instantiate-x0.c16 $ */ +/** @file + * BS3Kit - 16-bit common C template instantiator, using the BS3X0TEXT16 segment. + */ + +/* + * Copyright (C) 2007-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + +#define BS3_USE_X0_TEXT_SEG 1 +#include "bs3-cmn-instantiate-common.h" + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-instantiate-x1.c16 b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-instantiate-x1.c16 new file mode 100644 index 00000000..f737e50d --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-instantiate-x1.c16 @@ -0,0 +1,29 @@ +/* $Id: bs3-cmn-instantiate-x1.c16 $ */ +/** @file + * BS3Kit - 16-bit common C template instantiator, using the BS3X1TEXT16 segment. + */ + +/* + * Copyright (C) 2007-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + +#define BS3_USE_X1_TEXT_SEG 1 +#include "bs3-cmn-instantiate-common.h" + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-instantiate.c16 b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-instantiate.c16 new file mode 100644 index 00000000..b942f0c9 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-instantiate.c16 @@ -0,0 +1,29 @@ +/* $Id: bs3-cmn-instantiate.c16 $ */ +/** @file + * BS3Kit - 16-bit common C template instantiator. + */ + +/* + * Copyright (C) 2007-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + + +#include "bs3-cmn-instantiate-common.h" + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-instantiate.c32 b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-instantiate.c32 new file mode 100644 index 00000000..67e1486a --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-instantiate.c32 @@ -0,0 +1,29 @@ +/* $Id: bs3-cmn-instantiate.c32 $ */ +/** @file + * BS3Kit - 32-bit common C template instantiator. + */ + +/* + * Copyright (C) 2007-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + + +#include "bs3-cmn-instantiate-common.h" + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-instantiate.c64 b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-instantiate.c64 new file mode 100644 index 00000000..49b371f4 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-instantiate.c64 @@ -0,0 +1,29 @@ +/* $Id: bs3-cmn-instantiate.c64 $ */ +/** @file + * BS3Kit - 64-bit common C template instantiator. + */ + +/* + * Copyright (C) 2007-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + + +#include "bs3-cmn-instantiate-common.h" + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-memory.h b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-memory.h new file mode 100644 index 00000000..f0f315d7 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-memory.h @@ -0,0 +1,99 @@ +/* $Id: bs3-cmn-memory.h $ */ +/** @file + * BS3Kit - Internal Memory Structures, Variables and Functions. + */ + +/* + * Copyright (C) 2007-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + +#ifndef BS3KIT_INCLUDED_bs3_cmn_memory_h +#define BS3KIT_INCLUDED_bs3_cmn_memory_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include "bs3kit.h" +#include <iprt/asm.h> + +RT_C_DECLS_BEGIN; + + +typedef union BS3SLABCTLLOW +{ + BS3SLABCTL Core; + uint32_t au32Alloc[(sizeof(BS3SLABCTL) + (0xA0000 / _4K / 8) ) / 4]; +} BS3SLABCTLLOW; +#ifndef DOXYGEN_RUNNING +# define g_Bs3Mem4KLow BS3_DATA_NM(g_Bs3Mem4KLow) +#endif +extern BS3SLABCTLLOW g_Bs3Mem4KLow; + + +typedef union BS3SLABCTLUPPERTILED +{ + BS3SLABCTL Core; + uint32_t au32Alloc[(sizeof(BS3SLABCTL) + ((BS3_SEL_TILED_AREA_SIZE - _1M) / _4K / 8) ) / 4]; +} BS3SLABCTLUPPERTILED; +#ifndef DOXYGEN_RUNNING +# define g_Bs3Mem4KUpperTiled BS3_DATA_NM(g_Bs3Mem4KUpperTiled) +#endif +extern BS3SLABCTLUPPERTILED g_Bs3Mem4KUpperTiled; + + +/** The number of chunk sizes used by the slab list arrays + * (g_aBs3LowSlabLists, g_aBs3UpperTiledSlabLists, more?). */ +#define BS3_MEM_SLAB_LIST_COUNT 6 + +#ifndef DOXYGEN_RUNNING +# define g_aiBs3SlabListsByPowerOfTwo BS3_DATA_NM(g_aiBs3SlabListsByPowerOfTwo) +# define g_acbBs3SlabLists BS3_DATA_NM(g_acbBs3SlabLists) +# define g_aBs3LowSlabLists BS3_DATA_NM(g_aBs3LowSlabLists) +# define g_aBs3UpperTiledSlabLists BS3_DATA_NM(g_aBs3UpperTiledSlabLists) +# define g_cbBs3SlabCtlSizesforLists BS3_DATA_NM(g_cbBs3SlabCtlSizesforLists) +#endif +extern uint8_t const g_aiBs3SlabListsByPowerOfTwo[12]; +extern uint16_t const g_acbBs3SlabLists[BS3_MEM_SLAB_LIST_COUNT]; +extern BS3SLABHEAD g_aBs3LowSlabLists[BS3_MEM_SLAB_LIST_COUNT]; +extern BS3SLABHEAD g_aBs3UpperTiledSlabLists[BS3_MEM_SLAB_LIST_COUNT]; +extern uint16_t const g_cbBs3SlabCtlSizesforLists[BS3_MEM_SLAB_LIST_COUNT]; + + +/** + * Translates a allocation request size to a slab list index. + * + * @returns Slab list index if small request, UINT8_MAX if large. + * @param cbRequest The number of bytes requested. + */ +DECLINLINE(uint8_t) bs3MemSizeToSlabListIndex(size_t cbRequest) +{ + if (cbRequest <= g_acbBs3SlabLists[BS3_MEM_SLAB_LIST_COUNT - 1]) + { + unsigned idx = cbRequest ? ASMBitLastSetU16((uint16_t)(cbRequest - 1)) : 0; + return g_aiBs3SlabListsByPowerOfTwo[idx]; + } + return UINT8_MAX; +} + + +RT_C_DECLS_END; + +#endif /* !BS3KIT_INCLUDED_bs3_cmn_memory_h */ + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-paging.h b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-paging.h new file mode 100644 index 00000000..b7ea83fd --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-paging.h @@ -0,0 +1,59 @@ +/* $Id: bs3-cmn-paging.h $ */ +/** @file + * BS3Kit - Internal Paging Structures, Variables and Functions. + */ + +/* + * Copyright (C) 2007-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + +#ifndef BS3KIT_INCLUDED_bs3_cmn_paging_h +#define BS3KIT_INCLUDED_bs3_cmn_paging_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include "bs3kit.h" +#include <iprt/asm.h> + +RT_C_DECLS_BEGIN + +/** Root directory for page protected mode. + * UINT32_MAX if not initialized. */ +extern uint32_t g_PhysPagingRootPP; +/** Root directory pointer table for PAE mode. + * UINT32_MAX if not initialized. */ +extern uint32_t g_PhysPagingRootPAE; +/** Root table (level 4) for long mode. + * UINT32_MAX if not initialized. */ +extern uint32_t g_PhysPagingRootLM; + +#undef bs3PagingGetLegacyPte +BS3_CMN_PROTO_STUB(X86PTE BS3_FAR *, bs3PagingGetLegacyPte,(RTCCUINTXREG cr3, uint32_t uFlat, bool fUseInvlPg, int *prc)); +#undef bs3PagingGetPaePte +BS3_CMN_PROTO_STUB(X86PTEPAE BS3_FAR *, bs3PagingGetPaePte,(RTCCUINTXREG cr3, uint8_t bMode, uint64_t uFlat, + bool fUseInvlPg, int *prc)); + +RT_C_DECLS_END + +#include "bs3kit-mangling-code.h" + +#endif /* !BS3KIT_INCLUDED_bs3_cmn_paging_h */ + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-pic-data.c b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-pic-data.c new file mode 100644 index 00000000..a27d593c --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-pic-data.c @@ -0,0 +1,42 @@ +/* $Id: bs3-cmn-pic-data.c $ */ +/** @file + * BS3Kit - PIC Data. + */ + +/* + * Copyright (C) 2007-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include "bs3kit-template-header.h" +#include "bs3-cmn-pic.h" + + +/********************************************************************************************************************************* +* Global Variables * +*********************************************************************************************************************************/ +#if ARCH_BITS == 16 +/** Set by the first call to Bs3PicSetup. */ +bool g_fBs3PicConfigured = false; +#endif + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-pic.h b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-pic.h new file mode 100644 index 00000000..2889c362 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-pic.h @@ -0,0 +1,60 @@ +/* $Id: bs3-cmn-pic.h $ */ +/** @file + * BS3Kit - Internal PIC Defines, Variables and Functions. + */ + +/* + * Copyright (C) 2007-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + +#ifndef BS3KIT_INCLUDED_bs3_cmn_pic_h +#define BS3KIT_INCLUDED_bs3_cmn_pic_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include "bs3kit.h" + + +/** The master PIC port (base). */ +#define BS3_PIC_PORT_MASTER UINT8_C(0x20) +/** The slave PIC port (base). */ +#define BS3_PIC_PORT_SLAVE UINT8_C(0xa0) + +/** The init command. */ +#define BS3_PIC_CMD_INIT UINT8_C(0x10) +/** 4th init step option for the init command. */ +#define BS3_PIC_CMD_INIT_F_4STEP UINT8_C(0x01) + +/** Auto end of interrupt flag for the 4th init step. */ +#define BS3_PIC_I4_F_AUTO_EOI UINT8_C(0x01) + + +RT_C_DECLS_BEGIN + +extern bool g_fBs3PicConfigured; + +RT_C_DECLS_END + + +#include "bs3kit-mangling-code.h" + +#endif /* !BS3KIT_INCLUDED_bs3_cmn_pic_h */ + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-pit.c b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-pit.c new file mode 100644 index 00000000..910da6b8 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-pit.c @@ -0,0 +1,156 @@ +/* $Id: bs3-cmn-pit.c $ */ +/** @file + * BS3Kit - PIT Setup and Disable code. + */ + +/* + * Copyright (C) 2007-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include "bs3kit-template-header.h" +#include <iprt/asm-amd64-x86.h> + + +/********************************************************************************************************************************* +* Defined Constants And Macros * +*********************************************************************************************************************************/ +#define BS3_PIT_PORT_CMD 0x43 +#define BS3_PIT_PORT_CH0_DATA 0x40 +#define BS3_PIT_HZ UINT32_C(1193182) + + +/********************************************************************************************************************************* +* External Symbols * +*********************************************************************************************************************************/ +extern FNBS3TRAPHANDLER16 bs3PitIrqHandler_c16; +extern FNBS3TRAPHANDLER32 bs3PitIrqHandler_c32; +extern FNBS3TRAPHANDLER64 bs3PitIrqHandler_c64; + + +#undef Bs3PitSetupAndEnablePeriodTimer +BS3_CMN_DEF(void, Bs3PitSetupAndEnablePeriodTimer,(uint16_t cHzDesired)) +{ + RTCCUINTREG fSaved; + uint16_t cCount; + uint16_t cMsInterval; + uint32_t cNsInterval; + + /* + * Disable the PIT and make sure we've configured the IRQ handlers. + */ + Bs3PitDisable(); + Bs3PicSetup(); + Bs3TrapSetHandlerEx(0x70, bs3PitIrqHandler_c16, bs3PitIrqHandler_c32, bs3PitIrqHandler_c64); + + /* + * Calculate an interval. + */ + if (cHzDesired <= 18) + { + cCount = 0; /* 1193182 / 65536 = 18.206512451171875 Hz */ + cHzDesired = 18; + cNsInterval = UINT32_C(54925401); /* 65536 / 1193182 = 0.054925401154224586022920225078823 seconds */ + cMsInterval = 55; + } + else + { + cCount = BS3_PIT_HZ / cHzDesired; + cHzDesired = BS3_PIT_HZ / cCount; + /* 1s/1193182 = 0.000 000 838 095 110 38550698887512550474278 */ +#if ARCH_BITS == 64 + cNsInterval = cCount * UINT64_C(838095110) / 1000000; +#elif ARCH_BITS == 32 + cNsInterval = cCount * UINT32_C(8381) / 10; +#else + cNsInterval = cCount * 838; +#endif + if (cCount <= 1194) + cMsInterval = 1; /* Must not be zero! */ + else + cMsInterval = cCount / 1194; + } + + + /* + * Do the reprogramming. + */ + fSaved = ASMIntDisableFlags(); + ASMOutU8(BS3_PIT_PORT_CMD, + (0 << 6) /* select: channel 0 */ + | (3 << 4) /* access mode: lobyte/hibyte */ + | (2 << 1) /* operation: Mode 2 */ + | 0 /* binary mode */ + ); + ASMOutU8(BS3_PIT_PORT_CH0_DATA, (uint8_t)cCount); + ASMOutU8(BS3_PIT_PORT_CH0_DATA, (uint8_t)(cCount >> 8)); + + g_cBs3PitIntervalNs = cNsInterval; + g_cBs3PitIntervalHz = cHzDesired; + g_cBs3PitIntervalMs = cMsInterval; + + Bs3PicUpdateMask(UINT16_C(0xfffe), 0); + + ASMSetFlags(fSaved); +} + + +#undef Bs3PitDisable +BS3_CMN_DEF(void, Bs3PitDisable,(void)) +{ + if (g_cBs3PitIntervalMs != 0) + { + RTCCUINTREG fSaved = ASMIntDisableFlags(); + + /* + * Not entirely sure what's the best way to do this, but let's try reprogram + * it to a no-reload mode like 0 and set the count to 1. + */ + g_cBs3PitIntervalMs = 0; + ASMOutU8(BS3_PIT_PORT_CMD, + (0 << 6) /* select: channel 0 */ + | (1 << 4) /* access mode: lobyte */ + | (0 << 1) /* operation: Mode 0 */ + | 0 /* binary mode */ + ); + ASMOutU8(BS3_PIT_PORT_CH0_DATA, (uint8_t)1); + + /* + * Then mask the PIT IRQ on the PIC. + */ + Bs3PicUpdateMask(UINT16_C(0xffff), 1); + + ASMSetFlags(fSaved); + } + + /* + * Reset all the values. + */ + g_cBs3PitNs = 0; + g_cBs3PitMs = 0; + g_cBs3PitTicks = 0; + g_cBs3PitIntervalNs = 0; + g_cBs3PitIntervalMs = 0; + g_cBs3PitIntervalHz = 0; +} + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-test.h b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-test.h new file mode 100644 index 00000000..d2612fb6 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-test.h @@ -0,0 +1,169 @@ +/* $Id: bs3-cmn-test.h $ */ +/** @file + * BS3Kit - Bs3Test internal header. + */ + +/* + * Copyright (C) 2007-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + +#ifndef BS3KIT_INCLUDED_bs3_cmn_test_h +#define BS3KIT_INCLUDED_bs3_cmn_test_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include "bs3kit.h" +#include <VBox/VMMDevTesting.h> + + +/** Indicates whether the VMMDev is operational. */ +#ifndef DOXYGEN_RUNNING +# define g_fbBs3VMMDevTesting BS3_DATA_NM(g_fbBs3VMMDevTesting) +#endif +extern bool g_fbBs3VMMDevTesting; + +/** The number of tests that have failed. */ +#ifndef DOXYGEN_RUNNING +# define g_cusBs3TestErrors BS3_DATA_NM(g_cusBs3TestErrors) +#endif +extern uint16_t g_cusBs3TestErrors; + +/** The start error count of the current subtest. */ +#ifndef DOXYGEN_RUNNING +# define g_cusBs3SubTestAtErrors BS3_DATA_NM(g_cusBs3SubTestAtErrors) +#endif +extern uint16_t g_cusBs3SubTestAtErrors; + +/** Whether we've reported the sub-test result or not. */ +#ifndef DOXYGEN_RUNNING +# define g_fbBs3SubTestReported BS3_DATA_NM(g_fbBs3SubTestReported) +#endif +extern bool g_fbBs3SubTestReported; +/** Whether the sub-test has been skipped or not. */ +#ifndef DOXYGEN_RUNNING +# define g_fbBs3SubTestSkipped BS3_DATA_NM(g_fbBs3SubTestSkipped) +#endif +extern bool g_fbBs3SubTestSkipped; + +/** The number of sub tests. */ +#ifndef DOXYGEN_RUNNING +# define g_cusBs3SubTests BS3_DATA_NM(g_cusBs3SubTests) +#endif +extern uint16_t g_cusBs3SubTests; + +/** The number of sub tests that failed. */ +#ifndef DOXYGEN_RUNNING +# define g_cusBs3SubTestsFailed BS3_DATA_NM(g_cusBs3SubTestsFailed) +#endif +extern uint16_t g_cusBs3SubTestsFailed; + +/** VMMDEV_TESTING_UNIT_XXX -> string */ +#ifndef DOXYGEN_RUNNING +# define g_aszBs3TestUnitNames BS3_DATA_NM(g_aszBs3TestUnitNames) +#endif +extern char const g_aszBs3TestUnitNames[][16]; + +/** The test name. */ +extern const char BS3_FAR *g_pszBs3Test_c16; +extern const char *g_pszBs3Test_c32; +extern const char *g_pszBs3Test_c64; + +/** The subtest name. */ +#ifndef DOXYGEN_RUNNING +# define g_szBs3SubTest BS3_DATA_NM(g_szBs3SubTest) +#endif +extern char g_szBs3SubTest[64]; + + +/** + * Sends a command to VMMDev followed by a single string. + * + * If the VMMDev is not present or is not being used, this function will + * do nothing. + * + * @param uCmd The command. + * @param pszString The string. + */ +#ifndef DOXYGEN_RUNNING +# define bs3TestSendCmdWithStr BS3_CMN_NM(bs3TestSendCmdWithStr) +#endif +BS3_DECL(void) bs3TestSendCmdWithStr(uint32_t uCmd, const char BS3_FAR *pszString); + +/** + * Sends a command to VMMDev followed by a 32-bit unsigned integer value. + * + * If the VMMDev is not present or is not being used, this function will + * do nothing. + * + * @param uCmd The command. + * @param uValue The value. + */ +#ifndef DOXYGEN_RUNNING +# define bs3TestSendCmdWithU32 BS3_CMN_NM(bs3TestSendCmdWithU32) +#endif +BS3_DECL(void) bs3TestSendCmdWithU32(uint32_t uCmd, uint32_t uValue); + +/** + * Checks if the VMMDev is configured for testing. + * + * @returns true / false. + */ +#ifndef DOXYGEN_RUNNING +# define bs3TestIsVmmDevTestingPresent BS3_CMN_NM(bs3TestIsVmmDevTestingPresent) +#endif +BS3_DECL(bool) bs3TestIsVmmDevTestingPresent(void); + +/** + * Similar to rtTestSubCleanup. + */ +#ifndef DOXYGEN_RUNNING +# define bs3TestSubCleanup BS3_CMN_NM(bs3TestSubCleanup) +#endif +BS3_DECL(void) bs3TestSubCleanup(void); + +/** + * @callback_method_impl{FNBS3STRFORMATOUTPUT, + * Used by Bs3TestFailedV and Bs3TestSkippedV. + * + * The @a pvUser parameter must point a BS3TESTFAILEDBUF structure. } + */ +#ifndef DOXYGEN_RUNNING +# define bs3TestFailedStrOutput BS3_CMN_NM(bs3TestFailedStrOutput) +#endif +BS3_DECL_CALLBACK(size_t) bs3TestFailedStrOutput(char ch, void BS3_FAR *pvUser); + +/** + * Output buffering for bs3TestFailedStrOutput. + */ +typedef struct BS3TESTFAILEDBUF +{ + /** Initialize to false. */ + bool fNewLine; + /** Initialize to zero. */ + uint8_t cchBuf; + /** Buffer, uninitialized. */ + char achBuf[128]; +} BS3TESTFAILEDBUF; +/** Pointer to a bs3TestFailedStrOutput buffer. */ +typedef BS3TESTFAILEDBUF BS3_FAR *PBS3TESTFAILEDBUF; + +#endif /* !BS3KIT_INCLUDED_bs3_cmn_test_h */ + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-first-common.mac b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-first-common.mac new file mode 100644 index 00000000..500477ff --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-first-common.mac @@ -0,0 +1,271 @@ +; $Id: bs3-first-common.mac $ +;; @file +; BS3Kit - First Object, common stuff. +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + + +%define BS3_BEGIN_TEXT16_WITHOUT_GROUP +%define BS3_BEGIN_DATA16_WITHOUT_GROUP +%define BS3_BEGIN_RMTEXT16_WITHOUT_GROUP +%define BS3_BEGIN_X0TEXT16_WITHOUT_GROUP +%define BS3_BEGIN_X1TEXT16_WITHOUT_GROUP + +%include "bs3kit.mac" + + +; +; +; Define all the segments and their grouping, just to get that right once at +; the start of everything. +; +; + +; +; 16-bit text +; +%ifndef BS3_IS_DOS_EXE +BS3_BEGIN_TEXT16 +%else +section BEGTEXT align=2 CLASS=BS3CLASS16CODE PUBLIC USE16 +BS3_BEGIN_TEXT16 +section BEGTEXT +%endif +BS3_GLOBAL_DATA Bs3Text16_StartOfSegment, 0 + +; Entry point with eye-catcher. +GLOBALNAME start +global __ImageBase ; for MS compiler - must be first! +__ImageBase: +global ___begtext ; for DOS EXEs (causes harmless duplicate symbol warning) +___begtext: +%ifndef BS3_IS_DOS_EXE + jmp .after_eye_catcher +%else + int3 + jmp __ImageBase +%endif + db 10,13,'eye-catcher: BS3TEXT16',10,13 +BS3_BEGIN_TEXT16 +.after_eye_catcher: + +section _TEXT align=2 CLASS=BS3CLASS16CODE PUBLIC USE16 +section BS3TEXT16_NEARSTUBS align=1 CLASS=BS3CLASS16CODE PUBLIC USE16 +section BS3TEXT16_FARSTUBS align=1 CLASS=BS3CLASS16CODE PUBLIC USE16 +section BS3TEXT16_END align=1 CLASS=BS3CLASS16CODE PUBLIC USE16 + +BS3_GLOBAL_DATA Bs3Text16_EndOfSegment, 0 + +%ifndef BS3_IS_DOS_EXE +GROUP CGROUP16 BS3TEXT16 _TEXT BS3TEXT16_NEARSTUBS BS3TEXT16_FARSTUBS BS3TEXT16_END +%else +GROUP CGROUP16 BEGTEXT BS3TEXT16 _TEXT BS3TEXT16_NEARSTUBS BS3TEXT16_FARSTUBS BS3TEXT16_END +%endif + + +; +; 16-bit data +; +BS3_BEGIN_DATA16 +BS3_GLOBAL_DATA Bs3Data16_StartOfSegment, 0 + db 10,13,'eye-catcher: BS3DATA16',10,13 + +ALIGNDATA(16) +BS3_GLOBAL_DATA Bs3Data16_Size, 4 + dd BS3_DATA_NM(Bs3Data16_EndOfSegment) wrt BS3KIT_GRPNM_DATA16 +BS3_GLOBAL_DATA Bs3Data16Thru64Text32And64_TotalSize, 4 + dd BS3_DATA_NM(Bs3Data64_EndOfSegment) wrt BS3KIT_GRPNM_DATA16 +BS3_GLOBAL_DATA Bs3TotalImageSize, 4 + dd BS3_DATA_NM(Bs3Text64_EndOfSegment) wrt CGROUP16 ; ASSUMES TEXT64 is last. + +BS3_GLOBAL_DATA Bs3Text16_Size, 2 + dw BS3_DATA_NM(Bs3Text16_EndOfSegment) wrt CGROUP16 +BS3_GLOBAL_DATA Bs3RmText16_Size, 2 + dw BS3_DATA_NM(Bs3RmText16_EndOfSegment) wrt BS3GROUPRMTEXT16 +BS3_GLOBAL_DATA Bs3X0Text16_Size, 2 + dw BS3_DATA_NM(Bs3X0Text16_EndOfSegment) wrt BS3GROUPX0TEXT16 +BS3_GLOBAL_DATA Bs3X1Text16_Size, 2 + dw BS3_DATA_NM(Bs3X1Text16_EndOfSegment) wrt BS3GROUPX1TEXT16 + +BS3_GLOBAL_DATA Bs3RmText16_FlatAddr, 4 + dd BS3_DATA_NM(Bs3RmText16_StartOfSegment) wrt BS3FLAT +BS3_GLOBAL_DATA Bs3X0Text16_FlatAddr, 4 + dd BS3_DATA_NM(Bs3X0Text16_StartOfSegment) wrt BS3FLAT +BS3_GLOBAL_DATA Bs3X1Text16_FlatAddr, 4 + dd BS3_DATA_NM(Bs3X1Text16_StartOfSegment) wrt BS3FLAT + +section BS3DATA16CONST align=2 CLASS=BS3KIT_CLASS_DATA16 PUBLIC USE16 +section BS3DATA16CONST2 align=2 CLASS=BS3KIT_CLASS_DATA16 PUBLIC USE16 +section BS3DATA16_DATA align=2 CLASS=BS3KIT_CLASS_DATA16 PUBLIC USE16 +%ifdef BS3_IS_DOS_EXE +section _NULL align=16 CLASS=BEGDATA PUBLIC USE16 +section _AFTERNULL align=2 CLASS=BEGDATA PUBLIC USE16 +%endif +section CONST align=2 CLASS=DATA PUBLIC USE16 +section CONST2 align=2 CLASS=DATA PUBLIC USE16 +section _DATA align=2 CLASS=DATA PUBLIC USE16 +%ifdef BS3_IS_DOS_EXE +section XIB align=1 CLASS=DATA PUBLIC USE16 +section XI align=1 CLASS=DATA PUBLIC USE16 +section XIE align=1 CLASS=DATA PUBLIC USE16 +section YIB align=1 CLASS=DATA PUBLIC USE16 +section YI align=1 CLASS=DATA PUBLIC USE16 +section YIE align=1 CLASS=DATA PUBLIC USE16 +%endif +section STRINGS align=2 CLASS=DATA PUBLIC USE16 +section DATA align=2 CLASS=DATA PUBLIC USE16 +section _BSS align=2 CLASS=BS3KIT_CLASS_BSS16 PUBLIC USE16 +section BSS align=2 CLASS=BS3KIT_CLASS_BSS16 PUBLIC USE16 +%ifdef BS3_IS_DOS_EXE +section STACK align=16 CLASS=STACK STACK USE16 +%endif +section BS3DATA16_END align=2 CLASS=BS3KIT_CLASS_BSS16 PUBLIC USE16 + +BS3_GLOBAL_DATA Bs3Data16_EndOfSegment, 0 + +%ifndef BS3_IS_DOS_EXE +GROUP BS3KIT_GRPNM_DATA16 BS3DATA16 BS3DATA16_DATA _DATA DATA BS3DATA16CONST CONST BS3DATA16CONST2 CONST2 STRINGS _BSS BSS BS3DATA16_END +%else +GROUP BS3KIT_GRPNM_DATA16 \ + _NULL _AFTERNULL \ + CONST BS3DATA16CONST CONST2 BS3DATA16CONST2 _DATA XIB XI XIE YIB YI YIE STRINGS DATA BS3DATA16 BS3DATA16_DATA \ + _BSS BSS BS3DATA16_END \ + STACK +%endif + +; +; 16-bit real-mode text +; +section BS3RMTEXT16_START align=16 CLASS=BS3CLASS16RMCODE PUBLIC USE16 +BS3_GLOBAL_DATA Bs3RmText16_StartOfSegment, 0 + ;db 10,13,'eye-catcher: BS3RMTEXT16',10,13 - messes up switch in C code. Alt. is fConvertFixupp VBoxBs3ObjConverter.cpp. +BS3_BEGIN_RMTEXT16 +section BS3RMTEXT16_END align=1 CLASS=BS3CLASS16RMCODE PUBLIC USE16 +BS3_GLOBAL_DATA Bs3RmText16_EndOfSegment, 0 +GROUP BS3GROUPRMTEXT16 BS3RMTEXT16_START BS3RMTEXT16 BS3RMTEXT16_END + + +; +; 16-bit extra text segment #0. +; +section BS3X0TEXT16_START align=16 CLASS=BS3CLASS16X0CODE PUBLIC USE16 +BS3_GLOBAL_DATA Bs3X0Text16_StartOfSegment, 0 + ;db 10,13,'eye-catcher: BS3X0TEXT16',10,13 - messes up switch in C code. Alt. is fConvertFixupp VBoxBs3ObjConverter.cpp. +BS3_BEGIN_X0TEXT16 4 +section BS3X0TEXT16_END align=16 CLASS=BS3CLASS16X0CODE PUBLIC USE16 +BS3_GLOBAL_DATA Bs3X0Text16_EndOfSegment, 0 +GROUP BS3GROUPX0TEXT16 BS3X0TEXT16_START BS3X0TEXT16 BS3X0TEXT16_END + + +; +; 16-bit extra text segment #1. +; +section BS3X1TEXT16_START align=16 CLASS=BS3CLASS16X1CODE PUBLIC USE16 +BS3_GLOBAL_DATA Bs3X1Text16_StartOfSegment, 0 + ;db 10,13,'eye-catcher: BS3X1TEXT16',10,13 - messes up switch in C code. Alt. is fConvertFixupp VBoxBs3ObjConverter.cpp. +BS3_BEGIN_X1TEXT16 4 +section BS3X1TEXT16_END align=16 CLASS=BS3CLASS16X1CODE PUBLIC USE16 +BS3_GLOBAL_DATA Bs3X1Text16_EndOfSegment, 0 +GROUP BS3GROUPX1TEXT16 BS3X1TEXT16_START BS3X1TEXT16 BS3X1TEXT16_END + + +; +; 32-bit text +; +BS3_BEGIN_TEXT32 +BS3_GLOBAL_DATA Bs3Text32_StartOfSegment, 0 + db 10,13,'eye-catcher: BS3TEXT32',10,13 +section BS3TEXT32_END align=1 CLASS=BS3CLASS32CODE PUBLIC USE32 FLAT +BS3_GLOBAL_DATA Bs3Text32_EndOfSegment, 0 + + +; +; This is a hack to separate the 32-bit and 64-bit text segments when linking, +; such that they don't share the same base frame because they're both assigned +; to the AUTO group by the linker. +; +section BS3SEPARATE32AND64BITCODE align=16 CLASS=BS3CLASSSEPARATE32AND64BITCODE PUBLIC USE16 +BS3_GLOBAL_DATA Bs3Separate32And64BitCode_StartOfSegment, 0 + db 10,13,'eye-catcher: 32-64 wedge',10,13 +section BS3SEPARATE32AND64BITCODE_END align=16 CLASS=BS3CLASSSEPARATE32AND64BITCODE PUBLIC USE16 +BS3_GLOBAL_DATA Bs3Separate32And64BitCode_EndOfSegment, 0 +GROUP BS3SEPARATE32AND64BITCODEGROUP BS3SEPARATE32AND64BITCODE BS3SEPARATE32AND64BITCODE_END + + +; +; 64-bit text +; +BS3_BEGIN_TEXT64 +BS3_GLOBAL_DATA Bs3Text64_StartOfSegment, 0 + db 10,13,'eye-catcher: BS3TEXT64',10,13 +section BS3TEXT64_END align=1 CLASS=BS3CLASS64CODE PUBLIC USE32 FLAT +BS3_GLOBAL_DATA Bs3Text64_EndOfSegment, 0 + + +; +; FAR_DATA segment in DOS EXEs should be near the other FAR_DATA class segments. +; +%ifdef BS3_IS_DOS_EXE +section FAR_DATA align=1 CLASS=FAR_DATA PUBLIC USE16 +%endif + +; +; 32-bit data +; +BS3_BEGIN_DATA32 +BS3_GLOBAL_DATA Bs3Data32_StartOfSegment, 0 + db 10,13,'eye-catcher: BS3DATA32',10,13 +section BS3DATA32CONST align=16 CLASS=FAR_DATA PUBLIC USE32 +section BS3DATA32CONST2 align=16 CLASS=FAR_DATA PUBLIC USE32 +section BS3DATA32_DATA align=16 CLASS=FAR_DATA PUBLIC USE32 +section BS3DATA32_BSS align=16 CLASS=FAR_DATA PUBLIC USE32 +section BS3DATA32_END align=16 CLASS=FAR_DATA PUBLIC USE32 +BS3_GLOBAL_DATA Bs3Data32_EndOfSegment, 0 +GROUP BS3DATA32_GROUP BS3DATA32 BS3DATA32_DATA BS3DATA32CONST BS3DATA32CONST2 BS3DATA32_BSS BS3DATA32_END + +; +; 64-bit data +; +BS3_BEGIN_DATA64 +BS3_GLOBAL_DATA Bs3Data64_StartOfSegment, 0 + db 10,13,'eye-catcher: BS3DATA64',10,13 +section BS3DATA64CONST align=16 CLASS=FAR_DATA PUBLIC USE32 +section BS3DATA64_BSS align=16 CLASS=FAR_DATA PUBLIC USE32 +section BS3DATA64_END align=16 CLASS=FAR_DATA PUBLIC USE32 +BS3_GLOBAL_DATA Bs3Data64_EndOfSegment, 0 +GROUP BS3DATA64_GROUP BS3DATA64 BS3DATA64CONST BS3DATA64_BSS BS3DATA64_END + + +; +; 16-bit accessible system data. +; No need to do anything here. +; +BS3_BEGIN_SYSTEM16 + + +; +; Switch back to the 16-bit code segment and the startup code. +; +BS3_BEGIN_TEXT16 +BS3_GLOBAL_NAME_EX Bs3KitEntryPoint, function, 0 + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-first-dosexe.asm b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-first-dosexe.asm new file mode 100644 index 00000000..d871dbb9 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-first-dosexe.asm @@ -0,0 +1,33 @@ +; $Id: bs3-first-dosexe.asm $ +;; @file +; BS3Kit - First Object for DOS executables, defines segments only. +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + + +; +; Segment defs, grouping and related variables. +; Defines the entry point 'start' as well, leaving us in BS3TEXT16. +; +%include "bs3-first-common.mac" + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-first-init-all-pe32.asm b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-first-init-all-pe32.asm new file mode 100644 index 00000000..015f49a5 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-first-init-all-pe32.asm @@ -0,0 +1,59 @@ +; $Id: bs3-first-init-all-pe32.asm $ +;; @file +; BS3Kit - First Object, calling 32-bit protected mode main() after full init. +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + + +; +; Segment defs, grouping and related variables. +; Defines the entry point 'start' as well, leaving us in BS3TEXT16. +; +%include "bs3-first-common.mac" + +extern NAME(Bs3InitAll_rm) +extern NAME(Bs3SwitchToPE32_rm) + +;; Entry point. + push word 0 ; zero return address. + push word 0 ; zero caller BP + mov bp, sp + + ; + ; Init all while we're in real mode. + ; + mov ax, BS3_SEL_DATA16 + mov es, ax + mov ds, ax + call NAME(Bs3InitAll_rm) + + ; + ; Switch to 32-bit protected mode and call main. + ; + call NAME(Bs3SwitchToPE32_rm) + BS3_SET_BITS 32 + call _Main_pe32 +extern _Main_pe32 +BS3_EXTERN_CMN Bs3Shutdown + call Bs3Shutdown + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-first-init-all-pp32.asm b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-first-init-all-pp32.asm new file mode 100644 index 00000000..e6f40938 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-first-init-all-pp32.asm @@ -0,0 +1,59 @@ +; $Id: bs3-first-init-all-pp32.asm $ +;; @file +; BS3Kit - First Object, calling 32-bit paged protected mode main() after full init. +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + + +; +; Segment defs, grouping and related variables. +; Defines the entry point 'start' as well, leaving us in BS3TEXT16. +; +%include "bs3-first-common.mac" + +extern NAME(Bs3InitAll_rm) +extern NAME(Bs3SwitchToPP32_rm) + +;; Entry point. + push word 0 ; zero return address. + push word 0 ; zero caller BP + mov bp, sp + + ; + ; Init all while we're in real mode. + ; + mov ax, BS3_SEL_DATA16 + mov es, ax + mov ds, ax + call NAME(Bs3InitAll_rm) + + ; + ; Switch to 32-bit protected mode and call main. + ; + call NAME(Bs3SwitchToPP32_rm) + BS3_SET_BITS 32 + call _Main_pp32 +extern _Main_pp32 +BS3_EXTERN_CMN Bs3Shutdown + call Bs3Shutdown + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-first-pe16.asm b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-first-pe16.asm new file mode 100644 index 00000000..e950cd5b --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-first-pe16.asm @@ -0,0 +1,95 @@ +; $Id: bs3-first-pe16.asm $ +;; @file +; BS3Kit - First Object, calling 16-bit protected-mode main(). +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + + +;********************************************************************************************************************************* +;* Header Files * +;********************************************************************************************************************************* + +; +; Segment defs, grouping and related variables. +; Defines the entry point 'start' as well, leaving us in BS3TEXT16. +; +%include "bs3-first-common.mac" + + +;********************************************************************************************************************************* +;* External Symbols * +;********************************************************************************************************************************* +BS3_BEGIN_DATA16 + +BS3_BEGIN_RMTEXT16 +extern _Bs3CpuDetect_rm_far +extern _Bs3InitMemory_rm_far + +BS3_BEGIN_TEXT16 +BS3_EXTERN_CMN Bs3PicMaskAll +BS3_EXTERN_CMN Bs3Trap16Init +extern _Bs3SwitchToPE16_rm +extern _Main_pe16 +BS3_EXTERN_CMN Bs3Shutdown + + +BS3_BEGIN_TEXT16 + ; + ; Zero return address and zero caller BP. + ; + xor ax, ax + push ax + push ax + mov bp, sp + + ; + ; Load DS and ES with data selectors. + ; + mov ax, BS3KIT_GRPNM_DATA16 + mov ds, ax + mov es, ax + + + ; + ; Make sure interrupts are disabled as we cannot (don't want to) service + ; BIOS interrupts once we switch mode. + ; + cli + call Bs3PicMaskAll + + ; + ; Initialize 16-bit protected mode. + ; + call far _Bs3CpuDetect_rm_far + call far _Bs3InitMemory_rm_far + call Bs3Trap16Init + + ; + ; Switch to PE16 and call main. + ; + call _Bs3SwitchToPE16_rm + call _Main_pe16 + + ; Try shutdown if it returns. + call Bs3Shutdown + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-first-rm.asm b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-first-rm.asm new file mode 100644 index 00000000..a2e27232 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-first-rm.asm @@ -0,0 +1,49 @@ +; $Id: bs3-first-rm.asm $ +;; @file +; BS3Kit - First Object, calling real-mode main(). +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + + +; +; Segment defs, grouping and related variables. +; Defines the entry point 'start' as well, leaving us in BS3TEXT16. +; +%include "bs3-first-common.mac" + + +EXTERN Main_rm +BS3_EXTERN_CMN Bs3Shutdown + push word 0 ; zero return address. + push word 0 ; zero caller BP + mov bp, sp + + ; + ; Nothing to init here, just call main and shutdown if it returns. + ; + mov ax, BS3_SEL_DATA16 + mov es, ax + mov ds, ax + call NAME(Main_rm) + call Bs3Shutdown + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-CpuDetect.asm b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-CpuDetect.asm new file mode 100644 index 00000000..0ccfbf80 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-CpuDetect.asm @@ -0,0 +1,337 @@ +; $Id: bs3-mode-CpuDetect.asm $ +;; @file +; BS3Kit - Bs3CpuDetect +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + +%include "bs3kit-template-header.mac" + +BS3_EXTERN_DATA16 g_uBs3CpuDetected + + +;; +; Rough CPU detection, mainly for detecting really old CPUs. +; +; A Bs3CpuDetectEx can be added if this is insufficient. +; +; @returns BS3CPU_xxx in xAX. +; @cproto BS3_DECL(BS3CPU) Bs3CpuDetect(void); +; +; @uses xAX. +; +; @remarks ASSUMES we're in ring-0 when not in some kind of real mode. +; +; @note We put the real mode version of this code in the RMTEXT16 segment +; to save space elsewhere. We generate a far call stub that goes +; to the right segment. +; +%if TMPL_MODE == BS3_MODE_RM +BS3_BEGIN_RMTEXT16 +BS3_PROC_BEGIN_MODE Bs3CpuDetect, BS3_PBC_FAR +%else +TMPL_BEGIN_TEXT +BS3_PROC_BEGIN_MODE Bs3CpuDetect, BS3_PBC_HYBRID +%endif +CPU 8086 + push xBP + mov xBP, xSP + pushf ; xBP - xCB*1 + push xCX ; xBP - xCB*2 + push xDX ; xBP - xCB*3 + push xBX ; xBP - xCB*4 + sub xSP, 20h ; xBP - xCB*4 - 20h + +%ifndef TMPL_CMN_PAGING + %ifdef TMPL_RM + %if 1 ; this is simpler + ; + ; FLAGS bits 15:12 are always set on 8086, 8088, V20, V30, 80186, and + ; 80188. FLAGS bit 15 is always zero on 286+, whereas bit 14 is NT and + ; bits 13:12 are IOPL. + ; + test byte [xBP - xCB + 1], 80h ; Top byte of saved flags. + jz .286plus + %else + ; + ; When executing 'PUSH SP' the 8086, 8088, V20, V30, 80186, and 80188 + ; should be pushing the updated SP value instead of the initial one. + ; + push xSP + pop xAX + cmp xAX, xSP + je .286plus + %endif + + ; + ; Older than 286. + ; + ; Detect 8086/8088/V20/V30 vs. 80186/80188 by checking for pre 80186 + ; shift behavior. the 80186/188 and later will mask the CL value according + ; to the width of the destination register, whereas 8086/88 and V20/30 will + ; perform the exact number of shifts specified. + ; + mov cl, 20h ; Shift count; 80186/88 and later will mask this by 0x1f (or 0xf)? + mov dx, 7fh + shl dx, cl + cmp dx, 7fh ; If no change, this is a 80186/88. + mov xAX, BS3CPU_80186 + je .return + + ; + ; Detect 8086/88 vs V20/30 by exploiting undocumented POP CS encoding + ; that was redefined on V20/30 to SET1. + ; + xor ax, ax ; clear + push cs + db 0fh ; 8086/88: pop cs V20/30: set1 bl,cl + db 14h, 3ch ; 8086/88: add al, 3ch + ; 8086/88: al = 3ch V20/30: al = 0, cs on stack, bl modified. + cmp al, 3ch + jne .is_v20_or_v30 + mov xAX, BS3CPU_8086 + jmp .return + +.is_v20_or_v30: + pop xCX ; unclaimed CS + mov xAX, BS3CPU_V20 + jmp .return + + %endif ; TMPL_RM + +CPU 286 +.286plus: + ; + ; The 4th bit of the machine status word / CR0 indicates the precense + ; of a 80387 or later co-processor (a 80287+80386 => ET=0). 486 and + ; later should be hardcoding this to 1, according to the documentation + ; (need to test on 486SX). The initial idea here then would be to + ; assume 386+ if ET=1. + ; + ; The second idea was to check whether any reserved bits are set, + ; because the 286 here has bits 4 thru 15 all set. Unfortunately, it + ; turned out the 386SX and AMD 486DX-40 also sets bits 4 thru 15 when + ; using SMSW. So, nothing conclusive to distinguish 386 from 286, but + ; we've probably got a safe 486+ detection here. + ; + ;; @todo check if LOADALL can set any of the reserved bits on a 286 or 386. + smsw ax + test ax, ~(X86_CR0_PE | X86_CR0_MP | X86_CR0_EM | X86_CR0_TS | X86_CR0_ET | X86_CR0_NE) + jz .486plus + + ; + ; The 286 stores 0xff in the high byte of the SIDT and SGDT base + ; address (since it only did 24-bit addressing and the top 8-bit was + ; reserved for the 386). ASSUMES low IDT (which is the case for BS3Kit). + ; + sidt [xBP - xCB*4 - 20h] + cmp byte [xBP - xCB*4 - 20h + 2 + 3], 0ffh + jne .386plus + + %if 0 + ; + ; Detect 80286 by checking whether the IOPL and NT bits of EFLAGS can be + ; modified or not. There are different accounts of these bits. Dr.Dobb's + ; (http://www.drdobbs.com/embedded-systems/processor-detection-schemes/184409011) + ; say they are undefined on 286es and will always be zero. Whereas Intel + ; iAPX 286 Programmer's Reference Manual (both order #210498-001 and + ; #210498-003) documents both IOPL and NT, but with comment 4 on page + ; C-43 stating that they cannot be POPFed in real mode and will both + ; remain 0. This is different from the 386+, where the NT flag isn't + ; privileged according to page 3-37 in #230985-003. Later Intel docs + ; (#235383-052US, page 4-192) documents real mode as taking both NT and + ; IOPL from what POPF reads off the stack - which is the behavior + ; observed a 386SX here. + ; + test al, X86_CR0_PE ; This flag test doesn't work in protected mode, ... + jnz .386plus ; ... so ASSUME 386plus if in PE for now. + + pushf ; Save a copy of the original flags for restoring IF. + pushf + pop ax + xor ax, X86_EFL_IOPL | X86_EFL_NT ; Try modify IOPL and NT. + and ax, ~X86_EFL_IF ; Try clear IF. + push ax ; Load modified flags. + popf + pushf ; Get actual flags. + pop dx + popf ; Restore IF, IOPL and NT. + cmp ax, dx + je .386plus ; If any of the flags are set, we're on 386+. + + ; While we could in theory be in v8086 mode at this point and be fooled + ; by a flaky POPF implementation, we assume this isn't the case in our + ; execution environment. + %endif +.is_286: + mov ax, BS3CPU_80286 + jmp .return +%endif ; !TMPL_CMN_PAGING + +CPU 386 +.386plus: +.486plus: + ; + ; Check for CPUID and AC. The former flag indicates CPUID support, the + ; latter was introduced with the 486. + ; + mov ebx, esp ; Save esp. + and esp, 0fffch ; Clear high word and don't trigger ACs. + pushfd + mov eax, [esp] ; eax = original EFLAGS. + xor dword [esp], X86_EFL_ID | X86_EFL_AC ; Flip the ID and AC flags. + popfd ; Load modified flags. + pushfd ; Save actual flags. + xchg eax, [esp] ; Switch, so the stack has the original flags. + xor eax, [esp] ; Calc changed flags. + popf ; Restore EFLAGS. + mov esp, ebx ; Restore possibly unaligned ESP. + test eax, X86_EFL_ID + jnz .have_cpuid ; If ID changed, we've got CPUID. + test eax, X86_EFL_AC + mov xAX, BS3CPU_80486 + jnz .return ; If AC changed, we've got a 486 without CPUID (or similar). + mov xAX, BS3CPU_80386 + jmp .return + +CPU 586 +.have_cpuid: + ; + ; Do a very simple minded check here using the (standard) family field. + ; While here, we also check for PAE. + ; + mov eax, 1 + cpuid + + ; Calc the extended family and model values before we mess up EAX. + mov cl, ah + and cl, 0fh + cmp cl, 0fh + jnz .not_extended_family + mov ecx, eax + shr ecx, 20 + and cl, 7fh + add cl, 0fh +.not_extended_family: ; cl = family + mov ch, al + shr ch, 4 + cmp cl, 0fh + jae .extended_model + cmp cl, 06h ; actually only intel, but we'll let this slip for now. + jne .done_model +.extended_model: + shr eax, 12 + and al, 0f0h + or ch, al +.done_model: ; ch = model + + ; Start assembling return flags, checking for PSE + PAE. + mov eax, X86_CPUID_FEATURE_EDX_PSE | X86_CPUID_FEATURE_EDX_PAE + and eax, edx + mov ah, al + AssertCompile(X86_CPUID_FEATURE_EDX_PAE_BIT > BS3CPU_F_PAE_BIT - 8) ; 6 vs 10-8=2 + and al, X86_CPUID_FEATURE_EDX_PAE + shr al, X86_CPUID_FEATURE_EDX_PAE_BIT - (BS3CPU_F_PAE_BIT - 8) + AssertCompile(X86_CPUID_FEATURE_EDX_PSE_BIT == BS3CPU_F_PSE_BIT - 8) ; 3 vs 11-8=3 + and ah, X86_CPUID_FEATURE_EDX_PSE + or ah, al + or ah, (BS3CPU_F_CPUID >> 8) + + ; Add the CPU type based on the family and model values. + cmp cl, 6 + jne .not_family_06h + mov al, BS3CPU_PPro + cmp ch, 1 + jbe .return + mov al, BS3CPU_PProOrNewer + jmp .NewerThanPPro + +.not_family_06h: + mov al, BS3CPU_PProOrNewer + ja .NewerThanPPro + cmp cl, 5 + mov al, BS3CPU_Pentium + je .return + cmp cl, 4 + mov al, BS3CPU_80486 + je .return + cmp cl, 3 + mov al, BS3CPU_80386 + je .return + +.NewerThanPPro: + + ; Check for extended leaves and long mode. + push xAX ; save PAE+PProOrNewer + mov eax, 0x80000000 + cpuid + sub eax, 0x80000001 ; Minimum leaf 0x80000001 + cmp eax, 0x00010000 ; At most 0x10000 leaves. + ja .no_ext_leaves + + mov eax, 0x80000001 + cpuid + pop xAX ; restore PAE+PProOrNewer + test edx, X86_CPUID_EXT_FEATURE_EDX_LONG_MODE + jz .no_long_mode + or ah, ((BS3CPU_F_CPUID_EXT_LEAVES | BS3CPU_F_LONG_MODE) >> 8) + jmp .no_check_for_nx +.no_long_mode: + or ah, (BS3CPU_F_CPUID_EXT_LEAVES >> 8) +.no_check_for_nx: + test edx, X86_CPUID_EXT_FEATURE_EDX_NX + jz .return + or ax, BS3CPU_F_NX + jmp .return + +.no_ext_leaves: + pop xAX ; restore PAE+PProOrNewer + +CPU 8086 +.return: + ; + ; Save the return value. + ; + mov [BS3_DATA16_WRT(g_uBs3CpuDetected)], ax + + ; + ; Epilogue. + ; + add xSP, 20h + pop xBX + pop xDX + pop xCX + popf + pop xBP + BS3_HYBRID_RET + +BS3_PROC_END_MODE Bs3CpuDetect + + +%if TMPL_MODE == BS3_MODE_RM +BS3_BEGIN_TEXT16_NEARSTUBS +BS3_PROC_BEGIN_MODE Bs3CpuDetect, BS3_PBC_NEAR + call far TMPL_FAR_NM(Bs3CpuDetect) + ret +BS3_PROC_END_MODE Bs3CpuDetect +%endif + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-EnteredMode.asm b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-EnteredMode.asm new file mode 100644 index 00000000..07076e82 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-EnteredMode.asm @@ -0,0 +1,269 @@ +; $Id: bs3-mode-EnteredMode.asm $ +;; @file +; BS3Kit - Bs3EnteredMode +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + +%include "bs3kit-template-header.mac" + +%if TMPL_BITS == 16 +BS3_EXTERN_DATA16 g_uBs3CpuDetected +%endif +BS3_EXTERN_DATA16 g_bBs3CurrentMode +TMPL_BEGIN_TEXT + +;; +; @cproto BS3_DECL(void) Bs3EnteredMode(void); +; +; @uses Nothing. +; +; @remarks ASSUMES we're in ring-0 when not in some kind of real mode. +; +BS3_PROC_BEGIN_MODE Bs3EnteredMode, BS3_PBC_NEAR ; won't need this outside the switchers, so always near. + push xBP + mov xBP, xSP + push xAX + push xCX + push xDX +TONLY16 push xBX +%if BS3_MODE_IS_64BIT_CODE(TMPL_MODE) + push r8 + push r9 +%endif + + ; + ; Load stack selector (not always necessary) and sometimes CS too. + ; +%if BS3_MODE_IS_RM_SYS(TMPL_MODE) + xor ax, ax +%elif BS3_MODE_IS_V86(TMPL_MODE) + extern v86_versions_of_Bs3EnteredMode_should_not_be_dragged_into_the_link + call v86_versions_of_Bs3EnteredMode_should_not_be_dragged_into_the_link +%elif BS3_MODE_IS_16BIT_CODE(TMPL_MODE) + jmp BS3_SEL_R0_CS16:.reloaded_cs +.reloaded_cs: + mov ax, BS3_SEL_R0_SS16 +%elif BS3_MODE_IS_32BIT_CODE(TMPL_MODE) + mov ax, BS3_SEL_R0_SS32 +%elif BS3_MODE_IS_64BIT_CODE(TMPL_MODE) + mov ax, BS3_SEL_R0_DS64 +%else + %error "TMPL_MODE" +%endif + mov ss, ax + + ; + ; Load selector appropriate for accessing BS3SYSTEM16 data. + ; +%if BS3_MODE_IS_16BIT_CODE(TMPL_MODE) + mov ax, BS3_SEL_SYSTEM16 +%else + mov ax, RT_CONCAT(BS3_SEL_R0_DS,TMPL_BITS) +%endif + mov ds, ax + + ; + ; Load the appropritate IDT or IVT. + ; Always 64-bit in long mode, otherwise according to TMPL_BITS. + ; +%if BS3_MODE_IS_RM_SYS(TMPL_MODE) + BS3_EXTERN_SYSTEM16 Bs3Lidt_Ivt + TMPL_BEGIN_TEXT + lidt [Bs3Lidt_Ivt] + +%elif BS3_MODE_IS_16BIT_SYS(TMPL_MODE) + BS3_EXTERN_SYSTEM16 Bs3Lidt_Idt16 + TMPL_BEGIN_TEXT + lidt [Bs3Lidt_Idt16 TMPL_WRT_SYSTEM16_OR_FLAT] + +%elif BS3_MODE_IS_32BIT_SYS(TMPL_MODE) + BS3_EXTERN_SYSTEM16 Bs3Lidt_Idt32 + TMPL_BEGIN_TEXT + lidt [Bs3Lidt_Idt32 TMPL_WRT_SYSTEM16_OR_FLAT] + +%elif BS3_MODE_IS_64BIT_SYS(TMPL_MODE) + BS3_EXTERN_SYSTEM16 Bs3Lidt_Idt64 + TMPL_BEGIN_TEXT + lidt [Bs3Lidt_Idt64 TMPL_WRT_SYSTEM16_OR_FLAT] +%else + %error "TMPL_MODE" +%endif + +%if !BS3_MODE_IS_RM_OR_V86(TMPL_MODE) + ; + ; Load the appropriate task selector. + ; Always 64-bit in long mode, otherwise according to TMPL_BITS. + ; + %if BS3_MODE_IS_64BIT_SYS(TMPL_MODE) + BS3_EXTERN_SYSTEM16 Bs3Gdte_Tss64 + TMPL_BEGIN_TEXT + and byte [5 + Bs3Gdte_Tss64 TMPL_WRT_SYSTEM16_OR_FLAT], ~X86_SEL_TYPE_SYS_TSS_BUSY_MASK + mov ax, BS3_SEL_TSS64 + + %elif BS3_MODE_IS_16BIT_SYS(TMPL_MODE) + BS3_EXTERN_SYSTEM16 Bs3Gdte_Tss16 + BS3_EXTERN_SYSTEM16 Bs3Gdte_Tss16DoubleFault + TMPL_BEGIN_TEXT + and byte [5 + Bs3Gdte_Tss16 TMPL_WRT_SYSTEM16_OR_FLAT], ~X86_SEL_TYPE_SYS_TSS_BUSY_MASK + and byte [5 + Bs3Gdte_Tss16DoubleFault TMPL_WRT_SYSTEM16_OR_FLAT], ~X86_SEL_TYPE_SYS_TSS_BUSY_MASK + mov ax, BS3_SEL_TSS16 + + %elif BS3_MODE_IS_32BIT_SYS(TMPL_MODE) + BS3_EXTERN_SYSTEM16 Bs3Gdte_Tss32 + BS3_EXTERN_SYSTEM16 Bs3Gdte_Tss32DoubleFault + BS3_EXTERN_SYSTEM16 Bs3Tss32 + BS3_EXTERN_SYSTEM16 Bs3Tss32DoubleFault + TMPL_BEGIN_TEXT + and byte [5 + Bs3Gdte_Tss32 TMPL_WRT_SYSTEM16_OR_FLAT], ~X86_SEL_TYPE_SYS_TSS_BUSY_MASK + and byte [5 + Bs3Gdte_Tss32DoubleFault TMPL_WRT_SYSTEM16_OR_FLAT], ~X86_SEL_TYPE_SYS_TSS_BUSY_MASK + mov eax, cr3 + mov [X86TSS32.cr3 + Bs3Tss32 TMPL_WRT_SYSTEM16_OR_FLAT], eax + mov [X86TSS32.cr3 + Bs3Tss32DoubleFault TMPL_WRT_SYSTEM16_OR_FLAT], eax + mov ax, BS3_SEL_TSS32 + %else + %error "TMPL_BITS" + %endif + ltr ax +%endif ; !TMPL_CMN_R86 + +%if !BS3_MODE_IS_RM_OR_V86(TMPL_MODE) + ; + ; Load the LDT. + ; + mov ax, BS3_SEL_LDT + lldt ax +%endif + + ; + ; Load ds and es; clear fs and gs. + ; +%if BS3_MODE_IS_RM_OR_V86(TMPL_MODE) + mov ax, BS3_SEL_DATA16 +%else + mov ax, RT_CONCAT(BS3_SEL_R0_DS,TMPL_BITS) +%endif + mov ds, ax + mov es, ax + +%if TMPL_BITS == 16 + ; For restoring after Bs3Trap* calls below. + push ax + push ax + + cmp byte [BS3_DATA16_WRT(g_uBs3CpuDetected)], BS3CPU_80286 + jbe .skip_fs_gs +%endif + xor ax, ax + mov fs, ax + mov gs, ax +.skip_fs_gs: + + ; + ; Set global indicating CPU mode. + ; + mov byte [BS3_DATA16_WRT(g_bBs3CurrentMode)], TMPL_MODE + + ; + ; Install system call handler. + ; Always 64-bit in long mode, otherwise according to TMPL_BITS. + ; +%if BS3_MODE_IS_RM_SYS(TMPL_MODE) + extern _Bs3TrapSystemCallHandler_rm + mov word [ss: BS3_TRAP_SYSCALL*4], _Bs3TrapSystemCallHandler_rm wrt CGROUP16 + mov word [ss: BS3_TRAP_SYSCALL*4 + 2], CGROUP16 + +%elif BS3_MODE_IS_16BIT_SYS(TMPL_MODE) + BS3_EXTERN_CMN Bs3Trap16SetGate + extern TMPL_NM(Bs3TrapSystemCallHandler) + BS3_BEGIN_TEXT16 + TMPL_BEGIN_TEXT + push 0 ; cParams + push TMPL_NM(Bs3TrapSystemCallHandler) wrt CGROUP16 + push BS3_SEL_R0_CS16 + push 3 ; DPL + push X86_SEL_TYPE_SYS_286_INT_GATE + push BS3_TRAP_SYSCALL + BS3_CALL Bs3Trap16SetGate,6 + add xSP, xCB * 6 + +%elif BS3_MODE_IS_32BIT_SYS(TMPL_MODE) + BS3_EXTERN_CMN Bs3Trap32SetGate + extern TMPL_NM(Bs3TrapSystemCallHandler) + TMPL_BEGIN_TEXT + push 0 ; cParams + push dword TMPL_NM(Bs3TrapSystemCallHandler) wrt FLAT + push BS3_SEL_R0_CS32 + push 3 ; DPL + push X86_SEL_TYPE_SYS_386_INT_GATE + push BS3_TRAP_SYSCALL + BS3_CALL Bs3Trap32SetGate,6 + add xSP, xCB * 6 + +%elif BS3_MODE_IS_64BIT_SYS(TMPL_MODE) + BS3_EXTERN_CMN Bs3Trap64SetGate + extern _Bs3TrapSystemCallHandler_lm64 + TMPL_BEGIN_TEXT + push 0 ; bIst + %if BS3_MODE_IS_64BIT_CODE(TMPL_MODE) + push _Bs3TrapSystemCallHandler_lm64 wrt FLAT + %else + push dword 0 ; upper offset + push dword _Bs3TrapSystemCallHandler_lm64 wrt FLAT + %endif + push BS3_SEL_R0_CS64 + push 3 ; DPL + push AMD64_SEL_TYPE_SYS_INT_GATE + push BS3_TRAP_SYSCALL + BS3_CALL Bs3Trap64SetGate,6 + add xSP, xCB * 5 + 8 +%else + %error "TMPL_BITS" +%endif + +%if TMPL_BITS == 16 + ; Restoring ds and es after the above calls. + pop es + pop ds +%endif + + ; + ; Epilogue. + ; +%if TMPL_BITS == 64 + pop r9 + pop r8 +%endif +TONLY16 pop xBX + pop xDX + pop xCX + pop xAX +%ifdef BS3_STRICT + cmp xBP, xSP + je .return_stack_ok + int3 +.return_stack_ok: +%endif + pop xBP + ret +BS3_PROC_END_MODE Bs3EnteredMode + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-Name.asm b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-Name.asm new file mode 100644 index 00000000..35aa217e --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-Name.asm @@ -0,0 +1,34 @@ +; $Id: bs3-mode-Name.asm $ +;; @file +; BS3Kit - g_szBs3ModeName_xxx +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + +%include "bs3kit-template-header.mac" + + +BS3_BEGIN_DATA16 +BS3_GLOBAL_NAME_EX RT_CONCAT3(g_szBs3ModeName, _, TMPL_MODE_LNAME), , %strlen(TMPL_MODE_STR) +BS3_GLOBAL_NAME_EX RT_CONCAT3(_g_szBs3ModeName, _, TMPL_MODE_LNAME), , %strlen(TMPL_MODE_STR) + db TMPL_MODE_STR, 0 + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-NameShortLower.asm b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-NameShortLower.asm new file mode 100644 index 00000000..1b9894f4 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-NameShortLower.asm @@ -0,0 +1,36 @@ +; $Id: bs3-mode-NameShortLower.asm $ +;; @file +; BS3Kit - g_szBs3ModeName_xxx +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + +%include "bs3kit-template-header.mac" + + +BS3_BEGIN_DATA16 +%undef MY_MODE_NAME_STR +%defstr MY_MODE_NAME_STR TMPL_MODE_LNAME +BS3_GLOBAL_NAME_EX RT_CONCAT3(g_szBs3ModeNameShortLower, _, TMPL_MODE_LNAME), , %strlen(MY_MODE_NAME_STR) +BS3_GLOBAL_NAME_EX RT_CONCAT3(_g_szBs3ModeNameShortLower, _, TMPL_MODE_LNAME), , %strlen(MY_MODE_NAME_STR) + db MY_MODE_NAME_STR, 0 + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-PagingGetRootForLM64.asm b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-PagingGetRootForLM64.asm new file mode 100644 index 00000000..c3a034cc --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-PagingGetRootForLM64.asm @@ -0,0 +1,131 @@ +; $Id: bs3-mode-PagingGetRootForLM64.asm $ +;; @file +; BS3Kit - Bs3PagingGetRootForLM64 +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + +%include "bs3kit-template-header.mac" + + +%ifdef TMPL_RM +extern TMPL_NM(Bs3SwitchToPE16) +extern NAME(Bs3SwitchToRM_pe16) +%elifdef TMPL_CMN_V86 +extern TMPL_NM(Bs3SwitchToRing0) +extern TMPL_NM(Bs3SwitchTo16BitV86) +%endif + +BS3_EXTERN_CMN Bs3PagingInitRootForLM + +BS3_EXTERN_DATA16 g_PhysPagingRootLM +TMPL_BEGIN_TEXT + + +;; +; @cproto BS3_DECL(uint32_t) Bs3PagingGetRootForLM64(void) +; +; @returns eax +; +; @uses ax +; +; @remarks returns value in EAX, not dx:ax! +; +BS3_PROC_BEGIN_MODE Bs3PagingGetRootForLM64, BS3_PBC_NEAR ; Internal function, no far variant necessary. + mov eax, [BS3_DATA16_WRT(g_PhysPagingRootLM)] + cmp eax, 0ffffffffh + je .init_root +%ifdef BS3_STRICT +.return: + cmp eax, 1000h + jnb .cr3_ok_low + hlt +.cr3_ok_low: + cmp eax, 16*_1M + jb .cr3_ok_high + hlt +.cr3_ok_high: +%endif + ret + +.init_root: + push xBP + mov xBP, xSP +BONLY16 push es + push sDX + push sCX + push sBX +%if TMPL_BITS == 64 + push r8 + push r9 + push r10 + push r11 +%endif + +%ifdef TMPL_RM + ; + ; We don't want to be restricted to real mode addressing, so + ; temporarily switch to 16-bit protected mode. + ; + call TMPL_NM(Bs3SwitchToPE16) + call Bs3PagingInitRootForLM + call NAME(Bs3SwitchToRM_pe16) +%elifdef TMPL_CMN_V86 + ; + ; V8086 mode uses real mode addressing too. Unlikly that we'll + ; ever end up here though. + ; + call TMPL_NM(Bs3SwitchToRing0) + call Bs3PagingInitRootForLM + call TMPL_NM(Bs3SwitchTo16BitV86) +%else + ; + ; Not a problematic addressing mode. + ; +BONLY64 sub rsp, 20h + BS3_CALL Bs3PagingInitRootForLM, 0 +BONLY64 add rsp, 20h +%endif + + ; + ; Load the value and return. + ; + mov eax, [BS3_DATA16_WRT(g_PhysPagingRootLM)] + +%if TMPL_BITS == 64 + pop r11 + pop r10 + pop r9 + pop r8 +%endif + pop sBX + pop sCX + pop sDX +BONLY16 pop es + leave +%ifdef BS3_STRICT + jmp .return +%else + ret +%endif +BS3_PROC_END_MODE Bs3PagingGetRootForLM64 + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-PagingGetRootForPAE16.asm b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-PagingGetRootForPAE16.asm new file mode 100644 index 00000000..dd9ec4bb --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-PagingGetRootForPAE16.asm @@ -0,0 +1,45 @@ +; $Id: bs3-mode-PagingGetRootForPAE16.asm $ +;; @file +; BS3Kit - Bs3PagingGetRootForPAE16 +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + +%include "bs3kit-template-header.mac" + + +extern TMPL_NM(Bs3PagingGetRootForPAE32) + + +;; +; @cproto BS3_DECL(uint32_t) Bs3PagingGetRootForPAE16(void) +; +; @returns eax +; +; @uses ax +; +; @remarks returns value in EAX, not dx:ax! +; +BS3_PROC_BEGIN_MODE Bs3PagingGetRootForPAE16, BS3_PBC_NEAR ; Internal function, no far variant necessary. + jmp TMPL_NM(Bs3PagingGetRootForPAE32) +BS3_PROC_END_MODE Bs3PagingGetRootForPAE16 + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-PagingGetRootForPAE32.asm b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-PagingGetRootForPAE32.asm new file mode 100644 index 00000000..b28554a9 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-PagingGetRootForPAE32.asm @@ -0,0 +1,117 @@ +; $Id: bs3-mode-PagingGetRootForPAE32.asm $ +;; @file +; BS3Kit - Bs3PagingGetRootForPAE32 +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + +%include "bs3kit-template-header.mac" + + +%ifdef TMPL_RM +extern TMPL_NM(Bs3SwitchToPE16) +extern NAME(Bs3SwitchToRM_pe16) +%elifdef TMPL_CMN_V86 +extern TMPL_NM(Bs3SwitchToRing0) +extern TMPL_NM(Bs3SwitchTo16BitV86) +%endif + +BS3_EXTERN_CMN Bs3PagingInitRootForPAE + +BS3_EXTERN_DATA16 g_PhysPagingRootPAE +TMPL_BEGIN_TEXT + + +;; +; @cproto BS3_DECL(uint32_t) Bs3PagingGetRootForPAE32(void) +; +; @returns eax +; +; @uses ax +; +; @remarks returns value in EAX, not dx:ax! +; +BS3_PROC_BEGIN_MODE Bs3PagingGetRootForPAE32, BS3_PBC_NEAR ; Internal function, no far variant necessary. + mov eax, [BS3_DATA16_WRT(g_PhysPagingRootPAE)] + cmp eax, 0ffffffffh + je .init_root + ret + +.init_root: + push xBP + mov xBP, xSP +BONLY16 push es + push sDX + push sCX + push sBX +%if TMPL_BITS == 64 + push r8 + push r9 + push r10 + push r11 +%endif + +%ifdef TMPL_RM + ; + ; We don't want to be restricted to real mode addressing, so + ; temporarily switch to 16-bit protected mode. + ; + call TMPL_NM(Bs3SwitchToPE16) + call Bs3PagingInitRootForPAE + call NAME(Bs3SwitchToRM_pe16) + +%elifdef TMPL_CMN_V86 + ; + ; V8086 mode uses real mode addressing too. Unlikly that we'll + ; ever end up here though. + ; + call TMPL_NM(Bs3SwitchToRing0) + call Bs3PagingInitRootForPAE + call TMPL_NM(Bs3SwitchTo16BitV86) +%else + ; + ; Not a problematic addressing mode. + ; +BONLY64 sub rsp, 20h + BS3_CALL Bs3PagingInitRootForPAE, 0 +BONLY64 add rsp, 20h +%endif + + ; + ; Load the value and return. + ; + mov eax, [BS3_DATA16_WRT(g_PhysPagingRootPAE)] + +%if TMPL_BITS == 64 + pop r11 + pop r10 + pop r9 + pop r8 +%endif + pop sBX + pop sCX + pop sDX +BONLY16 pop es + leave + ret +BS3_PROC_END_MODE Bs3PagingGetRootForPAE32 + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-PagingGetRootForPP16.asm b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-PagingGetRootForPP16.asm new file mode 100644 index 00000000..96ae89f3 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-PagingGetRootForPP16.asm @@ -0,0 +1,45 @@ +; $Id: bs3-mode-PagingGetRootForPP16.asm $ +;; @file +; BS3Kit - Bs3PagingGetRootForPP16 +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + +%include "bs3kit-template-header.mac" + + +extern TMPL_NM(Bs3PagingGetRootForPP32) + + +;; +; @cproto BS3_DECL(uint32_t) Bs3PagingGetRootForPP16(void) +; +; @returns eax +; +; @uses ax +; +; @remarks returns value in EAX, not dx:ax! +; +BS3_PROC_BEGIN_MODE Bs3PagingGetRootForPP16, BS3_PBC_NEAR ; Internal function, no far variant necessary. + jmp TMPL_NM(Bs3PagingGetRootForPP32) +BS3_PROC_END_MODE Bs3PagingGetRootForPP16 + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-PagingGetRootForPP32.asm b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-PagingGetRootForPP32.asm new file mode 100644 index 00000000..9ae99068 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-PagingGetRootForPP32.asm @@ -0,0 +1,132 @@ +; $Id: bs3-mode-PagingGetRootForPP32.asm $ +;; @file +; BS3Kit - Bs3PagingGetRootForPP32 +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + +%include "bs3kit-template-header.mac" + + +%ifdef TMPL_RM +extern TMPL_NM(Bs3SwitchToPE16) +extern NAME(Bs3SwitchToRM_pe16) +%elifdef TMPL_CMN_V86 +extern TMPL_NM(Bs3SwitchToRing0) +extern TMPL_NM(Bs3SwitchTo16BitV86) +%endif + +BS3_EXTERN_CMN Bs3PagingInitRootForPP + +BS3_EXTERN_DATA16 g_PhysPagingRootPP +TMPL_BEGIN_TEXT + + +;; +; @cproto BS3_DECL(uint32_t) Bs3PagingGetRootForPP32(void) +; +; @returns eax +; +; @uses ax +; +; @remarks returns value in EAX, not dx:ax! +; +BS3_PROC_BEGIN_MODE Bs3PagingGetRootForPP32, BS3_PBC_NEAR ; Internal function, no far variant necessary. + mov eax, [BS3_DATA16_WRT(g_PhysPagingRootPP)] + cmp eax, 0ffffffffh + je .init_root +%ifdef BS3_STRICT +.return: + cmp eax, 1000h + jnb .cr3_ok_low + hlt +.cr3_ok_low: + cmp eax, 16*_1M + jb .cr3_ok_high + hlt +.cr3_ok_high: +%endif + ret + +.init_root: + push xBP + mov xBP, xSP +BONLY16 push es + push sDX + push sCX + push sBX +%if TMPL_BITS == 64 + push r8 + push r9 + push r10 + push r11 +%endif + +%ifdef TMPL_RM + ; + ; We don't want to be restricted to real mode addressing, so + ; temporarily switch to 16-bit protected mode. + ; + call TMPL_NM(Bs3SwitchToPE16) + call Bs3PagingInitRootForPP + call NAME(Bs3SwitchToRM_pe16) + +%elifdef TMPL_CMN_V86 + ; + ; V8086 mode uses real mode addressing too. Unlikly that we'll + ; ever end up here though. + ; + call TMPL_NM(Bs3SwitchToRing0) + call Bs3PagingInitRootForPP + call TMPL_NM(Bs3SwitchTo16BitV86) +%else + ; + ; Not a problematic addressing mode. + ; +BONLY64 sub rsp, 20h + BS3_CALL Bs3PagingInitRootForPP, 0 +BONLY64 add rsp, 20h +%endif + + ; + ; Load the value and return. + ; + mov eax, [BS3_DATA16_WRT(g_PhysPagingRootPP)] + +%if TMPL_BITS == 64 + pop r11 + pop r10 + pop r9 + pop r8 +%endif + pop sBX + pop sCX + pop sDX +BONLY16 pop es + leave +%ifdef BS3_STRICT + jmp .return +%else + ret +%endif +BS3_PROC_END_MODE Bs3PagingGetRootForPP32 + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-SwitchTo32BitAndCallC.asm b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-SwitchTo32BitAndCallC.asm new file mode 100644 index 00000000..c48b6090 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-SwitchTo32BitAndCallC.asm @@ -0,0 +1,154 @@ +; $Id: bs3-mode-SwitchTo32BitAndCallC.asm $ +;; @file +; BS3Kit - bs3SwitchTo32BitAndCallC +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + +;********************************************************************************************************************************* +;* Header Files * +;********************************************************************************************************************************* +%include "bs3kit-template-header.mac" + + +;********************************************************************************************************************************* +;* External Symbols * +;********************************************************************************************************************************* +BS3_EXTERN_DATA16 g_bBs3CurrentMode +TMPL_BEGIN_TEXT + +%ifdef BS3_STRICT +BS3_EXTERN_CMN Bs3Panic +%endif + +%if BS3_MODE_IS_RM_OR_V86(TMPL_MODE) +BS3_EXTERN_CMN Bs3SelRealModeCodeToFlat +%endif + +%if TMPL_MODE == BS3_MODE_RM +extern NAME(Bs3SwitchToPE32_rm) +extern NAME(Bs3SwitchToRM_pe32) +%elif !BS3_MODE_IS_32BIT_CODE(TMPL_MODE) +BS3_EXTERN_CMN Bs3SwitchTo32Bit + %if BS3_MODE_IS_16BIT_CODE_NO_V86(TMPL_MODE) +extern _Bs3SwitchTo16Bit_c32 + %elif BS3_MODE_IS_V86(TMPL_MODE) +extern _Bs3SwitchTo16BitV86_c32 + %elif !BS3_MODE_IS_32BIT_CODE(TMPL_MODE) +extern _Bs3SwitchTo64_c32 + %endif +%endif + + + +;; +; @cproto BS3_MODE_PROTO_STUB(int, Bs3SwitchTo32BitAndCallC,(PFNBS3FARADDRCONV fpfnCall, unsigned cbParams, ...)); +; +BS3_PROC_BEGIN_MODE Bs3SwitchTo32BitAndCallC, BS3_PBC_HYBRID + BS3_CALL_CONV_PROLOG 4 +TONLY16 inc xBP + push xBP + mov xBP, xSP + push xSI + + ; + ; Push the arguments first. + ; +TONLY16 mov si, [xBP + xCB + cbCurRetAddr + sCB] +TNOT16 mov esi, [xBP + xCB + cbCurRetAddr + sCB] +%ifdef BS3_STRICT + test xSI, 3 + jz .cbParams_ok + call Bs3Panic +.cbParams_ok: + cmp byte [BS3_DATA16_WRT(g_bBs3CurrentMode)], TMPL_MODE + je .mode_ok + call Bs3Panic +.mode_ok: +%endif + add xSI, sCB - 1 ; round it up to nearest push size / dword. + and xSI, ~(sCB - 1) + jz .done_pushing ; skip if zero +.push_more: + push xPRE [xBP + xCB + cbCurRetAddr + sCB + xCB + xSI - xCB] + sub xSI, xCB + jnz .push_more + mov xSI, xAX ; restore xSI +.done_pushing: + + ; + ; Load fpfnCall into eax. + ; +%if BS3_MODE_IS_RM_OR_V86(TMPL_MODE) + push sPRE [xBP + xCB + cbCurRetAddr] + BS3_CALL Bs3SelRealModeCodeToFlat, 1 + add xSP, sCB + rol eax, 16 + mov ax, dx + rol eax, 16 +%else + mov eax, [xBP + xCB + cbCurRetAddr] +%endif + + ; + ; Switch to 32-bit mode, if this is real mode pick PE32. + ; +%if TMPL_MODE == BS3_MODE_RM + call NAME(Bs3SwitchToPE32_rm) + BS3_SET_BITS 32 +%elif !BS3_MODE_IS_32BIT_CODE(TMPL_MODE) + call Bs3SwitchTo32Bit + BS3_SET_BITS 32 +%endif + + ; + ; Make the call. + ; + call eax + + ; + ; Return, preserving xAX. + ; +%if BS3_MODE_IS_RM_OR_V86(TMPL_MODE) + mov edx, eax + shr edx, 16 +%endif +%if TMPL_MODE == BS3_MODE_RM + call NAME(Bs3SwitchToRM_pe32) +%elif BS3_MODE_IS_16BIT_CODE_NO_V86(TMPL_MODE) + call _Bs3SwitchTo16Bit_c32 +%elif BS3_MODE_IS_V86(TMPL_MODE) + call _Bs3SwitchTo16BitV86_c32 +%elif !BS3_MODE_IS_32BIT_CODE(TMPL_MODE) + call _Bs3SwitchTo64_c32 +%endif + BS3_SET_BITS TMPL_BITS + + ; Epilog. + lea xSP, [xBP - xCB] + pop xSI + pop xBP +TONLY16 dec xBP + BS3_CALL_CONV_EPILOG 4 + BS3_HYBRID_RET +BS3_PROC_END_MODE Bs3SwitchTo32BitAndCallC + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-SwitchToLM16.asm b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-SwitchToLM16.asm new file mode 100644 index 00000000..51da27ce --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-SwitchToLM16.asm @@ -0,0 +1,126 @@ +; $Id: bs3-mode-SwitchToLM16.asm $ +;; @file +; BS3Kit - Bs3SwitchToLM16 +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + +%include "bs3kit-template-header.mac" + + +;; +; Switch to 16-bit long mode from any other mode. +; +; @cproto BS3_DECL(void) Bs3SwitchToLM16(void); +; +; @uses Nothing (except possibly high 32-bit and/or upper 64-bit register parts). +; +; @remarks Obviously returns to 16-bit mode, even if the caller was in 32-bit +; or 64-bit mode. It doesn't not preserve the callers ring, but +; instead changes to ring-0. +; +; @remarks Does not require 20h of parameter scratch space in 64-bit mode. +; +%if TMPL_BITS == 16 +BS3_GLOBAL_NAME_EX TMPL_NM(Bs3SwitchToLM16_Safe), function , 0 +%endif +BS3_PROC_BEGIN_MODE Bs3SwitchToLM16, BS3_PBC_NEAR +%ifdef TMPL_LM16 + extern BS3_CMN_NM(Bs3SwitchToRing0) + call BS3_CMN_NM(Bs3SwitchToRing0) + push ax + mov ax, BS3_SEL_R0_DS16 + mov ds, ax + mov es, ax + pop ax + ret + +%elifdef TMPL_CMN_LM + ; + ; Already in long mode, just switch to 16-bit. + ; + extern BS3_CMN_NM(Bs3SwitchTo16Bit) + jmp BS3_CMN_NM(Bs3SwitchTo16Bit) + +%else + ; + ; Switch to LM32 and then switch to 64-bits (IDT & TSS are the same for + ; LM16, LM32 and LM64, unlike the rest). + ; + ; (The long mode switching code is going via 32-bit protected mode, so + ; Bs3SwitchToLM32 contains the actual code for switching to avoid + ; unnecessary 32-bit -> 64-bit -> 32-bit trips.) + ; + extern TMPL_NM(Bs3SwitchToLM32) + call TMPL_NM(Bs3SwitchToLM32) + BS3_SET_BITS 32 + + extern _Bs3SwitchTo16Bit_c32 + %if TMPL_BITS == 16 + sub esp, 2 + shr dword [esp], 16 + %elif TMPL_BITS == 64 + pop dword [esp + 4] + %endif + jmp _Bs3SwitchTo16Bit_c32 +%endif +BS3_PROC_END_MODE Bs3SwitchToLM16 + + +%if TMPL_BITS == 16 +;; +; Custom far stub. +BS3_BEGIN_TEXT16_FARSTUBS +BS3_PROC_BEGIN_MODE Bs3SwitchToLM16, BS3_PBC_FAR + inc bp + push bp + mov bp, sp + + ; Call the real thing. + call TMPL_NM(Bs3SwitchToLM16) + + %if BS3_MODE_IS_RM_OR_V86(TMPL_MODE) + ; Jmp to common code for the tedious conversion. + BS3_EXTERN_CMN Bs3SwitchHlpConvRealModeRetfPopBpDecBpAndReturn + jmp Bs3SwitchHlpConvRealModeRetfPopBpDecBpAndReturn + %else + pop bp + dec bp + retf + %endif +BS3_PROC_END_MODE Bs3SwitchToLM16 + +%else +;; +; Safe far return to non-BS3TEXT16 code. +BS3_EXTERN_CMN Bs3SwitchHlpConvFlatRetToRetfProtMode +BS3_BEGIN_TEXT16 +BS3_SET_BITS TMPL_BITS +BS3_PROC_BEGIN_MODE Bs3SwitchToLM16_Safe, BS3_PBC_NEAR + call Bs3SwitchHlpConvFlatRetToRetfProtMode ; Special internal function. Uses nothing, but modifies the stack. + call TMPL_NM(Bs3SwitchToLM16) + BS3_SET_BITS 16 + retf +BS3_PROC_END_MODE Bs3SwitchToLM16_Safe + +%endif + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-SwitchToLM32.asm b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-SwitchToLM32.asm new file mode 100644 index 00000000..24c87a4a --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-SwitchToLM32.asm @@ -0,0 +1,193 @@ +; $Id: bs3-mode-SwitchToLM32.asm $ +;; @file +; BS3Kit - Bs3SwitchToLM32 +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + +%include "bs3kit-template-header.mac" + + +;; +; Switch to 32-bit long mode from any other mode. +; +; @cproto BS3_DECL(void) Bs3SwitchToLM32(void); +; +; @uses Nothing (except possibly high 32-bit and/or upper 64-bit register parts). +; +; @remarks There are no IDT or TSS differences between LM16, LM32 and LM64 (unlike +; PE16 & PE32, PP16 & PP32, and PAE16 & PAE32). +; +; @remarks Obviously returns to 32-bit mode, even if the caller was in 16-bit +; or 64-bit mode. It doesn't not preserve the callers ring, but +; instead changes to ring-0. +; +; @remarks Does not require 20h of parameter scratch space in 64-bit mode. +; +BS3_GLOBAL_NAME_EX TMPL_NM(Bs3SwitchToLM32_Safe), function, 0 +BS3_PROC_BEGIN_MODE Bs3SwitchToLM32, BS3_PBC_NEAR +%ifdef TMPL_LM32 + ret + +%elifdef TMPL_CMN_LM + ; + ; Already in long mode, just switch to 32-bit. + ; + extern BS3_CMN_NM(Bs3SwitchTo32Bit) + jmp BS3_CMN_NM(Bs3SwitchTo32Bit) + +%elif BS3_MODE_IS_V86(TMPL_MODE) + ; + ; V8086 - Switch to 16-bit ring-0 and call worker for that mode. + ; + extern BS3_CMN_NM(Bs3SwitchToRing0) + call BS3_CMN_NM(Bs3SwitchToRing0) + extern %[BS3_MODE_R0_NM_ %+ TMPL_MODE](Bs3SwitchToLM32) + jmp %[BS3_MODE_R0_NM_ %+ TMPL_MODE](Bs3SwitchToLM32) + +%else + %if TMPL_BITS == 16 + push word 0 ; save space for extending the return value. + %endif + + ; + ; Switch to 32-bit protected mode (for identify mapped pages). + ; + extern TMPL_NM(Bs3SwitchToPE32) + call TMPL_NM(Bs3SwitchToPE32) + BS3_SET_BITS 32 + %if TMPL_BITS == 16 + jmp .thirty_two_bit_segment +BS3_BEGIN_TEXT32 +BS3_GLOBAL_LOCAL_LABEL .thirty_two_bit_segment + %endif + + push eax + push ecx + push edx + pushfd + + ; + ; Make sure both PAE and PSE are enabled (requires pentium pro). + ; + mov eax, cr4 + mov ecx, eax + or eax, X86_CR4_PAE | X86_CR4_PSE + cmp eax, ecx + je .cr4_is_fine + mov cr4, eax +.cr4_is_fine: + + ; + ; Get the page directory (returned in eax). + ; Will lazy init page tables. + ; + extern NAME(Bs3PagingGetRootForLM64_pe32) + call NAME(Bs3PagingGetRootForLM64_pe32) + + cli + mov cr3, eax + + ; + ; Enable long mode in EFER. + ; + mov ecx, MSR_K6_EFER + rdmsr + or eax, MSR_K6_EFER_LME + wrmsr + + ; + ; Enable paging and thereby activating LM64. + ; +BS3_EXTERN_SYSTEM16 Bs3Lgdt_Gdt +BS3_BEGIN_TEXT32 + mov eax, cr0 + or eax, X86_CR0_PG + mov cr0, eax + jmp .in_lm32 +.in_lm32: + + ; + ; Call rountine for doing mode specific setups. + ; + extern NAME(Bs3EnteredMode_lm32) + call NAME(Bs3EnteredMode_lm32) + + ; + ; Load full 64-bit GDT base address from 64-bit segment. + ; + jmp dword BS3_SEL_R0_CS64:.load_full_gdt_base wrt FLAT +.load_full_gdt_base: + BS3_SET_BITS 64 + lgdt [Bs3Lgdt_Gdt wrt FLAT] + push BS3_SEL_R0_CS32 + push .back_to_32bit wrt FLAT + o64 retf +.back_to_32bit: + BS3_SET_BITS 32 + + ; + ; Restore ecx, eax and flags (IF). + ; + %if TMPL_BITS == 16 + movzx eax, word [esp + 16 + 2] ; Load return address. + add eax, BS3_ADDR_BS3TEXT16 ; Convert it to a flat address. + mov [esp + 16], eax ; Store it in the place right for 32-bit returns. + %endif + popfd + pop edx + pop ecx + pop eax + ret + + %if TMPL_BITS != 32 +TMPL_BEGIN_TEXT + %endif +%endif +BS3_PROC_END_MODE Bs3SwitchToLM32 + + +%if TMPL_BITS == 16 +;; +; Custom far stub. +BS3_BEGIN_TEXT16_FARSTUBS +BS3_PROC_BEGIN_MODE Bs3SwitchToLM32, BS3_PBC_FAR + inc bp + push bp + mov bp, sp + + ; Call the real thing. + call TMPL_NM(Bs3SwitchToLM32) + BS3_SET_BITS 32 + + ; Jmp to common code for the tedious conversion. + %if BS3_MODE_IS_RM_OR_V86(TMPL_MODE) + extern _Bs3SwitchHlpConvRealModeRetfPopBpDecBpAndReturn_c32 + jmp _Bs3SwitchHlpConvRealModeRetfPopBpDecBpAndReturn_c32 + %else + extern _Bs3SwitchHlpConvProtModeRetfPopBpDecBpAndReturn_c32 + jmp _Bs3SwitchHlpConvProtModeRetfPopBpDecBpAndReturn_c32 + %endif + BS3_SET_BITS 16 +BS3_PROC_END_MODE Bs3SwitchToLM32 +%endif + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-SwitchToLM64.asm b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-SwitchToLM64.asm new file mode 100644 index 00000000..73b71eeb --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-SwitchToLM64.asm @@ -0,0 +1,104 @@ +; $Id: bs3-mode-SwitchToLM64.asm $ +;; @file +; BS3Kit - Bs3SwitchToLM64 +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + +%include "bs3kit-template-header.mac" + + +;; +; Switch to 64-bit long mode from any other mode. +; +; @cproto BS3_DECL(void) Bs3SwitchToLM64(void); +; +; @uses Nothing (except possibly high 32-bit and/or upper 64-bit register parts). +; +; @remarks Obviously returns to 64-bit mode, even if the caller was in 16-bit +; or 32-bit mode. It doesn't not preserve the callers ring, but +; instead changes to ring-0. +; +; @remarks Does not require 20h of parameter scratch space in 64-bit mode. +; +BS3_GLOBAL_NAME_EX TMPL_NM(Bs3SwitchToLM64_Safe), function, 0 +BS3_PROC_BEGIN_MODE Bs3SwitchToLM64, BS3_PBC_NEAR +%ifdef TMPL_LM64 + ret + +%elifdef TMPL_CMN_LM + ; + ; Already in long mode, just switch to 64-bit. + ; + extern BS3_CMN_NM(Bs3SwitchTo64Bit) + jmp BS3_CMN_NM(Bs3SwitchTo64Bit) + +%else + ; + ; Switch to LM32 and then switch to 64-bits (IDT & TSS are the same for + ; LM16, LM32 and LM64, unlike the rest). + ; + ; (The long mode switching code is going via 32-bit protected mode, so + ; Bs3SwitchToLM32 contains the actual code for switching to avoid + ; unnecessary 32-bit -> 64-bit -> 32-bit trips.) + ; + %ifdef TMPL_16BIT + and esp, 0ffffh + push word [esp] ; copy return address. + and word [esp + 2], 0 ; clear upper return address + add dword [esp], BS3_ADDR_BS3TEXT16 ; Add base of return segment, completing 32-bit conversion. + %endif + extern TMPL_NM(Bs3SwitchToLM32) + call TMPL_NM(Bs3SwitchToLM32) + BS3_SET_BITS 32 + + extern _Bs3SwitchTo64Bit_c32 + jmp _Bs3SwitchTo64Bit_c32 +%endif +BS3_PROC_END_MODE Bs3SwitchToLM64 + + +%if TMPL_BITS == 16 +;; +; Custom far stub. +BS3_BEGIN_TEXT16_FARSTUBS +BS3_PROC_BEGIN_MODE Bs3SwitchToLM64, BS3_PBC_FAR + inc bp + push bp + mov bp, sp + + ; Call the real thing. + call TMPL_NM(Bs3SwitchToLM64) + BS3_SET_BITS 64 + + ; Jmp to common code for the tedious conversion. + %if BS3_MODE_IS_RM_OR_V86(TMPL_MODE) + extern _Bs3SwitchHlpConvRealModeRetfPopBpDecBpAndReturn_c64 + jmp _Bs3SwitchHlpConvRealModeRetfPopBpDecBpAndReturn_c64 + %else + extern _Bs3SwitchHlpConvProtModeRetfPopBpDecBpAndReturn_c64 + jmp _Bs3SwitchHlpConvProtModeRetfPopBpDecBpAndReturn_c64 + %endif + BS3_SET_BITS 16 +BS3_PROC_END_MODE Bs3SwitchToLM64 +%endif + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-SwitchToPAE16.asm b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-SwitchToPAE16.asm new file mode 100644 index 00000000..ff229883 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-SwitchToPAE16.asm @@ -0,0 +1,233 @@ +; $Id: bs3-mode-SwitchToPAE16.asm $ +;; @file +; BS3Kit - Bs3SwitchToPAE16 +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + +;********************************************************************************************************************************* +;* Header Files * +;********************************************************************************************************************************* +%include "bs3kit-template-header.mac" + + +;********************************************************************************************************************************* +;* External Symbols * +;********************************************************************************************************************************* +%ifndef TMPL_PAE16 +BS3_BEGIN_TEXT16 +extern NAME(Bs3EnteredMode_pae16) + %ifdef TMPL_PAE32 + BS3_EXTERN_CMN Bs3SwitchTo16Bit + %endif +TMPL_BEGIN_TEXT +%endif + + +;; +; Switch to 16-bit paged protected mode from any other mode. +; +; @cproto BS3_DECL(void) Bs3SwitchToPAE16(void); +; +; @uses Nothing (except high 32-bit register parts). +; +; @remarks Obviously returns to 16-bit mode, even if the caller was +; in 32-bit or 64-bit mode. +; +; @remarks Does not require 20h of parameter scratch space in 64-bit mode. +; +%if TMPL_BITS == 16 +BS3_GLOBAL_NAME_EX TMPL_NM(Bs3SwitchToPAE16_Safe), function , 0 +%endif +BS3_PROC_BEGIN_MODE Bs3SwitchToPAE16, BS3_PBC_NEAR +%ifdef TMPL_PAE16 + extern BS3_CMN_NM(Bs3SwitchToRing0) + call BS3_CMN_NM(Bs3SwitchToRing0) + push ax + mov ax, BS3_SEL_R0_DS16 + mov ds, ax + mov es, ax + pop ax + ret + +%elif BS3_MODE_IS_V86(TMPL_MODE) + ; + ; V8086 - Switch to 16-bit ring-0 and call worker for that mode. + ; + extern BS3_CMN_NM(Bs3SwitchToRing0) + call BS3_CMN_NM(Bs3SwitchToRing0) + extern %[BS3_MODE_R0_NM_ %+ TMPL_MODE](Bs3SwitchToPAE16) + jmp %[BS3_MODE_R0_NM_ %+ TMPL_MODE](Bs3SwitchToPAE16) + +%else + ; + ; Switch to 16-bit text segment and prepare for returning in 16-bit mode. + ; + %if TMPL_BITS != 16 + shl xPRE [xSP], TMPL_BITS - 16 ; Adjust the return address. + add xSP, xCB - 2 + + ; Must be in 16-bit segment when calling Bs3SwitchToRM and Bs3SwitchTo16Bit. + jmp .sixteen_bit_segment +BS3_BEGIN_TEXT16 + BS3_SET_BITS TMPL_BITS +BS3_GLOBAL_LOCAL_LABEL .sixteen_bit_segment + %endif + + %ifdef TMPL_PAE32 + ; + ; No need to go to real-mode here, we use the same CR3 and stuff. + ; Just switch to 32-bit mode and call the Bs3EnteredMode routine to + ; load the right descriptor tables. + ; + call Bs3SwitchTo16Bit + BS3_SET_BITS 16 + call NAME(Bs3EnteredMode_pae16) + ret + %else + + ; + ; Switch to real mode. + ; + extern TMPL_NM(Bs3SwitchToRM) + call TMPL_NM(Bs3SwitchToRM) + BS3_SET_BITS 16 + + push eax + push ecx + pushfd + + ; + ; Get the page directory (returned in eax). + ; Will lazy init page tables (in 16-bit prot mode). + ; + extern NAME(Bs3PagingGetRootForPAE16_rm) + call NAME(Bs3PagingGetRootForPAE16_rm) + + cli + mov cr3, eax + + ; + ; Make sure PAE, PSE, and VME are enabled (former two require pentium pro, latter 486). + ; + mov eax, cr4 + mov ecx, eax + or eax, X86_CR4_PAE | X86_CR4_PSE | X86_CR4_VME + cmp eax, ecx + je .cr4_is_fine + mov cr4, eax +.cr4_is_fine: + + ; + ; Load the GDT and enable PP16. + ; +BS3_EXTERN_SYSTEM16 Bs3LgdtDef_Gdt +BS3_EXTERN_SYSTEM16 Bs3Lgdt_Gdt +BS3_BEGIN_TEXT16 + mov ax, BS3SYSTEM16 + mov ds, ax + lgdt [Bs3LgdtDef_Gdt] ; Will only load 24-bit base! + + mov eax, cr0 + or eax, X86_CR0_PE | X86_CR0_PG + mov cr0, eax + jmp BS3_SEL_R0_CS16:.reload_cs_and_stuff +.reload_cs_and_stuff: + + ; + ; Convert the (now) real mode stack to 16-bit. + ; + mov ax, .stack_fix_return + extern NAME(Bs3ConvertRMStackToP16UsingCxReturnToAx_c16) + jmp NAME(Bs3ConvertRMStackToP16UsingCxReturnToAx_c16) +.stack_fix_return: + + ; + ; Call rountine for doing mode specific setups. + ; + call NAME(Bs3EnteredMode_pae16) + + ; + ; Load full 32-bit GDT base address from 32-bit segment. + ; + push ds + mov ax, BS3_SEL_SYSTEM16 + mov ds, ax + jmp dword BS3_SEL_R0_CS32:.load_full_gdt_base wrt FLAT +.load_full_gdt_base: + BS3_SET_BITS 32 + lgdt [Bs3Lgdt_Gdt wrt BS3SYSTEM16] + jmp BS3_SEL_R0_CS16:.back_to_16bit +.back_to_16bit: + BS3_SET_BITS 16 + pop ds + + popfd + pop ecx + pop eax + ret + + %endif ; !TMPL_PP32 + %if TMPL_BITS != 16 +TMPL_BEGIN_TEXT + %endif +%endif +BS3_PROC_END_MODE Bs3SwitchToPAE16 + + +%if TMPL_BITS == 16 +;; +; Custom far stub. +BS3_BEGIN_TEXT16_FARSTUBS +BS3_PROC_BEGIN_MODE Bs3SwitchToPAE16, BS3_PBC_FAR + inc bp + push bp + mov bp, sp + + ; Call the real thing. + call TMPL_NM(Bs3SwitchToPAE16) + + %if BS3_MODE_IS_RM_OR_V86(TMPL_MODE) + ; Jmp to common code for the tedious conversion. + BS3_EXTERN_CMN Bs3SwitchHlpConvRealModeRetfPopBpDecBpAndReturn + jmp Bs3SwitchHlpConvRealModeRetfPopBpDecBpAndReturn + %else + pop bp + dec bp + retf + %endif +BS3_PROC_END_MODE Bs3SwitchToPAE16 + +%else +;; +; Safe far return to non-BS3TEXT16 code. +BS3_EXTERN_CMN Bs3SwitchHlpConvFlatRetToRetfProtMode +BS3_BEGIN_TEXT16 +BS3_SET_BITS TMPL_BITS +BS3_PROC_BEGIN_MODE Bs3SwitchToPAE16_Safe, BS3_PBC_NEAR + call Bs3SwitchHlpConvFlatRetToRetfProtMode ; Special internal function. Uses nothing, but modifies the stack. + call TMPL_NM(Bs3SwitchToPAE16) + BS3_SET_BITS 16 + retf +BS3_PROC_END_MODE Bs3SwitchToPAE16_Safe +%endif + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-SwitchToPAE16_32.asm b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-SwitchToPAE16_32.asm new file mode 100644 index 00000000..20da0d91 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-SwitchToPAE16_32.asm @@ -0,0 +1,104 @@ +; $Id: bs3-mode-SwitchToPAE16_32.asm $ +;; @file +; BS3Kit - Bs3SwitchToPAE16_32 +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + +%include "bs3kit-template-header.mac" + + +;; +; Switch to 32-bit code under 16-bit PAE paged protected mode sys/tss from any other mode. +; +; @cproto BS3_DECL(void) Bs3SwitchToPE16_32(void); +; +; @uses Nothing (except high 32-bit register parts). +; +; @remarks Obviously returns to 32-bit mode, even if the caller was +; in 16-bit or 64-bit mode. +; +; @remarks Does not require 20h of parameter scratch space in 64-bit mode. +; +BS3_GLOBAL_NAME_EX TMPL_NM(Bs3SwitchToPAE16_32_Safe), function, 0 +BS3_PROC_BEGIN_MODE Bs3SwitchToPAE16_32, BS3_PBC_NEAR +%ifdef TMPL_PAE16_32 + ret + +%else + ; + ; Make sure we're in the 16-bit segment and then call Bs3SwitchToPAE16. + ; + %if TMPL_BITS != 16 + jmp .sixteen_bit_segment +BS3_BEGIN_TEXT16 + BS3_SET_BITS TMPL_BITS +BS3_GLOBAL_LOCAL_LABEL .sixteen_bit_segment + %endif + extern TMPL_NM(Bs3SwitchToPAE16) + call TMPL_NM(Bs3SwitchToPAE16) + BS3_SET_BITS 16 + + ; + ; Switch to 32-bit mode. + ; + extern _Bs3SwitchTo32Bit_c16 + %if TMPL_BITS == 16 + jmp _Bs3SwitchTo32Bit_c16 + %else + call _Bs3SwitchTo32Bit_c16 + BS3_SET_BITS 32 + %if TMPL_BITS == 32 + ret + %else + ret 4 ; Return and pop 4 bytes of "parameters" (unused return address). + %endif + %endif +%endif +BS3_PROC_END_MODE Bs3SwitchToPAE16_32 + + +%if TMPL_BITS == 16 +;; +; Custom far stub. +BS3_BEGIN_TEXT16_FARSTUBS +BS3_PROC_BEGIN_MODE Bs3SwitchToPAE16_32, BS3_PBC_FAR + inc bp + push bp + mov bp, sp + + ; Call the real thing. + call TMPL_NM(Bs3SwitchToPAE16_32) + BS3_SET_BITS 32 + + ; Jmp to common code for the tedious conversion. + %if BS3_MODE_IS_RM_OR_V86(TMPL_MODE) + extern _Bs3SwitchHlpConvRealModeRetfPopBpDecBpAndReturn_c32 + jmp _Bs3SwitchHlpConvRealModeRetfPopBpDecBpAndReturn_c32 + %else + extern _Bs3SwitchHlpConvProtModeRetfPopBpDecBpAndReturn_c32 + jmp _Bs3SwitchHlpConvProtModeRetfPopBpDecBpAndReturn_c32 + %endif + BS3_SET_BITS 16 +BS3_PROC_END_MODE Bs3SwitchToPAE16_32 +%endif + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-SwitchToPAE16_V86.asm b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-SwitchToPAE16_V86.asm new file mode 100644 index 00000000..cd457f9a --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-SwitchToPAE16_V86.asm @@ -0,0 +1,114 @@ +; $Id: bs3-mode-SwitchToPAE16_V86.asm $ +;; @file +; BS3Kit - Bs3SwitchToPAE16_V86 +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + +%include "bs3kit-template-header.mac" + + +;; +; Switch to 16-bit PAE paged protected mode with 16-bit sys+tss from any other mode. +; +; @cproto BS3_DECL(void) Bs3SwitchToPAE16(void); +; +; @uses Nothing (except high 32-bit register parts). +; +; @remarks Obviously returns to v8086 16-bit mode, even if the caller was +; in 16-bit, 32-bit or 64-bit mode. +; +; @remarks Does not require 20h of parameter scratch space in 64-bit mode. +; +%if TMPL_BITS == 16 +BS3_GLOBAL_NAME_EX TMPL_NM(Bs3SwitchToPAE16_V86_Safe), function , 0 +%endif +BS3_PROC_BEGIN_MODE Bs3SwitchToPAE16_V86, BS3_PBC_NEAR +%ifdef TMPL_PAE16_V86 + ret + +%else + ; + ; Convert the return address and jump to the 16-bit code segment. + ; + %if TMPL_BITS != 16 + shl xPRE [xSP], TMPL_BITS - 16 + add xSP, (TMPL_BITS - 16) / 8 + jmp .sixteen_bit_segment +BS3_BEGIN_TEXT16 + BS3_SET_BITS TMPL_BITS +BS3_GLOBAL_LOCAL_LABEL .sixteen_bit_segment + %endif + + ; + ; Switch to 16-bit PAE16 and from there to V8086. + ; + extern TMPL_NM(Bs3SwitchToPAE16) + call TMPL_NM(Bs3SwitchToPAE16) + BS3_SET_BITS 16 + + ; + ; Switch to v8086 mode (return address is already 16-bit). + ; + extern _Bs3SwitchTo16BitV86_c16 + jmp _Bs3SwitchTo16BitV86_c16 +%endif +BS3_PROC_END_MODE Bs3SwitchToPAE16_V86 + + +%if TMPL_BITS == 16 +;; +; Custom far stub. +BS3_BEGIN_TEXT16_FARSTUBS +BS3_PROC_BEGIN_MODE Bs3SwitchToPAE16_V86, BS3_PBC_FAR + inc bp + push bp + mov bp, sp + + ; Call the real thing. + call TMPL_NM(Bs3SwitchToPAE16_V86) + + %if !BS3_MODE_IS_RM_OR_V86(TMPL_MODE) + ; Jmp to common code for the tedious conversion. + BS3_EXTERN_CMN Bs3SwitchHlpConvProtModeRetfPopBpDecBpAndReturn + jmp Bs3SwitchHlpConvProtModeRetfPopBpDecBpAndReturn + %else + pop bp + dec bp + retf + %endif +BS3_PROC_END_MODE Bs3SwitchToPAE16_V86 + +%else +;; +; Safe far return to non-BS3TEXT16 code. +BS3_EXTERN_CMN Bs3SwitchHlpConvFlatRetToRetfProtMode +BS3_BEGIN_TEXT16 +BS3_SET_BITS TMPL_BITS +BS3_PROC_BEGIN_MODE Bs3SwitchToPAE16_V86_Safe, BS3_PBC_NEAR + call Bs3SwitchHlpConvFlatRetToRetfProtMode ; Special internal function. Uses nothing, but modifies the stack. + call TMPL_NM(Bs3SwitchToPAE16_V86) + BS3_SET_BITS 16 + retf +BS3_PROC_END_MODE Bs3SwitchToPAE16_V86_Safe +%endif + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-SwitchToPAE32.asm b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-SwitchToPAE32.asm new file mode 100644 index 00000000..ebd45c0c --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-SwitchToPAE32.asm @@ -0,0 +1,192 @@ +; $Id: bs3-mode-SwitchToPAE32.asm $ +;; @file +; BS3Kit - Bs3SwitchToPAE32 +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + +%include "bs3kit-template-header.mac" + + +;; +; Switch to PAE paged protected mode from any other mode. +; +; @cproto BS3_DECL(void) Bs3SwitchToPAE32(void); +; +; @uses Nothing (except high 32-bit register parts), upper part of ESP is +; cleared if caller is in 16-bit mode. +; +; @remarks Obviously returns to 32-bit mode, even if the caller was +; in 16-bit or 64-bit mode. It doesn't not preserve the callers +; ring, but instead changes to ring-0. +; +; @remarks Does not require 20h of parameter scratch space in 64-bit mode. +; +BS3_GLOBAL_NAME_EX TMPL_NM(Bs3SwitchToPAE32_Safe), function, 0 +BS3_PROC_BEGIN_MODE Bs3SwitchToPAE32, BS3_PBC_NEAR +%ifdef TMPL_PAE32 + ret + +%elif BS3_MODE_IS_V86(TMPL_MODE) + ; + ; V8086 - Switch to 16-bit ring-0 and call worker for that mode. + ; + extern BS3_CMN_NM(Bs3SwitchToRing0) + call BS3_CMN_NM(Bs3SwitchToRing0) + extern %[BS3_MODE_R0_NM_ %+ TMPL_MODE](Bs3SwitchToPAE32) + jmp %[BS3_MODE_R0_NM_ %+ TMPL_MODE](Bs3SwitchToPAE32) + +%else + ; + ; Switch to real mode. + ; + %if TMPL_BITS != 32 + %if TMPL_BITS > 32 + shl xPRE [xSP], 32 ; Adjust the return address from 64-bit to 32-bit. + add rsp, xCB - 4 + %else + push word 0 ; Reserve space to expand the return address. + %endif + %endif + %if TMPL_BITS != 16 + ; Must be in 16-bit segment when calling Bs3SwitchTo16Bit. + jmp .sixteen_bit_segment +BS3_BEGIN_TEXT16 + BS3_SET_BITS TMPL_BITS +BS3_GLOBAL_LOCAL_LABEL .sixteen_bit_segment + %endif + + ; + ; Switch to real mode. + ; + extern TMPL_NM(Bs3SwitchToRM) + call TMPL_NM(Bs3SwitchToRM) + BS3_SET_BITS 16 + + push eax + push ecx + pushfd + + ; + ; Get the page directory (returned in eax). + ; Will lazy init page tables (in 16-bit prot mode). + ; + extern NAME(Bs3PagingGetRootForPAE32_rm) + call NAME(Bs3PagingGetRootForPAE32_rm) + + cli + mov cr3, eax + + ; + ; Make sure PAE, PSE, and VME are enabled (former two require pentium pro, latter 486). + ; + mov eax, cr4 + mov ecx, eax + or eax, X86_CR4_PAE | X86_CR4_PSE | X86_CR4_VME + cmp eax, ecx + je .cr4_is_fine + mov cr4, eax +.cr4_is_fine: + + ; + ; Load the GDT and enable PE32. + ; +BS3_EXTERN_SYSTEM16 Bs3LgdtDef_Gdt +BS3_EXTERN_SYSTEM16 Bs3Lgdt_Gdt +BS3_BEGIN_TEXT16 + mov ax, BS3SYSTEM16 + mov ds, ax + lgdt [Bs3LgdtDef_Gdt] ; Will only load 24-bit base! + + mov eax, cr0 + or eax, X86_CR0_PE | X86_CR0_PG + mov cr0, eax + jmp BS3_SEL_R0_CS32:dword .thirty_two_bit wrt FLAT +BS3_BEGIN_TEXT32 +BS3_GLOBAL_LOCAL_LABEL .thirty_two_bit + + ; + ; Convert the (now) real mode stack pointer to 32-bit flat. + ; + xor eax, eax + mov ax, ss + shl eax, 4 + and esp, 0ffffh + add esp, eax + + mov ax, BS3_SEL_R0_SS32 + mov ss, ax + + ; + ; Call rountine for doing mode specific setups. + ; + extern NAME(Bs3EnteredMode_pae32) + call NAME(Bs3EnteredMode_pae32) + + ; Load full 32-bit GDT base address. + lgdt [Bs3Lgdt_Gdt wrt FLAT] + + ; + ; Restore ecx, eax and flags (IF). + ; + %if TMPL_BITS < 32 + movzx eax, word [esp + 12 + 2] ; Load return address. + add eax, BS3_ADDR_BS3TEXT16 ; Convert it to a flat address. + mov [esp + 12], eax ; Store it in the place right for 32-bit returns. + %endif + popfd + pop ecx + pop eax + ret + + %if TMPL_BITS != 32 +TMPL_BEGIN_TEXT + %endif +%endif +BS3_PROC_END_MODE Bs3SwitchToPAE32 + + +%if TMPL_BITS == 16 +;; +; Custom far stub. +BS3_BEGIN_TEXT16_FARSTUBS +BS3_PROC_BEGIN_MODE Bs3SwitchToPAE32, BS3_PBC_FAR + inc bp + push bp + mov bp, sp + + ; Call the real thing. + call TMPL_NM(Bs3SwitchToPAE32) + BS3_SET_BITS 32 + + ; Jmp to common code for the tedious conversion. + %if BS3_MODE_IS_RM_OR_V86(TMPL_MODE) + extern _Bs3SwitchHlpConvRealModeRetfPopBpDecBpAndReturn_c32 + jmp _Bs3SwitchHlpConvRealModeRetfPopBpDecBpAndReturn_c32 + %else + extern _Bs3SwitchHlpConvProtModeRetfPopBpDecBpAndReturn_c32 + jmp _Bs3SwitchHlpConvProtModeRetfPopBpDecBpAndReturn_c32 + %endif + BS3_SET_BITS 16 +BS3_PROC_END_MODE Bs3SwitchToPAE32 +%endif + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-SwitchToPAE32_16.asm b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-SwitchToPAE32_16.asm new file mode 100644 index 00000000..4f7e1c71 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-SwitchToPAE32_16.asm @@ -0,0 +1,122 @@ +; $Id: bs3-mode-SwitchToPAE32_16.asm $ +;; @file +; BS3Kit - Bs3SwitchToPAE32_16 +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + +%include "bs3kit-template-header.mac" + + +;; +; Switch to 16-bit code under 32-bit PAE paged protected mode sys/tss from any other mode. +; +; @cproto BS3_DECL(void) Bs3SwitchToPAE32_16(void); +; +; @uses Nothing (except high 32-bit register parts). +; +; @remarks Obviously returns to 16-bit mode, even if the caller was +; in 32-bit or 64-bit mode. +; +; @remarks Does not require 20h of parameter scratch space in 64-bit mode. +; +%if TMPL_BITS == 16 +BS3_GLOBAL_NAME_EX TMPL_NM(Bs3SwitchToPAE32_16_Safe), function , 0 +%endif +BS3_PROC_BEGIN_MODE Bs3SwitchToPAE32_16, BS3_PBC_NEAR +%if TMPL_MODE == BS3_MODE_PAE32_16 + ret + +%elif TMPL_MODE == BS3_MODE_PAE32 + extern BS3_CMN_NM(Bs3SwitchTo16Bit) + jmp BS3_CMN_NM(Bs3SwitchTo16Bit) + +%else + ; + ; Switch to PAE32. + ; + extern TMPL_NM(Bs3SwitchToPAE32) + call TMPL_NM(Bs3SwitchToPAE32) + BS3_SET_BITS 32 + + ; + ; Make sure we're in the 16-bit segment and then do the switch to 16-bit. + ; + %if TMPL_BITS != 16 + jmp .sixteen_bit_segment +BS3_BEGIN_TEXT16 + BS3_SET_BITS TMPL_BITS +BS3_GLOBAL_LOCAL_LABEL .sixteen_bit_segment + %endif + extern _Bs3SwitchTo16Bit_c32 + %if TMPL_BITS == 32 + jmp _Bs3SwitchTo16Bit_c32 + %else + call _Bs3SwitchTo16Bit_c32 + BS3_SET_BITS 16 + %if TMPL_BITS == 16 + ret + %else + ret 6 ; Return and pop 6 bytes of "parameters" (unused return address). + %endif + %endif +%endif +BS3_PROC_END_MODE Bs3SwitchToPAE32_16 + + +%if TMPL_BITS == 16 +;; +; Custom far stub. +BS3_BEGIN_TEXT16_FARSTUBS +BS3_PROC_BEGIN_MODE Bs3SwitchToPAE32_16, BS3_PBC_FAR + inc bp + push bp + mov bp, sp + + ; Call the real thing. + call TMPL_NM(Bs3SwitchToPAE32_16) + + %if BS3_MODE_IS_RM_OR_V86(TMPL_MODE) + ; Jmp to common code for the tedious conversion. + BS3_EXTERN_CMN Bs3SwitchHlpConvRealModeRetfPopBpDecBpAndReturn + jmp Bs3SwitchHlpConvRealModeRetfPopBpDecBpAndReturn + %else + pop bp + dec bp + retf + %endif +BS3_PROC_END_MODE Bs3SwitchToPAE32_16 + +%else +;; +; Safe far return to non-BS3TEXT16 code. +BS3_EXTERN_CMN Bs3SwitchHlpConvFlatRetToRetfProtMode +BS3_BEGIN_TEXT16 +BS3_SET_BITS TMPL_BITS +BS3_PROC_BEGIN_MODE Bs3SwitchToPAE32_16_Safe, BS3_PBC_NEAR + call Bs3SwitchHlpConvFlatRetToRetfProtMode ; Special internal function. Uses nothing, but modifies the stack. + call TMPL_NM(Bs3SwitchToPAE32_16) + BS3_SET_BITS 16 + retf +BS3_PROC_END_MODE Bs3SwitchToPAE32_16_Safe +%endif + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-SwitchToPAEV86.asm b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-SwitchToPAEV86.asm new file mode 100644 index 00000000..cbf29fee --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-SwitchToPAEV86.asm @@ -0,0 +1,108 @@ +; $Id: bs3-mode-SwitchToPAEV86.asm $ +;; @file +; BS3Kit - Bs3SwitchToPAEV86 +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + +%include "bs3kit-template-header.mac" + + +;; +; Switch to 16-bit v8086 PAE paged protected mode with 32-bit sys+tss from any other mode. +; +; @cproto BS3_DECL(void) Bs3SwitchToPAEV86(void); +; +; @uses Nothing (except high 32-bit register parts). +; +; @remarks Obviously returns to 16-bit v8086 mode, even if the caller was +; in 32-bit or 64-bit mode. +; +; @remarks Does not require 20h of parameter scratch space in 64-bit mode. +; +%if TMPL_BITS == 16 +BS3_GLOBAL_NAME_EX TMPL_NM(Bs3SwitchToPAEV86_Safe), function , 0 +%endif +BS3_PROC_BEGIN_MODE Bs3SwitchToPAEV86, BS3_PBC_NEAR +%if TMPL_MODE == BS3_MODE_PAEV86 + ret + +%else + ; + ; Switch to 32-bit PAE32 and from there to V8086. + ; + extern TMPL_NM(Bs3SwitchToPAE32) + call TMPL_NM(Bs3SwitchToPAE32) + BS3_SET_BITS 32 + + ; + ; Switch to v8086 mode after adjusting the return address. + ; + %if TMPL_BITS == 16 + push word [esp] + mov word [esp + 2], 0 + %elif TMPL_BITS == 64 + pop dword [esp + 4] + %endif + extern _Bs3SwitchTo16BitV86_c32 + jmp _Bs3SwitchTo16BitV86_c32 +%endif +BS3_PROC_END_MODE Bs3SwitchToPAEV86 + + +%if TMPL_BITS == 16 +;; +; Custom far stub. +BS3_BEGIN_TEXT16_FARSTUBS +BS3_PROC_BEGIN_MODE Bs3SwitchToPAEV86, BS3_PBC_FAR + inc bp + push bp + mov bp, sp + + ; Call the real thing. + call TMPL_NM(Bs3SwitchToPAEV86) + + %if !BS3_MODE_IS_RM_OR_V86(TMPL_MODE) + ; Jmp to common code for the tedious conversion. + BS3_EXTERN_CMN Bs3SwitchHlpConvProtModeRetfPopBpDecBpAndReturn + jmp Bs3SwitchHlpConvProtModeRetfPopBpDecBpAndReturn + %else + pop bp + dec bp + retf + %endif +BS3_PROC_END_MODE Bs3SwitchToPAEV86 + +%else +;; +; Safe far return to non-BS3TEXT16 code. +BS3_EXTERN_CMN Bs3SwitchHlpConvFlatRetToRetfProtMode +BS3_BEGIN_TEXT16 +BS3_SET_BITS TMPL_BITS +BS3_PROC_BEGIN_MODE Bs3SwitchToPAEV86_Safe, BS3_PBC_NEAR + call Bs3SwitchHlpConvFlatRetToRetfProtMode ; Special internal function. Uses nothing, but modifies the stack. + call TMPL_NM(Bs3SwitchToPAEV86) + BS3_SET_BITS 16 + retf +BS3_PROC_END_MODE Bs3SwitchToPAEV86_Safe +%endif + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-SwitchToPE16.asm b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-SwitchToPE16.asm new file mode 100644 index 00000000..d4cabc5d --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-SwitchToPE16.asm @@ -0,0 +1,188 @@ +; $Id: bs3-mode-SwitchToPE16.asm $ +;; @file +; BS3Kit - Bs3SwitchToPE16 +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + +%include "bs3kit-template-header.mac" + + +;; +; Switch to 16-bit unpaged protected mode from any other mode. +; +; @cproto BS3_DECL(void) Bs3SwitchToPE16(void); +; +; @uses Nothing (except high 32-bit register parts). +; +; @remarks Obviously returns to 16-bit mode, even if the caller was +; in 32-bit or 64-bit mode. +; +; @remarks Does not require 20h of parameter scratch space in 64-bit mode. +; +%if TMPL_BITS == 16 +BS3_GLOBAL_NAME_EX TMPL_NM(Bs3SwitchToPE16_Safe), function , 0 +%endif +BS3_PROC_BEGIN_MODE Bs3SwitchToPE16, BS3_PBC_NEAR +%ifdef TMPL_PE16 + extern BS3_CMN_NM(Bs3SwitchToRing0) + call BS3_CMN_NM(Bs3SwitchToRing0) + push ax + mov ax, BS3_SEL_R0_DS16 + mov ds, ax + mov es, ax + pop ax + ret + +%elif BS3_MODE_IS_V86(TMPL_MODE) + ; + ; V8086 - Switch to 16-bit ring-0 and call worker for that mode. + ; + extern BS3_CMN_NM(Bs3SwitchToRing0) + call BS3_CMN_NM(Bs3SwitchToRing0) + extern %[BS3_MODE_R0_NM_ %+ TMPL_MODE](Bs3SwitchToPE16) + jmp %[BS3_MODE_R0_NM_ %+ TMPL_MODE](Bs3SwitchToPE16) + +%else + ; + ; Switch to 16-bit mode and prepare for returning in 16-bit mode. + ; + %if TMPL_BITS != 16 + shl xPRE [xSP], TMPL_BITS - 16 ; Adjust the return address. + add xSP, xCB - 2 + + ; Must be in 16-bit segment when calling Bs3SwitchTo16Bit. + jmp .sixteen_bit_segment +BS3_BEGIN_TEXT16 + BS3_SET_BITS TMPL_BITS +BS3_GLOBAL_LOCAL_LABEL .sixteen_bit_segment + %endif + + ; + ; Switch to real mode. + ; + extern TMPL_NM(Bs3SwitchToRM) + call TMPL_NM(Bs3SwitchToRM) + BS3_SET_BITS 16 + + push ax + push cx + pushf + cli + + ; + ; Load the GDT and enable PE16. + ; +BS3_EXTERN_SYSTEM16 Bs3Lgdt_Gdt +BS3_EXTERN_SYSTEM16 Bs3LgdtDef_Gdt +BS3_BEGIN_TEXT16 + mov ax, BS3SYSTEM16 + mov ds, ax + lgdt [Bs3LgdtDef_Gdt] ; Will only load 24-bit base! + + smsw ax + or ax, X86_CR0_PE + lmsw ax + + ; + ; Convert from real mode stack to protected mode stack. + ; + mov ax, .p16_stack + extern NAME(Bs3ConvertRMStackToP16UsingCxReturnToAx_c16) + jmp NAME(Bs3ConvertRMStackToP16UsingCxReturnToAx_c16) +.p16_stack: + + ; + ; Call routine for doing mode specific setups. + ; + extern NAME(Bs3EnteredMode_pe16) + call NAME(Bs3EnteredMode_pe16) + + ; + ; Load full 32-bit GDT base address from 32-bit segment, if 386+ CPU. + ; + BS3_EXTERN_DATA16 g_uBs3CpuDetected + BS3_BEGIN_TEXT16 + cmp byte [g_uBs3CpuDetected], BS3CPU_80386 + jb .old_cpu_skip_32bit_lgdt + push ds + mov ax, BS3_SEL_SYSTEM16 + mov ds, ax + jmp dword BS3_SEL_R0_CS32:.load_full_gdt_base wrt FLAT +.load_full_gdt_base: + BS3_SET_BITS 32 + lgdt [Bs3Lgdt_Gdt wrt BS3SYSTEM16] + jmp BS3_SEL_R0_CS16:.back_to_16bit +.back_to_16bit: + BS3_SET_BITS 16 + pop ds +.old_cpu_skip_32bit_lgdt: + + popf + pop cx + pop ax + ret + + %if TMPL_BITS != 16 +TMPL_BEGIN_TEXT + %endif +%endif +BS3_PROC_END_MODE Bs3SwitchToPE16 + + +%if TMPL_BITS == 16 +;; +; Custom far stub. +BS3_BEGIN_TEXT16_FARSTUBS +BS3_PROC_BEGIN_MODE Bs3SwitchToPE16, BS3_PBC_FAR + inc bp + push bp + mov bp, sp + + ; Call the real thing. + call TMPL_NM(Bs3SwitchToPE16) + + %if BS3_MODE_IS_RM_OR_V86(TMPL_MODE) + ; Jmp to common code for the tedious conversion. + BS3_EXTERN_CMN Bs3SwitchHlpConvRealModeRetfPopBpDecBpAndReturn + jmp Bs3SwitchHlpConvRealModeRetfPopBpDecBpAndReturn + %else + pop bp + dec bp + retf + %endif +BS3_PROC_END_MODE Bs3SwitchToPE16 + +%else +;; +; Safe far return to non-BS3TEXT16 code. +BS3_EXTERN_CMN Bs3SwitchHlpConvFlatRetToRetfProtMode +BS3_BEGIN_TEXT16 +BS3_SET_BITS TMPL_BITS +BS3_PROC_BEGIN_MODE Bs3SwitchToPE16_Safe, BS3_PBC_NEAR + call Bs3SwitchHlpConvFlatRetToRetfProtMode ; Special internal function. Uses nothing, but modifies the stack. + call TMPL_NM(Bs3SwitchToPE16) + BS3_SET_BITS 16 + retf +BS3_PROC_END_MODE Bs3SwitchToPE16_Safe +%endif + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-SwitchToPE16_32.asm b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-SwitchToPE16_32.asm new file mode 100644 index 00000000..d6645ebd --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-SwitchToPE16_32.asm @@ -0,0 +1,104 @@ +; $Id: bs3-mode-SwitchToPE16_32.asm $ +;; @file +; BS3Kit - Bs3SwitchToPE16_32 +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + +%include "bs3kit-template-header.mac" + + +;; +; Switch to 32-bit code under 16-bit unpaged protected mode sys/tss from any other mode. +; +; @cproto BS3_DECL(void) Bs3SwitchToPE16_32(void); +; +; @uses Nothing (except high 32-bit register parts). +; +; @remarks Obviously returns to 32-bit mode, even if the caller was +; in 16-bit or 64-bit mode. +; +; @remarks Does not require 20h of parameter scratch space in 64-bit mode. +; +BS3_GLOBAL_NAME_EX TMPL_NM(Bs3SwitchToPE16_32_Safe), function, 0 +BS3_PROC_BEGIN_MODE Bs3SwitchToPE16_32, BS3_PBC_NEAR +%ifdef TMPL_PE16_32 + ret + +%else + ; + ; Make sure we're in the 16-bit segment and then call Bs3SwitchToPE16. + ; + %if TMPL_BITS != 16 + jmp .sixteen_bit_segment +BS3_BEGIN_TEXT16 + BS3_SET_BITS TMPL_BITS +BS3_GLOBAL_LOCAL_LABEL .sixteen_bit_segment + %endif + extern TMPL_NM(Bs3SwitchToPE16) + call TMPL_NM(Bs3SwitchToPE16) + BS3_SET_BITS 16 + + ; + ; Switch to 32-bit mode. + ; + extern _Bs3SwitchTo32Bit_c16 + %if TMPL_BITS == 16 + jmp _Bs3SwitchTo32Bit_c16 + %else + call _Bs3SwitchTo32Bit_c16 + BS3_SET_BITS 32 + %if TMPL_BITS == 32 + ret + %else + ret 4 ; Return and pop 4 bytes of "parameters" (unused return address). + %endif + %endif +%endif +BS3_PROC_END_MODE Bs3SwitchToPE16_32 + + +%if TMPL_BITS == 16 +;; +; Custom far stub. +BS3_BEGIN_TEXT16_FARSTUBS +BS3_PROC_BEGIN_MODE Bs3SwitchToPE16_32, BS3_PBC_FAR + inc bp + push bp + mov bp, sp + + ; Call the real thing. + call TMPL_NM(Bs3SwitchToPE16_32) + BS3_SET_BITS 32 + + ; Jmp to common code for the tedious conversion. + %if BS3_MODE_IS_RM_OR_V86(TMPL_MODE) + extern _Bs3SwitchHlpConvRealModeRetfPopBpDecBpAndReturn_c32 + jmp _Bs3SwitchHlpConvRealModeRetfPopBpDecBpAndReturn_c32 + %else + extern _Bs3SwitchHlpConvProtModeRetfPopBpDecBpAndReturn_c32 + jmp _Bs3SwitchHlpConvProtModeRetfPopBpDecBpAndReturn_c32 + %endif + BS3_SET_BITS 16 +BS3_PROC_END_MODE Bs3SwitchToPE16_32 +%endif + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-SwitchToPE16_V86.asm b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-SwitchToPE16_V86.asm new file mode 100644 index 00000000..384c204a --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-SwitchToPE16_V86.asm @@ -0,0 +1,114 @@ +; $Id: bs3-mode-SwitchToPE16_V86.asm $ +;; @file +; BS3Kit - Bs3SwitchToPE16_V86 +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + +%include "bs3kit-template-header.mac" + + +;; +; Switch to 16-bit unpaged protected mode with 16-bit sys+tss from any other mode. +; +; @cproto BS3_DECL(void) Bs3SwitchToPE16(void); +; +; @uses Nothing (except high 32-bit register parts). +; +; @remarks Obviously returns to 16-bit v8086 mode, even if the caller was +; in 16-bit, 32-bit or 64-bit mode. +; +; @remarks Does not require 20h of parameter scratch space in 64-bit mode. +; +%if TMPL_BITS == 16 +BS3_GLOBAL_NAME_EX TMPL_NM(Bs3SwitchToPE16_V86_Safe), function , 0 +%endif +BS3_PROC_BEGIN_MODE Bs3SwitchToPE16_V86, BS3_PBC_NEAR +%ifdef TMPL_PE16_V86 + ret + +%else + ; + ; Convert the return address and jump to the 16-bit code segment. + ; + %if TMPL_BITS != 16 + shl xPRE [xSP], TMPL_BITS - 16 + add xSP, (TMPL_BITS - 16) / 8 + jmp .sixteen_bit_segment +BS3_BEGIN_TEXT16 + BS3_SET_BITS TMPL_BITS +BS3_GLOBAL_LOCAL_LABEL .sixteen_bit_segment + %endif + + ; + ; Switch to 16-bit PE16 and from there to V8086. + ; + extern TMPL_NM(Bs3SwitchToPE16) + call TMPL_NM(Bs3SwitchToPE16) + BS3_SET_BITS 16 + + ; + ; Switch to v8086 mode (return address is already 16-bit). + ; + extern _Bs3SwitchTo16BitV86_c16 + jmp _Bs3SwitchTo16BitV86_c16 +%endif +BS3_PROC_END_MODE Bs3SwitchToPE16_V86 + + +%if TMPL_BITS == 16 +;; +; Custom far stub. +BS3_BEGIN_TEXT16_FARSTUBS +BS3_PROC_BEGIN_MODE Bs3SwitchToPE16_V86, BS3_PBC_FAR + inc bp + push bp + mov bp, sp + + ; Call the real thing. + call TMPL_NM(Bs3SwitchToPE16_V86) + + %if !BS3_MODE_IS_RM_OR_V86(TMPL_MODE) + ; Jmp to common code for the tedious conversion. + BS3_EXTERN_CMN Bs3SwitchHlpConvProtModeRetfPopBpDecBpAndReturn + jmp Bs3SwitchHlpConvProtModeRetfPopBpDecBpAndReturn + %else + pop bp + dec bp + retf + %endif +BS3_PROC_END_MODE Bs3SwitchToPE16_V86 + +%else +;; +; Safe far return to non-BS3TEXT16 code. +BS3_EXTERN_CMN Bs3SwitchHlpConvFlatRetToRetfProtMode +BS3_BEGIN_TEXT16 +BS3_SET_BITS TMPL_BITS +BS3_PROC_BEGIN_MODE Bs3SwitchToPE16_V86_Safe, BS3_PBC_NEAR + call Bs3SwitchHlpConvFlatRetToRetfProtMode ; Special internal function. Uses nothing, but modifies the stack. + call TMPL_NM(Bs3SwitchToPE16_V86) + BS3_SET_BITS 16 + retf +BS3_PROC_END_MODE Bs3SwitchToPE16_V86_Safe +%endif + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-SwitchToPE32.asm b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-SwitchToPE32.asm new file mode 100644 index 00000000..01628e65 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-SwitchToPE32.asm @@ -0,0 +1,169 @@ +; $Id: bs3-mode-SwitchToPE32.asm $ +;; @file +; BS3Kit - Bs3SwitchToPE32 +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + +%include "bs3kit-template-header.mac" + + +;; +; Switch to 32-bit unpaged protected mode from any other mode. +; +; @cproto BS3_DECL(void) Bs3SwitchToPE32(void); +; +; @uses Nothing (except high 32-bit register parts), upper part of ESP is +; cleared if caller is in 16-bit mode. +; +; @remarks Obviously returns to 32-bit mode, even if the caller was +; in 16-bit or 64-bit mode. +; +; @remarks Does not require 20h of parameter scratch space in 64-bit mode. +; +BS3_GLOBAL_NAME_EX TMPL_NM(Bs3SwitchToPE32_Safe), function, 0 +BS3_PROC_BEGIN_MODE Bs3SwitchToPE32, BS3_PBC_NEAR +%ifdef TMPL_PE32 + ret + +%elif BS3_MODE_IS_V86(TMPL_MODE) + ; + ; V8086 - Switch to 16-bit ring-0 and call worker for that mode. + ; + extern BS3_CMN_NM(Bs3SwitchToRing0) + call BS3_CMN_NM(Bs3SwitchToRing0) + extern %[BS3_MODE_R0_NM_ %+ TMPL_MODE](Bs3SwitchToPE32) + jmp %[BS3_MODE_R0_NM_ %+ TMPL_MODE](Bs3SwitchToPE32) + +%else + ; + ; Switch to real mode. + ; + %if TMPL_BITS != 32 + %if TMPL_BITS > 32 + shl xPRE [xSP], 32 ; Adjust the return address from 64-bit to 32-bit. + add rsp, xCB - 4 + %else + push word 0 ; Reserve space to expand the return address. + %endif + %endif + %if TMPL_BITS != 16 + ; Must be in 16-bit segment when calling Bs3SwitchTo16Bit. + jmp .sixteen_bit_segment +BS3_BEGIN_TEXT16 + BS3_SET_BITS TMPL_BITS +BS3_GLOBAL_LOCAL_LABEL .sixteen_bit_segment + %endif + ; + ; Switch to real mode. + ; + extern TMPL_NM(Bs3SwitchToRM) + call TMPL_NM(Bs3SwitchToRM) + BS3_SET_BITS 16 + + push eax + pushfd + cli + + ; + ; Load the GDT and enable PE32. + ; +BS3_EXTERN_SYSTEM16 Bs3LgdtDef_Gdt +BS3_EXTERN_SYSTEM16 Bs3Lgdt_Gdt +BS3_BEGIN_TEXT16 + mov ax, BS3SYSTEM16 + mov ds, ax + lgdt [Bs3LgdtDef_Gdt] ; Will only load 24-bit base! + + mov eax, cr0 + or eax, X86_CR0_PE + mov cr0, eax + jmp BS3_SEL_R0_CS32:dword .thirty_two_bit wrt FLAT +BS3_BEGIN_TEXT32 +BS3_GLOBAL_LOCAL_LABEL .thirty_two_bit + + ; + ; Convert the (now) real mode stack pointer to 32-bit flat. + ; + xor eax, eax + mov ax, ss + shl eax, 4 + and esp, 0ffffh + add esp, eax + + mov ax, BS3_SEL_R0_SS32 + mov ss, ax + + ; + ; Call rountine for doing mode specific setups. + ; + extern NAME(Bs3EnteredMode_pe32) + call NAME(Bs3EnteredMode_pe32) + + ; Load full 32-bit GDT base address. + lgdt [Bs3Lgdt_Gdt wrt FLAT] + + ; + ; Restore eax and flags (IF). + ; + %if TMPL_BITS < 32 + and esp, 0ffffh ; Make sure the high word is zero. + movzx eax, word [esp + 8 + 2] ; Load return address. + add eax, BS3_ADDR_BS3TEXT16 ; Convert it to a flat address. + mov [esp + 8], eax ; Store it in the place right for 32-bit returns. + %endif + popfd + pop eax + ret + + %if TMPL_BITS != 32 +TMPL_BEGIN_TEXT + %endif +%endif +BS3_PROC_END_MODE Bs3SwitchToPE32 + + +%if TMPL_BITS == 16 +;; +; Custom far stub. +BS3_BEGIN_TEXT16_FARSTUBS +BS3_PROC_BEGIN_MODE Bs3SwitchToPE32, BS3_PBC_FAR + inc bp + push bp + mov bp, sp + + ; Call the real thing. + call TMPL_NM(Bs3SwitchToPE32) + BS3_SET_BITS 32 + + ; Jmp to common code for the tedious conversion. + %if BS3_MODE_IS_RM_OR_V86(TMPL_MODE) + extern _Bs3SwitchHlpConvRealModeRetfPopBpDecBpAndReturn_c32 + jmp _Bs3SwitchHlpConvRealModeRetfPopBpDecBpAndReturn_c32 + %else + extern _Bs3SwitchHlpConvProtModeRetfPopBpDecBpAndReturn_c32 + jmp _Bs3SwitchHlpConvProtModeRetfPopBpDecBpAndReturn_c32 + %endif + BS3_SET_BITS 16 +BS3_PROC_END_MODE Bs3SwitchToPE32 +%endif + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-SwitchToPE32_16.asm b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-SwitchToPE32_16.asm new file mode 100644 index 00000000..8712d8e8 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-SwitchToPE32_16.asm @@ -0,0 +1,122 @@ +; $Id: bs3-mode-SwitchToPE32_16.asm $ +;; @file +; BS3Kit - Bs3SwitchToPE32_16 +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + +%include "bs3kit-template-header.mac" + + +;; +; Switch to 16-bit code under 32-bit unpaged protected mode sys/tss from any other mode. +; +; @cproto BS3_DECL(void) Bs3SwitchToPE32_16(void); +; +; @uses Nothing (except high 32-bit register parts). +; +; @remarks Obviously returns to 16-bit mode, even if the caller was +; in 32-bit or 64-bit mode. +; +; @remarks Does not require 20h of parameter scratch space in 64-bit mode. +; +%if TMPL_BITS == 16 +BS3_GLOBAL_NAME_EX TMPL_NM(Bs3SwitchToPE32_16_Safe), function , 0 +%endif +BS3_PROC_BEGIN_MODE Bs3SwitchToPE32_16, BS3_PBC_NEAR +%if TMPL_MODE == BS3_MODE_PE32_16 + ret + +%elif TMPL_MODE == BS3_MODE_PE32 + extern BS3_CMN_NM(Bs3SwitchTo16Bit) + jmp BS3_CMN_NM(Bs3SwitchTo16Bit) + +%else + ; + ; Switch to PE32. + ; + extern TMPL_NM(Bs3SwitchToPE32) + call TMPL_NM(Bs3SwitchToPE32) + BS3_SET_BITS 32 + + ; + ; Make sure we're in the 16-bit segment and then do the switch to 16-bit. + ; + %if TMPL_BITS != 16 + jmp .sixteen_bit_segment +BS3_BEGIN_TEXT16 + BS3_SET_BITS TMPL_BITS +BS3_GLOBAL_LOCAL_LABEL .sixteen_bit_segment + %endif + extern _Bs3SwitchTo16Bit_c32 + %if TMPL_BITS == 32 + jmp _Bs3SwitchTo16Bit_c32 + %else + call _Bs3SwitchTo16Bit_c32 + BS3_SET_BITS 16 + %if TMPL_BITS == 16 + ret + %else + ret 6 ; Return and pop 6 bytes of "parameters" (unused return address). + %endif + %endif +%endif +BS3_PROC_END_MODE Bs3SwitchToPE32_16 + + +%if TMPL_BITS == 16 +;; +; Custom far stub. +BS3_BEGIN_TEXT16_FARSTUBS +BS3_PROC_BEGIN_MODE Bs3SwitchToPE32_16, BS3_PBC_FAR + inc bp + push bp + mov bp, sp + + ; Call the real thing. + call TMPL_NM(Bs3SwitchToPE32_16) + + %if BS3_MODE_IS_RM_OR_V86(TMPL_MODE) + ; Jmp to common code for the tedious conversion. + BS3_EXTERN_CMN Bs3SwitchHlpConvRealModeRetfPopBpDecBpAndReturn + jmp Bs3SwitchHlpConvRealModeRetfPopBpDecBpAndReturn + %else + pop bp + dec bp + retf + %endif +BS3_PROC_END_MODE Bs3SwitchToPE32_16 + +%else +;; +; Safe far return to non-BS3TEXT16 code. +BS3_EXTERN_CMN Bs3SwitchHlpConvFlatRetToRetfProtMode +BS3_BEGIN_TEXT16 +BS3_SET_BITS TMPL_BITS +BS3_PROC_BEGIN_MODE Bs3SwitchToPE32_16_Safe, BS3_PBC_NEAR + call Bs3SwitchHlpConvFlatRetToRetfProtMode ; Special internal function. Uses nothing, but modifies the stack. + call TMPL_NM(Bs3SwitchToPE32_16) + BS3_SET_BITS 16 + retf +BS3_PROC_END_MODE Bs3SwitchToPE32_16_Safe +%endif + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-SwitchToPEV86.asm b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-SwitchToPEV86.asm new file mode 100644 index 00000000..09f340c5 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-SwitchToPEV86.asm @@ -0,0 +1,108 @@ +; $Id: bs3-mode-SwitchToPEV86.asm $ +;; @file +; BS3Kit - Bs3SwitchToPEV86 +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + +%include "bs3kit-template-header.mac" + + +;; +; Switch to 16-bit v8086 unpaged protected mode with 32-bit sys+tss from any other mode. +; +; @cproto BS3_DECL(void) Bs3SwitchToPEV86(void); +; +; @uses Nothing (except high 32-bit register parts). +; +; @remarks Obviously returns to 16-bit v8086 mode, even if the caller was +; in 32-bit or 64-bit mode. +; +; @remarks Does not require 20h of parameter scratch space in 64-bit mode. +; +%if TMPL_BITS == 16 +BS3_GLOBAL_NAME_EX TMPL_NM(Bs3SwitchToPEV86_Safe), function , 0 +%endif +BS3_PROC_BEGIN_MODE Bs3SwitchToPEV86, BS3_PBC_NEAR +%if TMPL_MODE == BS3_MODE_PEV86 + ret + +%else + ; + ; Switch to 32-bit PE32 and from there to V8086. + ; + extern TMPL_NM(Bs3SwitchToPE32) + call TMPL_NM(Bs3SwitchToPE32) + BS3_SET_BITS 32 + + ; + ; Switch to v8086 mode after adjusting the return address. + ; + %if TMPL_BITS == 16 + push word [esp] + mov word [esp + 2], 0 + %elif TMPL_BITS == 64 + pop dword [esp + 4] + %endif + extern _Bs3SwitchTo16BitV86_c32 + jmp _Bs3SwitchTo16BitV86_c32 +%endif +BS3_PROC_END_MODE Bs3SwitchToPEV86 + + +%if TMPL_BITS == 16 +;; +; Custom far stub. +BS3_BEGIN_TEXT16_FARSTUBS +BS3_PROC_BEGIN_MODE Bs3SwitchToPEV86, BS3_PBC_FAR + inc bp + push bp + mov bp, sp + + ; Call the real thing. + call TMPL_NM(Bs3SwitchToPEV86) + + %if !BS3_MODE_IS_RM_OR_V86(TMPL_MODE) + ; Jmp to common code for the tedious conversion. + BS3_EXTERN_CMN Bs3SwitchHlpConvProtModeRetfPopBpDecBpAndReturn + jmp Bs3SwitchHlpConvProtModeRetfPopBpDecBpAndReturn + %else + pop bp + dec bp + retf + %endif +BS3_PROC_END_MODE Bs3SwitchToPEV86 + +%else +;; +; Safe far return to non-BS3TEXT16 code. +BS3_EXTERN_CMN Bs3SwitchHlpConvFlatRetToRetfProtMode +BS3_BEGIN_TEXT16 +BS3_SET_BITS TMPL_BITS +BS3_PROC_BEGIN_MODE Bs3SwitchToPEV86_Safe, BS3_PBC_NEAR + call Bs3SwitchHlpConvFlatRetToRetfProtMode ; Special internal function. Uses nothing, but modifies the stack. + call TMPL_NM(Bs3SwitchToPEV86) + BS3_SET_BITS 16 + retf +BS3_PROC_END_MODE Bs3SwitchToPEV86_Safe +%endif + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-SwitchToPP16.asm b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-SwitchToPP16.asm new file mode 100644 index 00000000..ce037266 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-SwitchToPP16.asm @@ -0,0 +1,248 @@ +; $Id: bs3-mode-SwitchToPP16.asm $ +;; @file +; BS3Kit - Bs3SwitchToPP16 +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + +;********************************************************************************************************************************* +;* Header Files * +;********************************************************************************************************************************* +%include "bs3kit-template-header.mac" + +;********************************************************************************************************************************* +;* External Symbols * +;********************************************************************************************************************************* +%ifndef TMPL_PP16 +BS3_BEGIN_TEXT16 +extern NAME(Bs3EnteredMode_pp16) + %ifdef TMPL_PP32 + BS3_EXTERN_CMN Bs3SwitchTo16Bit + %endif +TMPL_BEGIN_TEXT +%endif + + +;; +; Switch to 16-bit paged protected mode from any other mode. +; +; @cproto BS3_DECL(void) Bs3SwitchToPP16(void); +; +; @uses Nothing (except high 32-bit register parts). +; +; @remarks Obviously returns to 16-bit mode, even if the caller was +; in 32-bit or 64-bit mode. +; +; @remarks Does not require 20h of parameter scratch space in 64-bit mode. +; +%if TMPL_BITS == 16 +BS3_GLOBAL_NAME_EX TMPL_NM(Bs3SwitchToPP16_Safe), function , 0 +%endif +BS3_PROC_BEGIN_MODE Bs3SwitchToPP16, BS3_PBC_NEAR +%ifdef TMPL_PP16 + extern BS3_CMN_NM(Bs3SwitchToRing0) + call BS3_CMN_NM(Bs3SwitchToRing0) + push ax + mov ax, BS3_SEL_R0_DS16 + mov ds, ax + mov es, ax + pop ax + ret + +%elif BS3_MODE_IS_V86(TMPL_MODE) + ; + ; V8086 - Switch to 16-bit ring-0 and call worker for that mode. + ; + extern BS3_CMN_NM(Bs3SwitchToRing0) + call BS3_CMN_NM(Bs3SwitchToRing0) + extern %[BS3_MODE_R0_NM_ %+ TMPL_MODE](Bs3SwitchToPP16) + jmp %[BS3_MODE_R0_NM_ %+ TMPL_MODE](Bs3SwitchToPP16) + +%else + + ; + ; Switch to 16-bit text segment and prepare for returning in 16-bit mode. + ; + %if TMPL_BITS != 16 + shl xPRE [xSP], TMPL_BITS - 16 ; Adjust the return address. + add xSP, xCB - 2 + + ; Must be in 16-bit segment when calling Bs3SwitchToRM and Bs3SwitchTo16Bit. + jmp .sixteen_bit_segment +BS3_BEGIN_TEXT16 + BS3_SET_BITS TMPL_BITS +BS3_GLOBAL_LOCAL_LABEL .sixteen_bit_segment + %endif + + %ifdef TMPL_PP32 + ; + ; No need to go to real-mode here, we use the same CR3 and stuff. + ; Just switch to 32-bit mode and call the Bs3EnteredMode routine to + ; load the right descriptor tables. + ; + call Bs3SwitchTo16Bit + BS3_SET_BITS 16 + call NAME(Bs3EnteredMode_pp16) + ret + %else + + ; + ; Switch to real mode. + ; + extern TMPL_NM(Bs3SwitchToRM) + call TMPL_NM(Bs3SwitchToRM) + BS3_SET_BITS 16 + + push eax + push ecx + pushfd +%ifdef BS3_STRICT + mov ax, ds + cmp ax, BS3_ADDR_BS3DATA16 >> 4 + je .real_mode_ds_ok + hlt +.real_mode_ds_ok: +%endif + + ; + ; Get the page directory (returned in eax). + ; Will lazy init page tables (in 16-bit prot mode). + ; + extern NAME(Bs3PagingGetRootForPP16_rm) + call NAME(Bs3PagingGetRootForPP16_rm) + + cli + mov cr3, eax + + ; + ; Make sure PAE is really off and that PSE is enabled when supported. + ; +BS3_EXTERN_DATA16 g_uBs3CpuDetected +BS3_BEGIN_TEXT16 + test byte [1 + BS3_DATA16_WRT(g_uBs3CpuDetected)], (BS3CPU_F_CPUID >> 8) + jz .cr4_is_fine + mov eax, cr4 + mov ecx, eax + and eax, ~(X86_CR4_PAE | X86_CR4_PSE) + test byte [1 + BS3_DATA16_WRT(g_uBs3CpuDetected)], (BS3CPU_F_PSE >> 8) + jz .no_pse + or eax, X86_CR4_PSE +.no_pse: + cmp eax, ecx + je .cr4_is_fine + mov cr4, eax +.cr4_is_fine: + + ; + ; Load the GDT and enable PP16. + ; +BS3_EXTERN_SYSTEM16 Bs3LgdtDef_Gdt +BS3_EXTERN_SYSTEM16 Bs3Lgdt_Gdt +BS3_BEGIN_TEXT16 + mov ax, BS3SYSTEM16 + mov ds, ax + lgdt [Bs3LgdtDef_Gdt] ; Will only load 24-bit base! + + mov eax, cr0 + or eax, X86_CR0_PE | X86_CR0_PG + mov cr0, eax + jmp BS3_SEL_R0_CS16:.reload_cs_and_stuff +.reload_cs_and_stuff: + + ; + ; Convert the (now) real mode stack to 16-bit. + ; + mov ax, .stack_fix_return + extern NAME(Bs3ConvertRMStackToP16UsingCxReturnToAx_c16) + jmp NAME(Bs3ConvertRMStackToP16UsingCxReturnToAx_c16) +.stack_fix_return: + + ; + ; Call rountine for doing mode specific setups. + ; + call NAME(Bs3EnteredMode_pp16) + + ; + ; Load full 32-bit GDT base address from 32-bit segment. + ; + push ds + mov ax, BS3_SEL_SYSTEM16 + mov ds, ax + jmp dword BS3_SEL_R0_CS32:.load_full_gdt_base wrt FLAT +.load_full_gdt_base: + BS3_SET_BITS 32 + lgdt [Bs3Lgdt_Gdt wrt BS3SYSTEM16] + jmp BS3_SEL_R0_CS16:.back_to_16bit +.back_to_16bit: + BS3_SET_BITS 16 + pop ds + + popfd + pop ecx + pop eax + ret + + %endif ; !TMPL_PP32 + %if TMPL_BITS != 16 +TMPL_BEGIN_TEXT + %endif +%endif +BS3_PROC_END_MODE Bs3SwitchToPP16 + + +%if TMPL_BITS == 16 +;; +; Custom far stub. +BS3_BEGIN_TEXT16_FARSTUBS +BS3_PROC_BEGIN_MODE Bs3SwitchToPP16, BS3_PBC_FAR + inc bp + push bp + mov bp, sp + + ; Call the real thing. + call TMPL_NM(Bs3SwitchToPP16) + + %if BS3_MODE_IS_RM_OR_V86(TMPL_MODE) + ; Jmp to common code for the tedious conversion. + BS3_EXTERN_CMN Bs3SwitchHlpConvRealModeRetfPopBpDecBpAndReturn + jmp Bs3SwitchHlpConvRealModeRetfPopBpDecBpAndReturn + %else + pop bp + dec bp + retf + %endif +BS3_PROC_END_MODE Bs3SwitchToPP16 + +%else +;; +; Safe far return to non-BS3TEXT16 code. +BS3_EXTERN_CMN Bs3SwitchHlpConvFlatRetToRetfProtMode +BS3_BEGIN_TEXT16 +BS3_SET_BITS TMPL_BITS +BS3_PROC_BEGIN_MODE Bs3SwitchToPP16_Safe, BS3_PBC_NEAR + call Bs3SwitchHlpConvFlatRetToRetfProtMode ; Special internal function. Uses nothing, but modifies the stack. + call TMPL_NM(Bs3SwitchToPP16) + BS3_SET_BITS 16 + retf +BS3_PROC_END_MODE Bs3SwitchToPP16_Safe +%endif + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-SwitchToPP16_32.asm b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-SwitchToPP16_32.asm new file mode 100644 index 00000000..9afdd9ed --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-SwitchToPP16_32.asm @@ -0,0 +1,104 @@ +; $Id: bs3-mode-SwitchToPP16_32.asm $ +;; @file +; BS3Kit - Bs3SwitchToPP16_32 +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + +%include "bs3kit-template-header.mac" + + +;; +; Switch to 32-bit code under 16-bit paged protected mode sys/tss from any other mode. +; +; @cproto BS3_DECL(void) Bs3SwitchToPP16_32(void); +; +; @uses Nothing (except high 32-bit register parts). +; +; @remarks Obviously returns to 32-bit mode, even if the caller was +; in 16-bit or 64-bit mode. +; +; @remarks Does not require 20h of parameter scratch space in 64-bit mode. +; +BS3_GLOBAL_NAME_EX TMPL_NM(Bs3SwitchToPP16_32_Safe), function, 0 +BS3_PROC_BEGIN_MODE Bs3SwitchToPP16_32, BS3_PBC_NEAR +%ifdef TMPL_PP16_32 + ret + +%else + ; + ; Make sure we're in the 16-bit segment and then call Bs3SwitchToPP16. + ; + %if TMPL_BITS != 16 + jmp .sixteen_bit_segment +BS3_BEGIN_TEXT16 + BS3_SET_BITS TMPL_BITS +BS3_GLOBAL_LOCAL_LABEL .sixteen_bit_segment + %endif + extern TMPL_NM(Bs3SwitchToPP16) + call TMPL_NM(Bs3SwitchToPP16) + BS3_SET_BITS 16 + + ; + ; Switch to 32-bit mode. + ; + extern _Bs3SwitchTo32Bit_c16 + %if TMPL_BITS == 16 + jmp _Bs3SwitchTo32Bit_c16 + %else + call _Bs3SwitchTo32Bit_c16 + BS3_SET_BITS 32 + %if TMPL_BITS == 32 + ret + %else + ret 4 ; Return and pop 4 bytes of "parameters" (unused return address). + %endif + %endif +%endif +BS3_PROC_END_MODE Bs3SwitchToPP16_32 + + +%if TMPL_BITS == 16 +;; +; Custom far stub. +BS3_BEGIN_TEXT16_FARSTUBS +BS3_PROC_BEGIN_MODE Bs3SwitchToPP16_32, BS3_PBC_FAR + inc bp + push bp + mov bp, sp + + ; Call the real thing. + call TMPL_NM(Bs3SwitchToPP16_32) + BS3_SET_BITS 32 + + ; Jmp to common code for the tedious conversion. + %if BS3_MODE_IS_RM_OR_V86(TMPL_MODE) + extern _Bs3SwitchHlpConvRealModeRetfPopBpDecBpAndReturn_c32 + jmp _Bs3SwitchHlpConvRealModeRetfPopBpDecBpAndReturn_c32 + %else + extern _Bs3SwitchHlpConvProtModeRetfPopBpDecBpAndReturn_c32 + jmp _Bs3SwitchHlpConvProtModeRetfPopBpDecBpAndReturn_c32 + %endif + BS3_SET_BITS 16 +BS3_PROC_END_MODE Bs3SwitchToPP16_32 +%endif + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-SwitchToPP16_V86.asm b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-SwitchToPP16_V86.asm new file mode 100644 index 00000000..a56e8486 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-SwitchToPP16_V86.asm @@ -0,0 +1,114 @@ +; $Id: bs3-mode-SwitchToPP16_V86.asm $ +;; @file +; BS3Kit - Bs3SwitchToPP16_V86 +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + +%include "bs3kit-template-header.mac" + + +;; +; Switch to 16-bit paged protected mode with 16-bit sys+tss from any other mode. +; +; @cproto BS3_DECL(void) Bs3SwitchToPP16(void); +; +; @uses Nothing (except high 32-bit register parts). +; +; @remarks Obviously returns to v8086 16-bit mode, even if the caller was +; in 16-bit, 32-bit or 64-bit mode. +; +; @remarks Does not require 20h of parameter scratch space in 64-bit mode. +; +%if TMPL_BITS == 16 +BS3_GLOBAL_NAME_EX TMPL_NM(Bs3SwitchToPP16_V86_Safe), function , 0 +%endif +BS3_PROC_BEGIN_MODE Bs3SwitchToPP16_V86, BS3_PBC_NEAR +%ifdef TMPL_PP16_V86 + ret + +%else + ; + ; Convert the return address and jump to the 16-bit code segment. + ; + %if TMPL_BITS != 16 + shl xPRE [xSP], TMPL_BITS - 16 + add xSP, (TMPL_BITS - 16) / 8 + jmp .sixteen_bit_segment +BS3_BEGIN_TEXT16 + BS3_SET_BITS TMPL_BITS +BS3_GLOBAL_LOCAL_LABEL .sixteen_bit_segment + %endif + + ; + ; Switch to 16-bit PP16 and from there to V8086. + ; + extern TMPL_NM(Bs3SwitchToPP16) + call TMPL_NM(Bs3SwitchToPP16) + BS3_SET_BITS 16 + + ; + ; Switch to v8086 mode (return address is already 16-bit). + ; + extern _Bs3SwitchTo16BitV86_c16 + jmp _Bs3SwitchTo16BitV86_c16 +%endif +BS3_PROC_END_MODE Bs3SwitchToPP16_V86 + + +%if TMPL_BITS == 16 +;; +; Custom far stub. +BS3_BEGIN_TEXT16_FARSTUBS +BS3_PROC_BEGIN_MODE Bs3SwitchToPP16_V86, BS3_PBC_FAR + inc bp + push bp + mov bp, sp + + ; Call the real thing. + call TMPL_NM(Bs3SwitchToPP16_V86) + + %if !BS3_MODE_IS_RM_OR_V86(TMPL_MODE) + ; Jmp to common code for the tedious conversion. + BS3_EXTERN_CMN Bs3SwitchHlpConvProtModeRetfPopBpDecBpAndReturn + jmp Bs3SwitchHlpConvProtModeRetfPopBpDecBpAndReturn + %else + pop bp + dec bp + retf + %endif +BS3_PROC_END_MODE Bs3SwitchToPP16_V86 + +%else +;; +; Safe far return to non-BS3TEXT16 code. +BS3_EXTERN_CMN Bs3SwitchHlpConvFlatRetToRetfProtMode +BS3_BEGIN_TEXT16 +BS3_SET_BITS TMPL_BITS +BS3_PROC_BEGIN_MODE Bs3SwitchToPP16_V86_Safe, BS3_PBC_NEAR + call Bs3SwitchHlpConvFlatRetToRetfProtMode ; Special internal function. Uses nothing, but modifies the stack. + call TMPL_NM(Bs3SwitchToPP16_V86) + BS3_SET_BITS 16 + retf +BS3_PROC_END_MODE Bs3SwitchToPP16_V86_Safe +%endif + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-SwitchToPP32.asm b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-SwitchToPP32.asm new file mode 100644 index 00000000..9adeaaff --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-SwitchToPP32.asm @@ -0,0 +1,199 @@ +; $Id: bs3-mode-SwitchToPP32.asm $ +;; @file +; BS3Kit - Bs3SwitchToPP32 +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + +%include "bs3kit-template-header.mac" + + +;; +; Switch to 32-bit paged protected mode from any other mode. +; +; @cproto BS3_DECL(void) Bs3SwitchToPE32(void); +; +; @uses Nothing (except high 32-bit register parts), upper part of ESP is +; cleared if caller is in 16-bit mode. +; +; @remarks Obviously returns to 32-bit mode, even if the caller was +; in 16-bit or 64-bit mode. It doesn't not preserve the callers +; ring, but instead changes to ring-0. +; +; @remarks Does not require 20h of parameter scratch space in 64-bit mode. +; +BS3_GLOBAL_NAME_EX TMPL_NM(Bs3SwitchToPP32_Safe), function, 0 +BS3_PROC_BEGIN_MODE Bs3SwitchToPP32, BS3_PBC_NEAR +%ifdef TMPL_PP32 + ret + +%elif BS3_MODE_IS_V86(TMPL_MODE) + ; + ; V8086 - Switch to 16-bit ring-0 and call worker for that mode. + ; + extern BS3_CMN_NM(Bs3SwitchToRing0) + call BS3_CMN_NM(Bs3SwitchToRing0) + extern %[BS3_MODE_R0_NM_ %+ TMPL_MODE](Bs3SwitchToPP32) + jmp %[BS3_MODE_R0_NM_ %+ TMPL_MODE](Bs3SwitchToPP32) + +%else + ; + ; Switch to real mode. + ; + %if TMPL_BITS != 32 + %if TMPL_BITS > 32 + shl xPRE [xSP], 32 ; Adjust the return address from 64-bit to 32-bit. + add rsp, xCB - 4 + %else + push word 0 ; Reserve space to expand the return address. + %endif + %endif + %if TMPL_BITS != 16 + ; Must be in 16-bit segment when calling Bs3SwitchTo16Bit. + jmp .sixteen_bit_segment +BS3_BEGIN_TEXT16 + BS3_SET_BITS TMPL_BITS +BS3_GLOBAL_LOCAL_LABEL .sixteen_bit_segment + %endif + + ; + ; Switch to real mode. + ; + extern TMPL_NM(Bs3SwitchToRM) + call TMPL_NM(Bs3SwitchToRM) + BS3_SET_BITS 16 + + push eax + push ecx + pushfd + + ; + ; Make sure PAE is really off and that PSE is on when supported. + ; +BS3_EXTERN_DATA16 g_uBs3CpuDetected +BS3_BEGIN_TEXT16 + test byte [1 + BS3_DATA16_WRT(g_uBs3CpuDetected)], (BS3CPU_F_CPUID >> 8) + jz .cr4_is_fine + mov eax, cr4 + mov ecx, eax + and eax, ~(X86_CR4_PAE | X86_CR4_PSE) + test byte [1 + BS3_DATA16_WRT(g_uBs3CpuDetected)], (BS3CPU_F_PSE >> 8) + jz .no_pse + or eax, X86_CR4_PSE +.no_pse: + cmp eax, ecx + je .cr4_is_fine + mov cr4, eax +.cr4_is_fine: + + ; + ; Get the page directory (returned in eax). + ; Will lazy init page tables (in 16-bit prot mode). + ; + extern NAME(Bs3PagingGetRootForPP32_rm) + call NAME(Bs3PagingGetRootForPP32_rm) + + cli + mov cr3, eax + + ; + ; Load the GDT and enable PE32. + ; +BS3_EXTERN_SYSTEM16 Bs3LgdtDef_Gdt +BS3_EXTERN_SYSTEM16 Bs3Lgdt_Gdt +BS3_BEGIN_TEXT16 + mov ax, BS3SYSTEM16 + mov ds, ax + lgdt [Bs3LgdtDef_Gdt] ; Will only load 24-bit base! + + mov eax, cr0 + or eax, X86_CR0_PE | X86_CR0_PG + mov cr0, eax + jmp BS3_SEL_R0_CS32:dword .thirty_two_bit wrt FLAT +BS3_BEGIN_TEXT32 +BS3_GLOBAL_LOCAL_LABEL .thirty_two_bit + ; + ; Convert the (now) real mode stack pointer to 32-bit flat. + ; + xor eax, eax + mov ax, ss + shl eax, 4 + and esp, 0ffffh + add esp, eax + + mov ax, BS3_SEL_R0_SS32 + mov ss, ax + + ; + ; Call rountine for doing mode specific setups. + ; + extern NAME(Bs3EnteredMode_pp32) + call NAME(Bs3EnteredMode_pp32) + + ; Load full 32-bit GDT base address. + lgdt [Bs3Lgdt_Gdt wrt FLAT] + + ; + ; Restore ecx, eax and flags (IF). + ; + %if TMPL_BITS < 32 + movzx eax, word [esp + 12 + 2] ; Load return address. + add eax, BS3_ADDR_BS3TEXT16 ; Convert it to a flat address. + mov [esp + 12], eax ; Store it in the place right for 32-bit returns. + %endif + popfd + pop ecx + pop eax + ret + + %if TMPL_BITS != 32 +TMPL_BEGIN_TEXT + %endif +%endif +BS3_PROC_END_MODE Bs3SwitchToPP32 + + +%if TMPL_BITS == 16 +;; +; Custom far stub. +BS3_BEGIN_TEXT16_FARSTUBS +BS3_PROC_BEGIN_MODE Bs3SwitchToPP32, BS3_PBC_FAR + inc bp + push bp + mov bp, sp + + ; Call the real thing. + call TMPL_NM(Bs3SwitchToPP32) + BS3_SET_BITS 32 + + ; Jmp to common code for the tedious conversion. + %if BS3_MODE_IS_RM_OR_V86(TMPL_MODE) + extern _Bs3SwitchHlpConvRealModeRetfPopBpDecBpAndReturn_c32 + jmp _Bs3SwitchHlpConvRealModeRetfPopBpDecBpAndReturn_c32 + %else + extern _Bs3SwitchHlpConvProtModeRetfPopBpDecBpAndReturn_c32 + jmp _Bs3SwitchHlpConvProtModeRetfPopBpDecBpAndReturn_c32 + %endif + BS3_SET_BITS 16 +BS3_PROC_END_MODE Bs3SwitchToPP32 +%endif + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-SwitchToPP32_16.asm b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-SwitchToPP32_16.asm new file mode 100644 index 00000000..29ada7e9 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-SwitchToPP32_16.asm @@ -0,0 +1,122 @@ +; $Id: bs3-mode-SwitchToPP32_16.asm $ +;; @file +; BS3Kit - Bs3SwitchToPP32_16 +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + +%include "bs3kit-template-header.mac" + + +;; +; Switch to 16-bit code under 32-bit paged protected mode sys/tss from any other mode. +; +; @cproto BS3_DECL(void) Bs3SwitchToPP32_16(void); +; +; @uses Nothing (except high 32-bit register parts). +; +; @remarks Obviously returns to 16-bit mode, even if the caller was +; in 32-bit or 64-bit mode. +; +; @remarks Does not require 20h of parameter scratch space in 64-bit mode. +; +%if TMPL_BITS == 16 +BS3_GLOBAL_NAME_EX TMPL_NM(Bs3SwitchToPP32_16_Safe), function , 0 +%endif +BS3_PROC_BEGIN_MODE Bs3SwitchToPP32_16, BS3_PBC_NEAR +%if TMPL_MODE == BS3_MODE_PP32_16 + ret + +%elif TMPL_MODE == BS3_MODE_PP32 + extern BS3_CMN_NM(Bs3SwitchTo16Bit) + jmp BS3_CMN_NM(Bs3SwitchTo16Bit) + +%else + ; + ; Switch to PP32. + ; + extern TMPL_NM(Bs3SwitchToPP32) + call TMPL_NM(Bs3SwitchToPP32) + BS3_SET_BITS 32 + + ; + ; Make sure we're in the 16-bit segment and then do the switch to 16-bit. + ; + %if TMPL_BITS != 16 + jmp .sixteen_bit_segment +BS3_BEGIN_TEXT16 + BS3_SET_BITS TMPL_BITS +.sixteen_bit_segment: + %endif + extern _Bs3SwitchTo16Bit_c32 + %if TMPL_BITS == 32 + jmp _Bs3SwitchTo16Bit_c32 + %else + call _Bs3SwitchTo16Bit_c32 + BS3_SET_BITS 16 + %if TMPL_BITS == 16 + ret + %else + ret 6 ; Return and pop 6 bytes of "parameters" (unused return address). + %endif + %endif +%endif +BS3_PROC_END_MODE Bs3SwitchToPP32_16 + + +%if TMPL_BITS == 16 +;; +; Custom far stub. +BS3_BEGIN_TEXT16_FARSTUBS +BS3_PROC_BEGIN_MODE Bs3SwitchToPP32_16, BS3_PBC_FAR + inc bp + push bp + mov bp, sp + + ; Call the real thing. + call TMPL_NM(Bs3SwitchToPP32_16) + + %if BS3_MODE_IS_RM_OR_V86(TMPL_MODE) + ; Jmp to common code for the tedious conversion. + BS3_EXTERN_CMN Bs3SwitchHlpConvRealModeRetfPopBpDecBpAndReturn + jmp Bs3SwitchHlpConvRealModeRetfPopBpDecBpAndReturn + %else + pop bp + dec bp + retf + %endif +BS3_PROC_END_MODE Bs3SwitchToPP32_16 + +%else +;; +; Safe far return to non-BS3TEXT16 code. +BS3_EXTERN_CMN Bs3SwitchHlpConvFlatRetToRetfProtMode +BS3_BEGIN_TEXT16 +BS3_SET_BITS TMPL_BITS +BS3_PROC_BEGIN_MODE Bs3SwitchToPP32_16_Safe, BS3_PBC_NEAR + call Bs3SwitchHlpConvFlatRetToRetfProtMode ; Special internal function. Uses nothing, but modifies the stack. + call TMPL_NM(Bs3SwitchToPP32_16) + BS3_SET_BITS 16 + retf +BS3_PROC_END_MODE Bs3SwitchToPP32_16_Safe +%endif + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-SwitchToPPV86.asm b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-SwitchToPPV86.asm new file mode 100644 index 00000000..302bad9a --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-SwitchToPPV86.asm @@ -0,0 +1,108 @@ +; $Id: bs3-mode-SwitchToPPV86.asm $ +;; @file +; BS3Kit - Bs3SwitchToPPV86 +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + +%include "bs3kit-template-header.mac" + + +;; +; Switch to 16-bit v8086 paged protected mode with 32-bit sys+tss from any other mode. +; +; @cproto BS3_DECL(void) Bs3SwitchToPPV86(void); +; +; @uses Nothing (except high 32-bit register parts). +; +; @remarks Obviously returns to 16-bit v8086 mode, even if the caller was +; in 32-bit or 64-bit mode. +; +; @remarks Does not require 20h of parameter scratch space in 64-bit mode. +; +%if TMPL_BITS == 16 +BS3_GLOBAL_NAME_EX TMPL_NM(Bs3SwitchToPPV86_Safe), function , 0 +%endif +BS3_PROC_BEGIN_MODE Bs3SwitchToPPV86, BS3_PBC_NEAR +%if TMPL_MODE == BS3_MODE_PPV86 + ret + +%else + ; + ; Switch to 32-bit PP32 and from there to V8086. + ; + extern TMPL_NM(Bs3SwitchToPP32) + call TMPL_NM(Bs3SwitchToPP32) + BS3_SET_BITS 32 + + ; + ; Switch to v8086 mode after adjusting the return address. + ; + %if TMPL_BITS == 16 + push word [esp] + mov word [esp + 2], 0 + %elif TMPL_BITS == 64 + pop dword [esp + 4] + %endif + extern _Bs3SwitchTo16BitV86_c32 + jmp _Bs3SwitchTo16BitV86_c32 +%endif +BS3_PROC_END_MODE Bs3SwitchToPPV86 + + +%if TMPL_BITS == 16 +;; +; Custom far stub. +BS3_BEGIN_TEXT16_FARSTUBS +BS3_PROC_BEGIN_MODE Bs3SwitchToPPV86, BS3_PBC_FAR + inc bp + push bp + mov bp, sp + + ; Call the real thing. + call TMPL_NM(Bs3SwitchToPPV86) + + %if !BS3_MODE_IS_RM_OR_V86(TMPL_MODE) + ; Jmp to common code for the tedious conversion. + BS3_EXTERN_CMN Bs3SwitchHlpConvProtModeRetfPopBpDecBpAndReturn + jmp Bs3SwitchHlpConvProtModeRetfPopBpDecBpAndReturn + %else + pop bp + dec bp + retf + %endif +BS3_PROC_END_MODE Bs3SwitchToPPV86 + +%else +;; +; Safe far return to non-BS3TEXT16 code. +BS3_EXTERN_CMN Bs3SwitchHlpConvFlatRetToRetfProtMode +BS3_BEGIN_TEXT16 +BS3_SET_BITS TMPL_BITS +BS3_PROC_BEGIN_MODE Bs3SwitchToPPV86_Safe, BS3_PBC_NEAR + call Bs3SwitchHlpConvFlatRetToRetfProtMode ; Special internal function. Uses nothing, but modifies the stack. + call TMPL_NM(Bs3SwitchToPPV86) + BS3_SET_BITS 16 + retf +BS3_PROC_END_MODE Bs3SwitchToPPV86_Safe +%endif + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-SwitchToRM.asm b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-SwitchToRM.asm new file mode 100644 index 00000000..81a09188 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-SwitchToRM.asm @@ -0,0 +1,398 @@ +; $Id: bs3-mode-SwitchToRM.asm $ +;; @file +; BS3Kit - Bs3SwitchToRM +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + +%include "bs3kit-template-header.mac" + +BS3_EXTERN_SYSTEM16 Bs3Gdt +%if TMPL_MODE == BS3_MODE_PE16 +BS3_EXTERN_DATA16 g_uBs3CpuDetected +BS3_EXTERN_CMN Bs3KbdWrite +BS3_EXTERN_CMN Bs3KbdWait +%endif + + +;********************************************************************************************************************************* +;* Global Variables * +;********************************************************************************************************************************* +%if TMPL_MODE == BS3_MODE_PE16 +BS3_BEGIN_DATA16 +;; Where to start restoring stack. +g_ResumeSp: dw 0xfeed +;; Where to start restoring stack. +g_ResumeSs: dw 0xface +%endif + +TMPL_BEGIN_TEXT + + +;; +; Switch to real mode from any other mode. +; +; @cproto BS3_DECL(void) Bs3SwitchToRM(void); +; +; @uses GPRs and EFLAGS are unchanged (except high 32-bit register (AMD64) parts). +; CS is loaded with CGROUP16. +; SS:[RE]SP is converted to real mode address. +; DS and ES are loaded with BS3DATA16_GROUP. +; FS and GS are loaded with zero if present. +; +; @remarks Obviously returns to 16-bit mode, even if the caller was +; in 32-bit or 64-bit mode. +; +; @remarks Does not require 20h of parameter scratch space in 64-bit mode. +; +%if TMPL_BITS == 16 +BS3_GLOBAL_NAME_EX TMPL_NM(Bs3SwitchToRM_Safe), function , 0 +%endif +BS3_PROC_BEGIN_MODE Bs3SwitchToRM, BS3_PBC_NEAR +%ifdef TMPL_RM + push ax + mov ax, BS3_SEL_DATA16 + mov ds, ax + mov es, ax + pop ax + ret + +%elif BS3_MODE_IS_V86(TMPL_MODE) + ; + ; V8086 - Switch to 16-bit ring-0 and call worker for that mode. + ; + extern BS3_CMN_NM(Bs3SwitchToRing0) + call BS3_CMN_NM(Bs3SwitchToRing0) + extern %[BS3_MODE_R0_NM_ %+ TMPL_MODE](Bs3SwitchToRM) + jmp %[BS3_MODE_R0_NM_ %+ TMPL_MODE](Bs3SwitchToRM) + +%else + ; + ; Protected mode. + ; 80286 requirements for PE16 clutters the code a little. + ; + %if TMPL_MODE == BS3_MODE_PE16 + cmp byte [BS3_DATA16_WRT(g_uBs3CpuDetected)], BS3CPU_80286 + ja .do_386_prologue + push ax + push bx + pushf + push word 1 + jmp .done_prologue + %endif +.do_386_prologue: + push sAX + push sBX + sPUSHF + %if TMPL_MODE == BS3_MODE_PE16 + push word 0 + %elif BS3_MODE_IS_64BIT_SYS(TMPL_MODE) + push sDX + push sCX + %endif +.done_prologue: + + ; + ; Get to 16-bit ring-0 and disable interrupts. + ; + extern BS3_CMN_NM(Bs3SwitchToRing0) + call BS3_CMN_NM(Bs3SwitchToRing0) + + cli + + %if TMPL_MODE == BS3_MODE_PE16 + ; + ; On 80286 we must reset the CPU to get back to real mode. + ; + CPU 286 + pop ax + push ax + test ax, ax + jz .is_386_or_better + + ; Save registers and flags, storing SS:SP in at a known global address. +%ifdef BS3_STRICT + mov ax, 0feedh + mov bx, 0faceh +%endif + push di + push si + push bp + push bx + push dx + push cx + push ax + pushf + + ; Convert ss:sp to real mode address. + BS3_EXTERN_CMN Bs3SelProtFar32ToFlat32 + mov ax, sp + push ss + push 0 + push ax + call Bs3SelProtFar32ToFlat32 + add sp, 6 + + mov [g_ResumeSp], ax + shl dx, 12 + mov [g_ResumeSs], dx + + ; Setup resume vector. + mov bx, BS3_SEL_R0_SS16 + mov es, bx + mov word [es:467h], .resume + mov word [es:467h+2], BS3_SEL_TEXT16 + + mov al, 0fh | 80h + out 70h, al ; set register index + in al, 80h + mov al, 0ah ; shutdown action command - no EOI, no 287 reset. + out 71h, al ; set cmos[f] = al - invoke testResume as early as possible. + in al, 71h ; flush + + %if 0 ; for testing in VM + CPU 386 + mov ax, BS3_SEL_R0_DS16 + mov ds, ax + mov es, ax + mov fs, ax + mov gs, ax + + mov eax, cr0 + and ax, ~X86_CR0_PE + mov cr0, eax + jmp BS3_SEL_TEXT16:.resume + %endif + + ; Port A reset. (FYI: tripple fault does not do the trick) + in al, 92h + or al, 1 + out 92h, al + in al, 80h ; flush + mov cx, 0ffffh +.reset_delay: + loop .reset_delay + + ; Keyboard controller reset. + call Bs3KbdWait + push 0 ; zero data (whatever. + push 0fh ; KBD_CCMD_RESET + call Bs3KbdWrite +.forever: + jmp .forever + + ; This is the resume point. We should be in real mode now, at least in theory. +.resume: + mov ax, BS3_SEL_DATA16 + mov ds, ax + mov es, ax + mov ax, [g_ResumeSp] + mov ss, [g_ResumeSs] + mov sp, ax + + popf + pop ax + pop cx + pop dx + pop bx + pop bp + pop si + pop di + %ifdef BS3_STRICT + cmp ax, 0feedh + jne .bad_286_rm_switch + cmp bx, 0faceh + jne .bad_286_rm_switch + %endif + jmp .enter_mode + + %ifdef BS3_STRICT +.bad_286_rm_switch: + mov ax, 0e00h + 'Q' + mov bx, 0ff00h + int 10h + jmp .bad_286_rm_switch + %endif + + CPU 386 + %elif TMPL_BITS != 16 + ; + ; Must be in 16-bit segment when calling Bs3SwitchTo16Bit. + ; + jmp .sixteen_bit_segment wrt FLAT +BS3_BEGIN_TEXT16 + BS3_SET_BITS TMPL_BITS +BS3_GLOBAL_LOCAL_LABEL .sixteen_bit_segment + + extern BS3_CMN_NM(Bs3SwitchTo16Bit) + call BS3_CMN_NM(Bs3SwitchTo16Bit) + BS3_SET_BITS 16 + %endif + ; + ; Before exiting to real mode we must load sensible selectors into the + ; segment registers so the hidden parts (which doesn't get reloaded in + ; real mode) are real mode compatible. + ; +.is_386_or_better: +;; @todo Testcase: Experiment leaving weird stuff in the hidden segment registers. + mov ax, BS3_SEL_R0_DS16 + mov ds, ax + mov es, ax + mov fs, ax + mov gs, ax + + ; + ; Exit to real mode. + ; + mov eax, cr0 + and eax, X86_CR0_NO_PE_NO_PG + mov cr0, eax + jmp CGROUP16:.reload_cs +.reload_cs: + + ; + ; Convert the stack (now 16-bit prot) to real mode. + ; + mov ax, BS3_SEL_SYSTEM16 + mov ds, ax + mov bx, ss + and bx, X86_SEL_MASK ; ASSUMES GDT stack selector + mov al, [bx + 4 + Bs3Gdt] + mov ah, [bx + 7 + Bs3Gdt] + add sp, [bx + 2 + Bs3Gdt] ; ASSUMES not expand down segment. + adc ax, 0 + %ifdef BS3_STRICT + test ax, 0fff0h + jz .stack_conv_ok + int3 +.stack_conv_ok: + %endif + shl ax, 12 + mov ss, ax + %if TMPL_BITS != 16 + and esp, 0ffffh + %endif + + %if BS3_MODE_IS_64BIT_SYS(TMPL_MODE) + ; + ; Clear the long mode enable bit. + ; + mov ecx, MSR_K6_EFER + rdmsr + and eax, ~MSR_K6_EFER_LME + wrmsr + %endif + + ; + ; Call routine for doing mode specific setups. + ; +.enter_mode: + extern NAME(Bs3EnteredMode_rm) + call NAME(Bs3EnteredMode_rm) + + %if TMPL_MODE == BS3_MODE_PE16 + pop ax + test ax, ax + jz .do_386_epilogue + popf + pop bx + pop ax + ret + %endif +.do_386_epilogue: + %if BS3_MODE_IS_64BIT_SYS(TMPL_MODE) + pop ecx +TONLY64 pop eax + pop edx +TONLY64 pop eax + %endif + popfd +TONLY64 pop eax + pop ebx +TONLY64 pop eax + pop eax +TONLY64 add sp, 4 + retn (TMPL_BITS - 16) / 8 + + %if TMPL_BITS != 16 +TMPL_BEGIN_TEXT + %endif +%endif +BS3_PROC_END_MODE Bs3SwitchToRM + + +%if TMPL_BITS == 16 +;; +; Custom far stub. +BS3_BEGIN_TEXT16_FARSTUBS +BS3_PROC_BEGIN_MODE Bs3SwitchToRM, BS3_PBC_FAR + inc bp + push bp + mov bp, sp + + ; Call the real thing. + call TMPL_NM(Bs3SwitchToRM) + + %if !BS3_MODE_IS_RM_OR_V86(TMPL_MODE) + ; Jmp to common code for the tedious conversion. + BS3_EXTERN_CMN Bs3SwitchHlpConvProtModeRetfPopBpDecBpAndReturn + jmp Bs3SwitchHlpConvProtModeRetfPopBpDecBpAndReturn + %else + pop bp + dec bp + retf + %endif +BS3_PROC_END_MODE Bs3SwitchToRM + +%else +;; +; Safe far return to non-BS3TEXT16 code. +BS3_EXTERN_CMN Bs3SelFlatCodeToRealMode +BS3_BEGIN_TEXT16 +BS3_SET_BITS TMPL_BITS +BS3_PROC_BEGIN_MODE Bs3SwitchToRM_Safe, BS3_PBC_NEAR + %if TMPL_BITS == 64 + push xAX + push xCX + sub xSP, 20h + + mov xCX, [xSP + xCB*2 + 20h] + call Bs3SelFlatCodeToRealMode ; well behaved assembly function, only clobbers ecx + mov [xSP + xCB*2 + 20h + 4], eax + + add xSP, 20h + pop xCX + pop xAX + add xSP, 4 + %else + xchg eax, [xSP] + push xAX + call Bs3SelFlatCodeToRealMode ; well behaved assembly function, only clobbers eax + add xSP, 4 + xchg [xSP], eax + %endif + call TMPL_NM(Bs3SwitchToRM) + BS3_SET_BITS 16 + retf +BS3_PROC_END_MODE Bs3SwitchToRM_Safe +%endif + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-TestDoModes.c b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-TestDoModes.c new file mode 100644 index 00000000..b3b83127 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-TestDoModes.c @@ -0,0 +1,370 @@ +/* $Id: bs3-mode-TestDoModes.c $ */ +/** @file + * BS3Kit - Bs3TestDoModes + */ + +/* + * Copyright (C) 2007-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#if TMPL_MODE == BS3_MODE_RM +# define BS3_USE_RM_TEXT_SEG 1 /* Real mode version in RMTEXT16 segment to save space. */ +# include "bs3kit-template-header.h" +# include "bs3-cmn-test.h" +#else +# include "bs3kit-template-header.h" +# include "bs3-cmn-test.h" +#endif +#include "bs3-mode-TestDoModes.h" + + + +/** + * Warns about CPU modes that must be skipped. + * + * It will try not warn about modes for which there are no tests. + * + * @param paEntries The mode test entries. + * @param cEntries The number of tests. + * @param bCpuType The CPU type byte (see #BS3CPU_TYPE_MASK). + * @param fHavePae Whether the CPU has PAE. + * @param fHaveLongMode Whether the CPU does long mode. + */ +static void bs3TestWarnAboutSkippedModes(PCBS3TESTMODEENTRY paEntries, unsigned cEntries, + uint8_t bCpuType, bool fHavePae, bool fHaveLongMode) +{ + bool fComplained286 = false; + bool fComplained386 = false; + bool fComplainedPAE = false; + bool fComplainedAMD64 = false; + unsigned i; + + /* + * Complaint run. + */ + for (i = 0; i < cEntries; i++) + { + if ( !fComplained286 + && paEntries[i].pfnDoPE16) + { + if (bCpuType < BS3CPU_80286) + { + Bs3Printf("Only executing real-mode tests as no 80286+ CPU was detected.\n"); + break; + } + fComplained286 = true; + } + + if ( !fComplained386 + && ( paEntries[i].pfnDoPE16_32 + || paEntries[i].pfnDoPE16_V86 + || paEntries[i].pfnDoPE32 + || paEntries[i].pfnDoPE32_16 + || paEntries[i].pfnDoPEV86 + || paEntries[i].pfnDoPP16 + || paEntries[i].pfnDoPP16_32 + || paEntries[i].pfnDoPP16_V86 + || paEntries[i].pfnDoPP32 + || paEntries[i].pfnDoPP32_16 + || paEntries[i].pfnDoPPV86) ) + { + if (bCpuType < BS3CPU_80386) + { + Bs3Printf("80286 CPU: Only executing 16-bit protected and real mode tests.\n"); + break; + } + fComplained386 = true; + } + + if ( !fComplainedPAE + && ( paEntries[i].pfnDoPAE16 + || paEntries[i].pfnDoPAE16_32 + || paEntries[i].pfnDoPAE16_V86 + || paEntries[i].pfnDoPAE32 + || paEntries[i].pfnDoPAE32_16 + || paEntries[i].pfnDoPAEV86) ) + { + if (!fHavePae) + { + Bs3Printf("PAE and long mode tests will be skipped.\n"); + break; + } + fComplainedPAE = true; + } + + if ( !fComplainedAMD64 + && ( paEntries[i].pfnDoLM16 + || paEntries[i].pfnDoLM32 + || paEntries[i].pfnDoLM64) ) + { + if (!fHaveLongMode) + { + Bs3Printf("Long mode tests will be skipped.\n"); + break; + } + fComplainedAMD64 = true; + } + } +} + +#undef Bs3TestDoModes +BS3_MODE_DEF(void, Bs3TestDoModes,(PCBS3TESTMODEENTRY paEntries, size_t cEntries)) +{ + bool const fVerbose = true; + bool const fDoV86Modes = true; + bool const fDoWeirdV86Modes = true; + uint16_t const uCpuDetected = g_uBs3CpuDetected; + uint8_t const bCpuType = uCpuDetected & BS3CPU_TYPE_MASK; + bool const fHavePae = RT_BOOL(uCpuDetected & BS3CPU_F_PAE); + bool const fHaveLongMode = RT_BOOL(uCpuDetected & BS3CPU_F_LONG_MODE); + unsigned i; + +#if 1 /* debug. */ + Bs3Printf("Bs3TestDoModes: uCpuDetected=%#x fHavePae=%d fHaveLongMode=%d\n", uCpuDetected, fHavePae, fHaveLongMode); +#endif + bs3TestWarnAboutSkippedModes(paEntries, cEntries, bCpuType, fHavePae, fHaveLongMode); + + /* + * The real run. + */ + for (i = 0; i < cEntries; i++) + { + const char *pszFmtStr = "Error #%u (%#x) in %s!\n"; + bool fSkipped = true; + uint8_t bErrNo; + + if (paEntries[i].pszSubTest != NULL) + Bs3TestSub(paEntries[i].pszSubTest); + +#define PRE_DO_CALL(a_szModeName) do { if (fVerbose) Bs3TestPrintf("...%s\n", a_szModeName); } while (0) +#define CHECK_RESULT(a_szModeName) \ + do { \ + if (bErrNo != BS3TESTDOMODE_SKIPPED) \ + { \ + /*Bs3Printf("bErrNo=%#x %s\n", bErrNo, a_szModeName);*/ \ + fSkipped = false; \ + if (bErrNo != 0) \ + Bs3TestFailedF(pszFmtStr, bErrNo, bErrNo, a_szModeName); \ + } \ + } while (0) + + if (paEntries[i].pfnDoRM) + { + PRE_DO_CALL(g_szBs3ModeName_rm); + bErrNo = TMPL_NM(Bs3TestCallDoerInRM)(CONV_TO_RM_FAR16(paEntries[i].pfnDoRM)); + CHECK_RESULT(g_szBs3ModeName_rm); + } + + if (bCpuType < BS3CPU_80286) + { + if (fSkipped) + Bs3TestSkipped(NULL); + continue; + } + + /* + * Unpaged prot mode. + */ + if (paEntries[i].pfnDoPE16) + { + PRE_DO_CALL(g_szBs3ModeName_pe16); + bErrNo = TMPL_NM(Bs3TestCallDoerInPE16)(CONV_TO_PROT_FAR16(paEntries[i].pfnDoPE16)); + CHECK_RESULT(g_szBs3ModeName_pe16); + } + if (bCpuType < BS3CPU_80386) + { + if (fSkipped) + Bs3TestSkipped(NULL); + continue; + } + + if (paEntries[i].pfnDoPE16_32) + { + PRE_DO_CALL(g_szBs3ModeName_pe16_32); + bErrNo = TMPL_NM(Bs3TestCallDoerInPE16_32)(CONV_TO_FLAT(paEntries[i].pfnDoPE16_32), BS3_MODE_PE16_32); + CHECK_RESULT(g_szBs3ModeName_pe16_32); + } + + if (paEntries[i].pfnDoPE16_V86 && fDoWeirdV86Modes) + { + PRE_DO_CALL(g_szBs3ModeName_pe16_v86); + bErrNo = TMPL_NM(Bs3TestCallDoerInPE16_V86)(CONV_TO_RM_FAR16(paEntries[i].pfnDoPE16_V86)); + CHECK_RESULT(g_szBs3ModeName_pe16_v86); + } + + if (paEntries[i].pfnDoPE32) + { + PRE_DO_CALL(g_szBs3ModeName_pe32); + bErrNo = TMPL_NM(Bs3TestCallDoerInPE32)(CONV_TO_FLAT(paEntries[i].pfnDoPE32), BS3_MODE_PE32); + CHECK_RESULT(g_szBs3ModeName_pe32); + } + + if (paEntries[i].pfnDoPE32_16) + { + PRE_DO_CALL(g_szBs3ModeName_pe32_16); + bErrNo = TMPL_NM(Bs3TestCallDoerInPE32_16)(CONV_TO_PROT_FAR16(paEntries[i].pfnDoPE32_16)); + CHECK_RESULT(g_szBs3ModeName_pe32_16); + } + + if (paEntries[i].pfnDoPEV86 && fDoV86Modes) + { + PRE_DO_CALL(g_szBs3ModeName_pev86); + bErrNo = TMPL_NM(Bs3TestCallDoerInPEV86)(CONV_TO_RM_FAR16(paEntries[i].pfnDoPEV86)); + CHECK_RESULT(g_szBs3ModeName_pev86); + } + + /* + * Paged protected mode. + */ + if (paEntries[i].pfnDoPP16) + { + PRE_DO_CALL(g_szBs3ModeName_pp16); + bErrNo = TMPL_NM(Bs3TestCallDoerInPP16)(CONV_TO_PROT_FAR16(paEntries[i].pfnDoPP16)); + CHECK_RESULT(g_szBs3ModeName_pp16); + } + + if (paEntries[i].pfnDoPP16_32) + { + PRE_DO_CALL(g_szBs3ModeName_pp16_32); + bErrNo = TMPL_NM(Bs3TestCallDoerInPP16_32)(CONV_TO_FLAT(paEntries[i].pfnDoPP16_32), BS3_MODE_PP16_32); + CHECK_RESULT(g_szBs3ModeName_pp16_32); + } + + if (paEntries[i].pfnDoPP16_V86 && fDoWeirdV86Modes) + { + PRE_DO_CALL(g_szBs3ModeName_pp16_v86); + bErrNo = TMPL_NM(Bs3TestCallDoerInPP16_V86)(CONV_TO_RM_FAR16(paEntries[i].pfnDoPP16_V86)); + CHECK_RESULT(g_szBs3ModeName_pp16_v86); + } + + if (paEntries[i].pfnDoPP32) + { + PRE_DO_CALL(g_szBs3ModeName_pp32); + bErrNo = TMPL_NM(Bs3TestCallDoerInPP32)(CONV_TO_FLAT(paEntries[i].pfnDoPP32), BS3_MODE_PP32); + CHECK_RESULT(g_szBs3ModeName_pp32); + } + + if (paEntries[i].pfnDoPP32_16) + { + PRE_DO_CALL(g_szBs3ModeName_pp32_16); + bErrNo = TMPL_NM(Bs3TestCallDoerInPP32_16)(CONV_TO_PROT_FAR16(paEntries[i].pfnDoPP32_16)); + CHECK_RESULT(g_szBs3ModeName_pp32_16); + } + + if (paEntries[i].pfnDoPPV86 && fDoV86Modes) + { + PRE_DO_CALL(g_szBs3ModeName_ppv86); + bErrNo = TMPL_NM(Bs3TestCallDoerInPPV86)(CONV_TO_RM_FAR16(paEntries[i].pfnDoPPV86)); + CHECK_RESULT(g_szBs3ModeName_ppv86); + } + + /* + * Protected mode with PAE paging. + */ + if (!fHavePae) + { + if (fSkipped) + Bs3TestSkipped(NULL); + continue; + } + + if (paEntries[i].pfnDoPAE16) + { + PRE_DO_CALL(g_szBs3ModeName_pae16); + bErrNo = TMPL_NM(Bs3TestCallDoerInPAE16)(CONV_TO_PROT_FAR16(paEntries[i].pfnDoPAE16)); + CHECK_RESULT(g_szBs3ModeName_pae16); + } + + if (paEntries[i].pfnDoPAE16_32) + { + PRE_DO_CALL(g_szBs3ModeName_pae16_32); + bErrNo = TMPL_NM(Bs3TestCallDoerInPAE16_32)(CONV_TO_FLAT(paEntries[i].pfnDoPAE16_32), BS3_MODE_PAE16_32); + CHECK_RESULT(g_szBs3ModeName_pae16_32); + } + + if (paEntries[i].pfnDoPAE16_V86 && fDoWeirdV86Modes) + { + PRE_DO_CALL(g_szBs3ModeName_pae16_v86); + bErrNo = TMPL_NM(Bs3TestCallDoerInPAE16_V86)(CONV_TO_RM_FAR16(paEntries[i].pfnDoPAE16_V86)); + CHECK_RESULT(g_szBs3ModeName_pae16_v86); + } + + if (paEntries[i].pfnDoPAE32) + { + PRE_DO_CALL(g_szBs3ModeName_pae32); + bErrNo = TMPL_NM(Bs3TestCallDoerInPAE32)(CONV_TO_FLAT(paEntries[i].pfnDoPAE32), BS3_MODE_PAE32); + CHECK_RESULT(g_szBs3ModeName_pae32); + } + + if (paEntries[i].pfnDoPAE32_16) + { + PRE_DO_CALL(g_szBs3ModeName_pae32_16); + bErrNo = TMPL_NM(Bs3TestCallDoerInPAE32_16)(CONV_TO_PROT_FAR16(paEntries[i].pfnDoPAE32_16)); + CHECK_RESULT(g_szBs3ModeName_pae32_16); + } + + if (paEntries[i].pfnDoPAEV86 && fDoV86Modes) + { + PRE_DO_CALL(g_szBs3ModeName_paev86); + bErrNo = TMPL_NM(Bs3TestCallDoerInPAEV86)(CONV_TO_RM_FAR16(paEntries[i].pfnDoPAEV86)); + CHECK_RESULT(g_szBs3ModeName_paev86); + } + + /* + * Long mode. + */ + if (!fHaveLongMode) + { + if (fSkipped) + Bs3TestSkipped(NULL); + continue; + } + + if (paEntries[i].pfnDoLM16) + { + PRE_DO_CALL(g_szBs3ModeName_lm16); + bErrNo = TMPL_NM(Bs3TestCallDoerInLM16)(CONV_TO_PROT_FAR16(paEntries[i].pfnDoLM16)); + CHECK_RESULT(g_szBs3ModeName_lm16); + } + + if (paEntries[i].pfnDoLM32) + { + PRE_DO_CALL(g_szBs3ModeName_lm32); + bErrNo = TMPL_NM(Bs3TestCallDoerInLM32)(CONV_TO_FLAT(paEntries[i].pfnDoLM32)); + CHECK_RESULT(g_szBs3ModeName_lm32); + } + + if (paEntries[i].pfnDoLM64) + { + PRE_DO_CALL(g_szBs3ModeName_lm64); + bErrNo = TMPL_NM(Bs3TestCallDoerInLM64)(CONV_TO_FLAT(paEntries[i].pfnDoLM64), BS3_MODE_LM64); + CHECK_RESULT(g_szBs3ModeName_lm64); + } + + if (fSkipped) + Bs3TestSkipped("skipped\n"); + } + Bs3TestSubDone(); +} + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-TestDoModes.h b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-TestDoModes.h new file mode 100644 index 00000000..b0f6e080 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-TestDoModes.h @@ -0,0 +1,89 @@ +/* $Id: bs3-mode-TestDoModes.h $ */ +/** @file + * BS3Kit - Common header for the Bs3TestDoModes family. + */ + +/* + * Copyright (C) 2007-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + +#ifndef BS3KIT_INCLUDED_bs3_mode_TestDoModes_h +#define BS3KIT_INCLUDED_bs3_mode_TestDoModes_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include "bs3kit.h" + + +/********************************************************************************************************************************* +* Defined Constants And Macros * +*********************************************************************************************************************************/ +/** @def CONV_TO_FLAT + * Get flat address. In 16-bit the parameter is a real mode far address, while + * in 32-bit and 64-bit modes it is already flat. + */ +/** @def CONV_TO_PROT_FAR16 + * Get a 32-bit value that makes a protected mode far 16:16 address. + */ +/** @def CONV_TO_RM_FAR16 + * Get a 32-bit value that makes a real mode far 16:16 address. In 16-bit mode + * this is already what we've got, except must be converted to uint32_t. + */ +#if ARCH_BITS == 16 +# define CONV_TO_FLAT(a_fpfn) (((uint32_t)BS3_FP_SEG(a_fpfn) << 4) + BS3_FP_OFF(a_fpfn)) +# define CONV_TO_PROT_FAR16(a_fpfn) RT_MAKE_U32(BS3_FP_OFF(a_fpfn), Bs3SelRealModeCodeToProtMode(BS3_FP_SEG(a_fpfn))) +# define CONV_TO_RM_FAR16(a_fpfn) RT_MAKE_U32(BS3_FP_OFF(a_fpfn), BS3_FP_SEG(a_fpfn)) +#else +# define CONV_TO_FLAT(a_fpfn) ((uint32_t)(uintptr_t)(a_fpfn)) +# define CONV_TO_PROT_FAR16(a_fpfn) Bs3SelFlatCodeToProtFar16((uint32_t)(uintptr_t)(a_fpfn)) +# define CONV_TO_RM_FAR16(a_fpfn) Bs3SelFlatCodeToRealMode( (uint32_t)(uintptr_t)(a_fpfn)) +#endif + + +/********************************************************************************************************************************* +* Assembly Symbols * +*********************************************************************************************************************************/ +/* These are in the same code segment as the main API, so no FAR necessary. */ +BS3_DECL_NEAR(uint8_t) TMPL_NM(Bs3TestCallDoerInRM)(uint32_t uCallbackFarPtr); +BS3_DECL_NEAR(uint8_t) TMPL_NM(Bs3TestCallDoerInPE16)(uint32_t uCallbackFarPtr); +BS3_DECL_NEAR(uint8_t) TMPL_NM(Bs3TestCallDoerInPE16_32)(uint32_t uFlatAddrCallback, uint8_t bMode); +BS3_DECL_NEAR(uint8_t) TMPL_NM(Bs3TestCallDoerInPE16_V86)(uint32_t uCallbackFarPtr); +BS3_DECL_NEAR(uint8_t) TMPL_NM(Bs3TestCallDoerInPE32)(uint32_t uFlatAddrCallback, uint8_t bMode); +BS3_DECL_NEAR(uint8_t) TMPL_NM(Bs3TestCallDoerInPE32_16)(uint32_t uCallbackFarPtr); +BS3_DECL_NEAR(uint8_t) TMPL_NM(Bs3TestCallDoerInPEV86)(uint32_t uCallbackFarPtr); +BS3_DECL_NEAR(uint8_t) TMPL_NM(Bs3TestCallDoerInPP16)(uint32_t uCallbackFarPtr); +BS3_DECL_NEAR(uint8_t) TMPL_NM(Bs3TestCallDoerInPP16_32)(uint32_t uFlatAddrCallback, uint8_t bMode); +BS3_DECL_NEAR(uint8_t) TMPL_NM(Bs3TestCallDoerInPP16_V86)(uint32_t uCallbackFarPtr); +BS3_DECL_NEAR(uint8_t) TMPL_NM(Bs3TestCallDoerInPP32)(uint32_t uFlatAddrCallback, uint8_t bMode); +BS3_DECL_NEAR(uint8_t) TMPL_NM(Bs3TestCallDoerInPP32_16)(uint32_t uCallbackFarPtr); +BS3_DECL_NEAR(uint8_t) TMPL_NM(Bs3TestCallDoerInPPV86)(uint32_t uCallbackFarPtr); +BS3_DECL_NEAR(uint8_t) TMPL_NM(Bs3TestCallDoerInPAE16)(uint32_t uCallbackFarPtr); +BS3_DECL_NEAR(uint8_t) TMPL_NM(Bs3TestCallDoerInPAE16_32)(uint32_t uFlatAddrCallback, uint8_t bMode); +BS3_DECL_NEAR(uint8_t) TMPL_NM(Bs3TestCallDoerInPAE16_V86)(uint32_t uCallbackFarPtr); +BS3_DECL_NEAR(uint8_t) TMPL_NM(Bs3TestCallDoerInPAE32)(uint32_t uFlatAddrCallback, uint8_t bMode); +BS3_DECL_NEAR(uint8_t) TMPL_NM(Bs3TestCallDoerInPAE32_16)(uint32_t uCallbackFarPtr); +BS3_DECL_NEAR(uint8_t) TMPL_NM(Bs3TestCallDoerInPAEV86)(uint32_t uCallbackFarPtr); +BS3_DECL_NEAR(uint8_t) TMPL_NM(Bs3TestCallDoerInLM16)(uint32_t uCallbackFarPtr); +BS3_DECL_NEAR(uint8_t) TMPL_NM(Bs3TestCallDoerInLM32)(uint32_t uFlatAddrCallback); +BS3_DECL_NEAR(uint8_t) TMPL_NM(Bs3TestCallDoerInLM64)(uint32_t uFlatAddrCallback, uint8_t bMode); + +#endif /* !BS3KIT_INCLUDED_bs3_mode_TestDoModes_h */ + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-TestDoModesByMax.c b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-TestDoModesByMax.c new file mode 100644 index 00000000..3cc5c888 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-TestDoModesByMax.c @@ -0,0 +1,370 @@ +/* $Id: bs3-mode-TestDoModesByMax.c $ */ +/** @file + * BS3Kit - Bs3TestDoModesByMax + */ + +/* + * Copyright (C) 2007-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#if TMPL_MODE == BS3_MODE_RM +# define BS3_USE_RM_TEXT_SEG 1 /* Real mode version in RMTEXT16 segment to save space. */ +# include "bs3kit-template-header.h" +# include "bs3-cmn-test.h" +#else +# include "bs3kit-template-header.h" +# include "bs3-cmn-test.h" +#endif +#include "bs3-mode-TestDoModes.h" + + + +/** + * Warns about CPU modes that must be skipped. + * + * It will try not warn about modes for which there are no tests. + * + * @param paEntries The mode test entries. + * @param cEntries The number of tests. + * @param bCpuType The CPU type byte (see #BS3CPU_TYPE_MASK). + * @param fHavePae Whether the CPU has PAE. + * @param fHaveLongMode Whether the CPU does long mode. + */ +static void bs3TestWarnAboutSkippedModes(PCBS3TESTMODEBYMAXENTRY paEntries, unsigned cEntries, + uint8_t bCpuType, bool fHavePae, bool fHaveLongMode) +{ + bool fComplained286 = false; + bool fComplained386 = false; + bool fComplainedPAE = false; + bool fComplainedAMD64 = false; + unsigned i; + + /* + * Complaint run. + */ + for (i = 0; i < cEntries; i++) + { + if ( !fComplained286 + && paEntries[i].pfnDoPE16) + { + if (bCpuType < BS3CPU_80286) + { + Bs3Printf("Only executing real-mode tests as no 80286+ CPU was detected.\n"); + break; + } + fComplained286 = true; + } + + if ( !fComplained386 + && ( paEntries[i].fDoPE16_32 + || paEntries[i].fDoPE16_V86 + || paEntries[i].fDoPE32 + || paEntries[i].fDoPE32_16 + || paEntries[i].fDoPEV86 + || paEntries[i].fDoPP16 + || paEntries[i].fDoPP16_32 + || paEntries[i].fDoPP16_V86 + || paEntries[i].fDoPP32 + || paEntries[i].fDoPP32_16 + || paEntries[i].fDoPPV86) ) + { + if (bCpuType < BS3CPU_80386) + { + Bs3Printf("80286 CPU: Only executing 16-bit protected and real mode tests.\n"); + break; + } + fComplained386 = true; + } + + if ( !fComplainedPAE + && ( paEntries[i].fDoPAE16 + || paEntries[i].fDoPAE16_32 + || paEntries[i].fDoPAE16_V86 + || paEntries[i].fDoPAE32 + || paEntries[i].fDoPAE32_16 + || paEntries[i].fDoPAEV86) ) + { + if (!fHavePae) + { + Bs3Printf("PAE and long mode tests will be skipped.\n"); + break; + } + fComplainedPAE = true; + } + + if ( !fComplainedAMD64 + && ( paEntries[i].fDoLM16 + || paEntries[i].fDoLM32 + || paEntries[i].fDoLM64) ) + { + if (!fHaveLongMode) + { + Bs3Printf("Long mode tests will be skipped.\n"); + break; + } + fComplainedAMD64 = true; + } + } +} + +#undef Bs3TestDoModesByMax +BS3_MODE_DEF(void, Bs3TestDoModesByMax,(PCBS3TESTMODEBYMAXENTRY paEntries, size_t cEntries)) +{ + bool const fVerbose = true; + bool const fDoV86Modes = true; + bool const fDoWeirdV86Modes = true; + uint16_t const uCpuDetected = g_uBs3CpuDetected; + uint8_t const bCpuType = uCpuDetected & BS3CPU_TYPE_MASK; + bool const fHavePae = RT_BOOL(uCpuDetected & BS3CPU_F_PAE); + bool const fHaveLongMode = RT_BOOL(uCpuDetected & BS3CPU_F_LONG_MODE); + unsigned i; + +#if 1 /* debug. */ + Bs3Printf("Bs3TestDoModes: uCpuDetected=%#x fHavePae=%d fHaveLongMode=%d\n", uCpuDetected, fHavePae, fHaveLongMode); +#endif + bs3TestWarnAboutSkippedModes(paEntries, cEntries, bCpuType, fHavePae, fHaveLongMode); + + /* + * The real run. + */ + for (i = 0; i < cEntries; i++) + { + const char *pszFmtStr = "Error #%u (%#x) in %s!\n"; + bool fSkipped = true; + uint8_t bErrNo; + + if (paEntries[i].pszSubTest != NULL) + Bs3TestSub(paEntries[i].pszSubTest); + +#define PRE_DO_CALL(a_szModeName) do { if (fVerbose) Bs3TestPrintf("...%s\n", a_szModeName); } while (0) +#define CHECK_RESULT(a_szModeName) \ + do { \ + if (bErrNo != BS3TESTDOMODE_SKIPPED) \ + { \ + /*Bs3Printf("bErrNo=%#x %s\n", bErrNo, a_szModeName);*/ \ + fSkipped = false; \ + if (bErrNo != 0) \ + Bs3TestFailedF(pszFmtStr, bErrNo, bErrNo, a_szModeName); \ + } \ + } while (0) + + if (paEntries[i].fDoRM) + { + PRE_DO_CALL(g_szBs3ModeName_rm); + bErrNo = TMPL_NM(Bs3TestCallDoerInRM)(CONV_TO_RM_FAR16(paEntries[i].pfnDoRM)); + CHECK_RESULT(g_szBs3ModeName_rm); + } + + if (bCpuType < BS3CPU_80286) + { + if (fSkipped) + Bs3TestSkipped(NULL); + continue; + } + + /* + * Unpaged prot mode. + */ + if (paEntries[i].fDoPE16) + { + PRE_DO_CALL(g_szBs3ModeName_pe16); + bErrNo = TMPL_NM(Bs3TestCallDoerInPE16)(CONV_TO_PROT_FAR16(paEntries[i].pfnDoPE16)); + CHECK_RESULT(g_szBs3ModeName_pe16); + } + if (bCpuType < BS3CPU_80386) + { + if (fSkipped) + Bs3TestSkipped(NULL); + continue; + } + + if (paEntries[i].fDoPE16_32) + { + PRE_DO_CALL(g_szBs3ModeName_pe16_32); + bErrNo = TMPL_NM(Bs3TestCallDoerInPE16_32)(CONV_TO_FLAT(paEntries[i].pfnDoPE16_32), BS3_MODE_PE16_32); + CHECK_RESULT(g_szBs3ModeName_pe16_32); + } + + if (paEntries[i].fDoPE16_V86 && fDoWeirdV86Modes) + { + PRE_DO_CALL(g_szBs3ModeName_pe16_v86); + bErrNo = TMPL_NM(Bs3TestCallDoerInPE16_32)(CONV_TO_FLAT(paEntries[i].pfnDoPE16_32), BS3_MODE_PE16_V86); + CHECK_RESULT(g_szBs3ModeName_pe16_v86); + } + + if (paEntries[i].fDoPE32) + { + PRE_DO_CALL(g_szBs3ModeName_pe32); + bErrNo = TMPL_NM(Bs3TestCallDoerInPE32)(CONV_TO_FLAT(paEntries[i].pfnDoPE32), BS3_MODE_PE32); + CHECK_RESULT(g_szBs3ModeName_pe32); + } + + if (paEntries[i].fDoPE32_16) + { + PRE_DO_CALL(g_szBs3ModeName_pe32_16); + bErrNo = TMPL_NM(Bs3TestCallDoerInPE32)(CONV_TO_FLAT(paEntries[i].pfnDoPE32), BS3_MODE_PE32_16); + CHECK_RESULT(g_szBs3ModeName_pe32_16); + } + + if (paEntries[i].fDoPEV86 && fDoV86Modes) + { + PRE_DO_CALL(g_szBs3ModeName_pev86); + bErrNo = TMPL_NM(Bs3TestCallDoerInPE32)(CONV_TO_FLAT(paEntries[i].pfnDoPE32), BS3_MODE_PEV86); + CHECK_RESULT(g_szBs3ModeName_pev86); + } + + /* + * Paged protected mode. + */ + if (paEntries[i].fDoPP16) + { + PRE_DO_CALL(g_szBs3ModeName_pp16); + bErrNo = TMPL_NM(Bs3TestCallDoerInPP16_32)(CONV_TO_FLAT(paEntries[i].pfnDoPP16_32), BS3_MODE_PP16); + CHECK_RESULT(g_szBs3ModeName_pp16); + } + + if (paEntries[i].fDoPP16_32) + { + PRE_DO_CALL(g_szBs3ModeName_pp16_32); + bErrNo = TMPL_NM(Bs3TestCallDoerInPP16_32)(CONV_TO_FLAT(paEntries[i].pfnDoPP16_32), BS3_MODE_PP16_32); + CHECK_RESULT(g_szBs3ModeName_pp16_32); + } + + if (paEntries[i].fDoPP16_V86 && fDoWeirdV86Modes) + { + PRE_DO_CALL(g_szBs3ModeName_pp16_v86); + bErrNo = TMPL_NM(Bs3TestCallDoerInPP16_32)(CONV_TO_FLAT(paEntries[i].pfnDoPP16_32), BS3_MODE_PP16_V86); + CHECK_RESULT(g_szBs3ModeName_pp16_v86); + } + + if (paEntries[i].fDoPP32) + { + PRE_DO_CALL(g_szBs3ModeName_pp32); + bErrNo = TMPL_NM(Bs3TestCallDoerInPP32)(CONV_TO_FLAT(paEntries[i].pfnDoPP32), BS3_MODE_PP32); + CHECK_RESULT(g_szBs3ModeName_pp32); + } + + if (paEntries[i].fDoPP32_16) + { + PRE_DO_CALL(g_szBs3ModeName_pp32_16); + bErrNo = TMPL_NM(Bs3TestCallDoerInPP32)(CONV_TO_FLAT(paEntries[i].pfnDoPP32), BS3_MODE_PP32_16); + CHECK_RESULT(g_szBs3ModeName_pp32_16); + } + + if (paEntries[i].fDoPPV86 && fDoV86Modes) + { + PRE_DO_CALL(g_szBs3ModeName_ppv86); + bErrNo = TMPL_NM(Bs3TestCallDoerInPP32)(CONV_TO_FLAT(paEntries[i].pfnDoPP32), BS3_MODE_PPV86); + CHECK_RESULT(g_szBs3ModeName_ppv86); + } + + /* + * Protected mode with PAE paging. + */ + if (!fHavePae) + { + if (fSkipped) + Bs3TestSkipped(NULL); + continue; + } + + if (paEntries[i].fDoPAE16) + { + PRE_DO_CALL(g_szBs3ModeName_pae16); + bErrNo = TMPL_NM(Bs3TestCallDoerInPAE16_32)(CONV_TO_FLAT(paEntries[i].pfnDoPAE16_32), BS3_MODE_PAE16); + CHECK_RESULT(g_szBs3ModeName_pae16); + } + + if (paEntries[i].fDoPAE16_32) + { + PRE_DO_CALL(g_szBs3ModeName_pae16_32); + bErrNo = TMPL_NM(Bs3TestCallDoerInPAE16_32)(CONV_TO_FLAT(paEntries[i].pfnDoPAE16_32), BS3_MODE_PAE16_32); + CHECK_RESULT(g_szBs3ModeName_pae16_32); + } + + if (paEntries[i].fDoPAE16_V86 && fDoWeirdV86Modes) + { + PRE_DO_CALL(g_szBs3ModeName_pae16_v86); + bErrNo = TMPL_NM(Bs3TestCallDoerInPAE16_32)(CONV_TO_FLAT(paEntries[i].pfnDoPAE16_32), BS3_MODE_PAE16_V86); + CHECK_RESULT(g_szBs3ModeName_pae16_v86); + } + + if (paEntries[i].fDoPAE32) + { + PRE_DO_CALL(g_szBs3ModeName_pae32); + bErrNo = TMPL_NM(Bs3TestCallDoerInPAE32)(CONV_TO_FLAT(paEntries[i].pfnDoPAE32), BS3_MODE_PAE32); + CHECK_RESULT(g_szBs3ModeName_pae32); + } + + if (paEntries[i].fDoPAE32_16) + { + PRE_DO_CALL(g_szBs3ModeName_pae32_16); + bErrNo = TMPL_NM(Bs3TestCallDoerInPAE32)(CONV_TO_FLAT(paEntries[i].pfnDoPAE32), BS3_MODE_PAE32_16); + CHECK_RESULT(g_szBs3ModeName_pae32_16); + } + + if (paEntries[i].fDoPAEV86 && fDoV86Modes) + { + PRE_DO_CALL(g_szBs3ModeName_paev86); + bErrNo = TMPL_NM(Bs3TestCallDoerInPAE32)(CONV_TO_FLAT(paEntries[i].pfnDoPAE32), BS3_MODE_PAEV86); + CHECK_RESULT(g_szBs3ModeName_paev86); + } + + /* + * Long mode. + */ + if (!fHaveLongMode) + { + if (fSkipped) + Bs3TestSkipped(NULL); + continue; + } + + if (paEntries[i].fDoLM16) + { + PRE_DO_CALL(g_szBs3ModeName_lm16); + bErrNo = TMPL_NM(Bs3TestCallDoerInLM64)(CONV_TO_FLAT(paEntries[i].pfnDoLM64), BS3_MODE_LM16); + CHECK_RESULT(g_szBs3ModeName_lm16); + } + + if (paEntries[i].fDoLM32) + { + PRE_DO_CALL(g_szBs3ModeName_lm32); + bErrNo = TMPL_NM(Bs3TestCallDoerInLM64)(CONV_TO_FLAT(paEntries[i].pfnDoLM64), BS3_MODE_LM32); + CHECK_RESULT(g_szBs3ModeName_lm32); + } + + if (paEntries[i].fDoLM64) + { + PRE_DO_CALL(g_szBs3ModeName_lm64); + bErrNo = TMPL_NM(Bs3TestCallDoerInLM64)(CONV_TO_FLAT(paEntries[i].pfnDoLM64), BS3_MODE_LM64); + CHECK_RESULT(g_szBs3ModeName_lm64); + } + + if (fSkipped) + Bs3TestSkipped("skipped\n"); + } + Bs3TestSubDone(); +} + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-TestDoModesByMaxStub.asm b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-TestDoModesByMaxStub.asm new file mode 100644 index 00000000..43a56b5b --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-TestDoModesByMaxStub.asm @@ -0,0 +1,53 @@ +; $Id: bs3-mode-TestDoModesByMaxStub.asm $ +;; @file +; BS3Kit - Bs3TestDoModesByMax near stub. +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + +;********************************************************************************************************************************* +;* Header Files * +;********************************************************************************************************************************* +%include "bs3kit-template-header.mac" + +; +; Near stub for the API call (16-bit only). +; +%if TMPL_BITS == 16 + %if TMPL_MODE == BS3_MODE_RM +BS3_BEGIN_RMTEXT16 + %endif +BS3_BEGIN_TEXT16_NEARSTUBS +BS3_PROC_BEGIN_MODE Bs3TestDoModesByMax, BS3_PBC_NEAR + pop ax + push cs + push ax + %if TMPL_MODE == BS3_MODE_RM + extern TMPL_FAR_NM(Bs3TestDoModesByMax):wrt BS3GROUPRMTEXT16 + jmp far TMPL_FAR_NM(Bs3TestDoModesByMax) + %else + extern TMPL_FAR_NM(Bs3TestDoModesByMax):wrt CGROUP16 + jmp TMPL_NM(Bs3TestDoModesByMax) + %endif +BS3_PROC_END_MODE Bs3TestDoModesByMax +%endif + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-TestDoModesByOne.c b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-TestDoModesByOne.c new file mode 100644 index 00000000..bebf347c --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-TestDoModesByOne.c @@ -0,0 +1,404 @@ +/* $Id: bs3-mode-TestDoModesByOne.c $ */ +/** @file + * BS3Kit - Bs3TestDoModesByOne + */ + +/* + * Copyright (C) 2007-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#if TMPL_MODE == BS3_MODE_RM +# define BS3_USE_RM_TEXT_SEG 1 /* Real mode version in RMTEXT16 segment to save space. */ +# include "bs3kit-template-header.h" +# include "bs3-cmn-test.h" +#else +# include "bs3kit-template-header.h" +# include "bs3-cmn-test.h" +#endif +#include "bs3-mode-TestDoModes.h" + + +/********************************************************************************************************************************* +* Assembly Symbols * +*********************************************************************************************************************************/ +/* Assembly helpers for switching to the work bitcount and calling it. */ +BS3_DECL_FAR(uint8_t) Bs3TestCallDoerTo16_f16(uint8_t bMode); +BS3_DECL_FAR(uint8_t) Bs3TestCallDoerTo16_c32(uint8_t bMode); +BS3_DECL_FAR(uint8_t) Bs3TestCallDoerTo16_c64(uint8_t bMode); +BS3_DECL_FAR(uint8_t) Bs3TestCallDoerTo32_f16(uint8_t bMode); +BS3_DECL_FAR(uint8_t) Bs3TestCallDoerTo32_c32(uint8_t bMode); +BS3_DECL_FAR(uint8_t) Bs3TestCallDoerTo32_c64(uint8_t bMode); +BS3_DECL_FAR(uint8_t) Bs3TestCallDoerTo64_f16(uint8_t bMode); +BS3_DECL_FAR(uint8_t) Bs3TestCallDoerTo64_c32(uint8_t bMode); +BS3_DECL_FAR(uint8_t) Bs3TestCallDoerTo64_c64(uint8_t bMode); + + +/** The current worker function, picked up by our assembly helpers. */ +#ifndef DOXYGEN_RUNNING +# define g_pfnBs3TestDoModesByOneCurrent BS3_CMN_NM(g_pfnBs3TestDoModesByOneCurrent) +#endif +extern PFNBS3TESTDOMODE g_pfnBs3TestDoModesByOneCurrent; + +#include <iprt/asm-amd64-x86.h> + + +#undef Bs3TestDoModesByOne +BS3_MODE_DEF(void, Bs3TestDoModesByOne,(PCBS3TESTMODEBYONEENTRY paEntries, size_t cEntries, uint32_t fFlags)) +{ + bool const fVerbose = true; + bool const fDoV86Modes = true; + bool const fDoWeirdV86Modes = true; + uint16_t const uCpuDetected = g_uBs3CpuDetected; + uint8_t const bCpuType = uCpuDetected & BS3CPU_TYPE_MASK; + bool const fHavePae = RT_BOOL(uCpuDetected & BS3CPU_F_PAE); + bool const fHaveLongMode = RT_BOOL(uCpuDetected & BS3CPU_F_LONG_MODE); + unsigned i; + +#if 1 /* debug. */ + Bs3Printf("Bs3TestDoModesByOne: uCpuDetected=%#x fHavePae=%d fHaveLongMode=%d\n", uCpuDetected, fHavePae, fHaveLongMode); +#endif + + /* + * Inform about modes we won't test (if any). + */ + if (bCpuType < BS3CPU_80286) + Bs3Printf("Only executing real-mode tests as no 80286+ CPU was detected.\n"); + else if (bCpuType < BS3CPU_80386) + Bs3Printf("80286 CPU: Only executing 16-bit protected and real mode tests.\n"); + else if (!fHavePae) + Bs3Printf("PAE and long mode tests will be skipped.\n"); + else if (!fHaveLongMode) + Bs3Printf("Long mode tests will be skipped.\n"); +#if ARCH_BITS != 16 + Bs3Printf("Real-mode tests will be skipped.\n"); +#endif + + /* + * The real run. + */ + for (i = 0; i < cEntries; i++) + { + const char *pszFmtStr = "Error #%u (%#x) in %s!\n"; + bool fSkipped = true; + bool const fOnlyPaging = RT_BOOL(paEntries[i].fFlags & BS3TESTMODEBYONEENTRY_F_ONLY_PAGING); + uint8_t bErrNo; + Bs3TestSub(paEntries[i].pszSubTest); + +#define PRE_DO_CALL(a_szModeName) do { if (fVerbose) Bs3TestPrintf("...%s\n", a_szModeName); } while (0) +#define CHECK_RESULT(a_szModeName) \ + do { \ + if (bErrNo != BS3TESTDOMODE_SKIPPED) \ + { \ + /*Bs3Printf("bErrNo=%#x %s\n", bErrNo, a_szModeName);*/ \ + fSkipped = false; \ + if (bErrNo != 0) \ + Bs3TestFailedF(pszFmtStr, bErrNo, bErrNo, a_szModeName); \ + } \ + } while (0) + + g_pfnBs3TestDoModesByOneCurrent = paEntries[i].pfnWorker; + +#if ARCH_BITS != 64 + +# if ARCH_BITS == 16 + if (!fOnlyPaging) + { + PRE_DO_CALL(g_szBs3ModeName_rm); + bErrNo = TMPL_NM(Bs3TestCallDoerInRM)(CONV_TO_RM_FAR16(paEntries[i].pfnWorker)); + CHECK_RESULT(g_szBs3ModeName_rm); + } +# endif + + if (bCpuType < BS3CPU_80286) + { + if (fSkipped) + Bs3TestSkipped(NULL); + continue; + } + + /* + * Unpaged prot mode. + */ + if (!fOnlyPaging) + { + PRE_DO_CALL(g_szBs3ModeName_pe16); +# if ARCH_BITS == 16 + bErrNo = TMPL_NM(Bs3TestCallDoerInPE16)(CONV_TO_PROT_FAR16(paEntries[i].pfnWorker)); +# else + bErrNo = TMPL_NM(Bs3TestCallDoerInPE16)(CONV_TO_PROT_FAR16(RT_CONCAT3(Bs3TestCallDoerTo,ARCH_BITS,_f16))); +# endif + CHECK_RESULT(g_szBs3ModeName_pe16); + } + if (bCpuType < BS3CPU_80386) + { + if (fSkipped) + Bs3TestSkipped(NULL); + continue; + } + + if (!fOnlyPaging) + { + PRE_DO_CALL(g_szBs3ModeName_pe16_32); +# if ARCH_BITS == 32 + bErrNo = TMPL_NM(Bs3TestCallDoerInPE16_32)(CONV_TO_FLAT(paEntries[i].pfnWorker), BS3_MODE_PE16_32); +# else + bErrNo = TMPL_NM(Bs3TestCallDoerInPE16_32)(CONV_TO_FLAT(RT_CONCAT3(Bs3TestCallDoerTo,ARCH_BITS,_c32)), BS3_MODE_PE16_32); +# endif + CHECK_RESULT(g_szBs3ModeName_pe16_32); + } + + if (fDoWeirdV86Modes && !fOnlyPaging) + { + PRE_DO_CALL(g_szBs3ModeName_pe16_v86); +# if ARCH_BITS == 16 + bErrNo = TMPL_NM(Bs3TestCallDoerInPE16_V86)(CONV_TO_RM_FAR16(paEntries[i].pfnWorker)); +# else + bErrNo = TMPL_NM(Bs3TestCallDoerInPE16_V86)(CONV_TO_RM_FAR16(RT_CONCAT3(Bs3TestCallDoerTo,ARCH_BITS,_f16))); +# endif + CHECK_RESULT(g_szBs3ModeName_pe16_v86); + } + + if (!fOnlyPaging) + { + PRE_DO_CALL(g_szBs3ModeName_pe32); +# if ARCH_BITS == 32 + bErrNo = TMPL_NM(Bs3TestCallDoerInPE32)(CONV_TO_FLAT(paEntries[i].pfnWorker), BS3_MODE_PE32); +# else + bErrNo = TMPL_NM(Bs3TestCallDoerInPE32)(CONV_TO_FLAT(RT_CONCAT3(Bs3TestCallDoerTo,ARCH_BITS,_c32)), BS3_MODE_PE32); +# endif + CHECK_RESULT(g_szBs3ModeName_pe32); + } + + if (!fOnlyPaging) + { + PRE_DO_CALL(g_szBs3ModeName_pe32_16); +# if ARCH_BITS == 16 + bErrNo = TMPL_NM(Bs3TestCallDoerInPE32_16)(CONV_TO_PROT_FAR16(paEntries[i].pfnWorker)); +# else + bErrNo = TMPL_NM(Bs3TestCallDoerInPE32_16)(CONV_TO_PROT_FAR16(RT_CONCAT3(Bs3TestCallDoerTo,ARCH_BITS,_f16))); +# endif + CHECK_RESULT(g_szBs3ModeName_pe32_16); + } + + if (fDoV86Modes && !fOnlyPaging) + { + PRE_DO_CALL(g_szBs3ModeName_pev86); +# if ARCH_BITS == 16 + bErrNo = TMPL_NM(Bs3TestCallDoerInPEV86)(CONV_TO_RM_FAR16(paEntries[i].pfnWorker)); +# else + bErrNo = TMPL_NM(Bs3TestCallDoerInPEV86)(CONV_TO_RM_FAR16(RT_CONCAT3(Bs3TestCallDoerTo,ARCH_BITS,_f16))); +# endif + CHECK_RESULT(g_szBs3ModeName_pev86); + } + + /* + * Paged protected mode. + */ + if (true) + { + PRE_DO_CALL(g_szBs3ModeName_pp16); +# if ARCH_BITS == 16 + bErrNo = TMPL_NM(Bs3TestCallDoerInPP16)(CONV_TO_PROT_FAR16(paEntries[i].pfnWorker)); +# else + bErrNo = TMPL_NM(Bs3TestCallDoerInPP16)(CONV_TO_PROT_FAR16(RT_CONCAT3(Bs3TestCallDoerTo,ARCH_BITS,_f16))); +# endif + CHECK_RESULT(g_szBs3ModeName_pp16); + } + + if (true) + { + PRE_DO_CALL(g_szBs3ModeName_pp16_32); +# if ARCH_BITS == 32 + bErrNo = TMPL_NM(Bs3TestCallDoerInPP16_32)(CONV_TO_FLAT(paEntries[i].pfnWorker), BS3_MODE_PP16_32); +# else + bErrNo = TMPL_NM(Bs3TestCallDoerInPP16_32)(CONV_TO_FLAT(RT_CONCAT3(Bs3TestCallDoerTo,ARCH_BITS,_c32)), BS3_MODE_PP16_32); +# endif + CHECK_RESULT(g_szBs3ModeName_pp16_32); + } + + if (fDoWeirdV86Modes) + { + PRE_DO_CALL(g_szBs3ModeName_pp16_v86); +# if ARCH_BITS == 16 + bErrNo = TMPL_NM(Bs3TestCallDoerInPP16_V86)(CONV_TO_RM_FAR16(paEntries[i].pfnWorker)); +# else + bErrNo = TMPL_NM(Bs3TestCallDoerInPP16_V86)(CONV_TO_RM_FAR16(RT_CONCAT3(Bs3TestCallDoerTo,ARCH_BITS,_f16))); +# endif + CHECK_RESULT(g_szBs3ModeName_pp16_v86); + } + + if (true) + { + PRE_DO_CALL(g_szBs3ModeName_pp32); +# if ARCH_BITS == 32 + bErrNo = TMPL_NM(Bs3TestCallDoerInPP32)(CONV_TO_FLAT(paEntries[i].pfnWorker), BS3_MODE_PP32); +# else + bErrNo = TMPL_NM(Bs3TestCallDoerInPP32)(CONV_TO_FLAT(RT_CONCAT3(Bs3TestCallDoerTo,ARCH_BITS,_c32)), BS3_MODE_PP32); +# endif + CHECK_RESULT(g_szBs3ModeName_pp32); + } + + if (true) + { + PRE_DO_CALL(g_szBs3ModeName_pp32_16); +# if ARCH_BITS == 16 + bErrNo = TMPL_NM(Bs3TestCallDoerInPP32_16)(CONV_TO_PROT_FAR16(paEntries[i].pfnWorker)); +# else + bErrNo = TMPL_NM(Bs3TestCallDoerInPP32_16)(CONV_TO_PROT_FAR16(RT_CONCAT3(Bs3TestCallDoerTo,ARCH_BITS,_f16))); +# endif + CHECK_RESULT(g_szBs3ModeName_pp32_16); + } + + if (fDoV86Modes) + { + PRE_DO_CALL(g_szBs3ModeName_ppv86); +# if ARCH_BITS == 16 + bErrNo = TMPL_NM(Bs3TestCallDoerInPPV86)(CONV_TO_RM_FAR16(paEntries[i].pfnWorker)); +# else + bErrNo = TMPL_NM(Bs3TestCallDoerInPPV86)(CONV_TO_RM_FAR16(RT_CONCAT3(Bs3TestCallDoerTo,ARCH_BITS,_f16))); +# endif + CHECK_RESULT(g_szBs3ModeName_ppv86); + } + + + /* + * Protected mode with PAE paging. + */ + if (true) + { + PRE_DO_CALL(g_szBs3ModeName_pae16); +# if ARCH_BITS == 16 + bErrNo = TMPL_NM(Bs3TestCallDoerInPAE16)(CONV_TO_PROT_FAR16(paEntries[i].pfnWorker)); +# else + bErrNo = TMPL_NM(Bs3TestCallDoerInPAE16)(CONV_TO_PROT_FAR16(RT_CONCAT3(Bs3TestCallDoerTo,ARCH_BITS,_f16))); +# endif + CHECK_RESULT(g_szBs3ModeName_pae16); + } + + if (true) + { + PRE_DO_CALL(g_szBs3ModeName_pae16_32); +# if ARCH_BITS == 32 + bErrNo = TMPL_NM(Bs3TestCallDoerInPAE16_32)(CONV_TO_FLAT(paEntries[i].pfnWorker), BS3_MODE_PAE16_32); +# else + bErrNo = TMPL_NM(Bs3TestCallDoerInPAE16_32)(CONV_TO_FLAT(RT_CONCAT3(Bs3TestCallDoerTo,ARCH_BITS,_c32)), BS3_MODE_PAE16_32); +# endif + CHECK_RESULT(g_szBs3ModeName_pae16_32); + } + + if (fDoWeirdV86Modes) + { + PRE_DO_CALL(g_szBs3ModeName_pae16_v86); +# if ARCH_BITS == 16 + bErrNo = TMPL_NM(Bs3TestCallDoerInPAE16_V86)(CONV_TO_RM_FAR16(paEntries[i].pfnWorker)); +# else + bErrNo = TMPL_NM(Bs3TestCallDoerInPAE16_V86)(CONV_TO_RM_FAR16(RT_CONCAT3(Bs3TestCallDoerTo,ARCH_BITS,_f16))); +# endif + CHECK_RESULT(g_szBs3ModeName_pae16_v86); + } + + if (true) + { + PRE_DO_CALL(g_szBs3ModeName_pae32); +# if ARCH_BITS == 32 + bErrNo = TMPL_NM(Bs3TestCallDoerInPAE32)(CONV_TO_FLAT(paEntries[i].pfnWorker), BS3_MODE_PAE32); +# else + bErrNo = TMPL_NM(Bs3TestCallDoerInPAE32)(CONV_TO_FLAT(RT_CONCAT3(Bs3TestCallDoerTo,ARCH_BITS,_c32)), BS3_MODE_PAE32); +# endif + CHECK_RESULT(g_szBs3ModeName_pae32); + } + + if (true) + { + PRE_DO_CALL(g_szBs3ModeName_pae32_16); +# if ARCH_BITS == 16 + bErrNo = TMPL_NM(Bs3TestCallDoerInPAE32_16)(CONV_TO_PROT_FAR16(paEntries[i].pfnWorker)); +# else + bErrNo = TMPL_NM(Bs3TestCallDoerInPAE32_16)(CONV_TO_PROT_FAR16(RT_CONCAT3(Bs3TestCallDoerTo,ARCH_BITS,_f16))); +# endif + CHECK_RESULT(g_szBs3ModeName_pae32_16); + } + + if (fDoV86Modes) + { + PRE_DO_CALL(g_szBs3ModeName_paev86); +# if ARCH_BITS == 16 + bErrNo = TMPL_NM(Bs3TestCallDoerInPAEV86)(CONV_TO_RM_FAR16(paEntries[i].pfnWorker)); +# else + bErrNo = TMPL_NM(Bs3TestCallDoerInPAEV86)(CONV_TO_RM_FAR16(RT_CONCAT3(Bs3TestCallDoerTo,ARCH_BITS,_f16))); +# endif + CHECK_RESULT(g_szBs3ModeName_paev86); + } + +#endif /* ARCH_BITS != 64 */ + + /* + * Long mode. + */ + if (!fHaveLongMode) + { + if (fSkipped) + Bs3TestSkipped(NULL); + continue; + } + + if (true) + { + PRE_DO_CALL(g_szBs3ModeName_lm16); +#if ARCH_BITS == 16 + bErrNo = TMPL_NM(Bs3TestCallDoerInLM16)(CONV_TO_PROT_FAR16(paEntries[i].pfnWorker)); +#else + bErrNo = TMPL_NM(Bs3TestCallDoerInLM16)(CONV_TO_PROT_FAR16(RT_CONCAT3(Bs3TestCallDoerTo,ARCH_BITS,_f16))); +#endif + CHECK_RESULT(g_szBs3ModeName_lm16); + } + + if (true) + { + PRE_DO_CALL(g_szBs3ModeName_lm32); +#if ARCH_BITS == 32 + bErrNo = TMPL_NM(Bs3TestCallDoerInLM32)(CONV_TO_FLAT(paEntries[i].pfnWorker)); +#else + bErrNo = TMPL_NM(Bs3TestCallDoerInLM32)(CONV_TO_FLAT(RT_CONCAT3(Bs3TestCallDoerTo,ARCH_BITS,_c32))); +#endif + CHECK_RESULT(g_szBs3ModeName_lm32); + } + + if (true) + { + PRE_DO_CALL(g_szBs3ModeName_lm64); +#if ARCH_BITS == 64 + bErrNo = TMPL_NM(Bs3TestCallDoerInLM64)(CONV_TO_FLAT(paEntries[i].pfnWorker), BS3_MODE_LM64); +#else + bErrNo = TMPL_NM(Bs3TestCallDoerInLM64)(CONV_TO_FLAT(RT_CONCAT3(Bs3TestCallDoerTo,ARCH_BITS,_c64)), BS3_MODE_LM64); +#endif + CHECK_RESULT(g_szBs3ModeName_lm64); + } + + if (fSkipped) + Bs3TestSkipped("skipped\n"); + } + Bs3TestSubDone(); +} + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-TestDoModesByOneStub.asm b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-TestDoModesByOneStub.asm new file mode 100644 index 00000000..ec30326a --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-TestDoModesByOneStub.asm @@ -0,0 +1,53 @@ +; $Id: bs3-mode-TestDoModesByOneStub.asm $ +;; @file +; BS3Kit - Bs3TestDoModesByOne near stub. +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + +;********************************************************************************************************************************* +;* Header Files * +;********************************************************************************************************************************* +%include "bs3kit-template-header.mac" + +; +; Near stub for the API call (16-bit only). +; +%if TMPL_BITS == 16 + %if TMPL_MODE == BS3_MODE_RM +BS3_BEGIN_RMTEXT16 + %endif +BS3_BEGIN_TEXT16_NEARSTUBS +BS3_PROC_BEGIN_MODE Bs3TestDoModesByOne, BS3_PBC_NEAR + pop ax + push cs + push ax + %if TMPL_MODE == BS3_MODE_RM + extern TMPL_FAR_NM(Bs3TestDoModesByOne):wrt BS3GROUPRMTEXT16 + jmp far TMPL_FAR_NM(Bs3TestDoModesByOne) + %else + extern TMPL_FAR_NM(Bs3TestDoModesByOne):wrt CGROUP16 + jmp TMPL_NM(Bs3TestDoModesByOne) + %endif +BS3_PROC_END_MODE Bs3TestDoModesByOne +%endif + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-TestDoModesHlp.asm b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-TestDoModesHlp.asm new file mode 100644 index 00000000..dbe82b18 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-TestDoModesHlp.asm @@ -0,0 +1,1129 @@ +; $Id: bs3-mode-TestDoModesHlp.asm $ +;; @file +; BS3Kit - Bs3TestDoModes helpers +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + +;********************************************************************************************************************************* +;* Header Files * +;********************************************************************************************************************************* +%include "bs3kit-template-header.mac" + + +;********************************************************************************************************************************* +;* Defined Constants And Macros * +;********************************************************************************************************************************* +; +; We put most of this mess in the RMTEXT16 segment when in real mode. +; +%if TMPL_MODE == BS3_MODE_RM + %define MY_BEGIN_TEXT BS3_BEGIN_RMTEXT16 + %define MY_BEGIN_TEXT16 BS3_BEGIN_RMTEXT16 + %define MY_TEXT16_WRT(a_Label) a_Label wrt BS3GROUPRMTEXT16 +%else + %define MY_BEGIN_TEXT TMPL_BEGIN_TEXT + %define MY_BEGIN_TEXT16 BS3_BEGIN_TEXT16 + %define MY_TEXT16_WRT(a_Label) BS3_TEXT16_WRT(a_Label) +%endif + + +;********************************************************************************************************************************* +;* External Symbols * +;********************************************************************************************************************************* +%if TMPL_MODE == BS3_MODE_RM +BS3_BEGIN_TEXT16_FARSTUBS +extern TMPL_FAR_NM(Bs3SwitchToRM) +extern TMPL_FAR_NM(Bs3SwitchToPE16) +extern TMPL_FAR_NM(Bs3SwitchToPE16_32) +extern TMPL_FAR_NM(Bs3SwitchToPE16_V86) +extern TMPL_FAR_NM(Bs3SwitchToPE32) +extern TMPL_FAR_NM(Bs3SwitchToPE32_16) +extern TMPL_FAR_NM(Bs3SwitchToPEV86) +extern TMPL_FAR_NM(Bs3SwitchToPP16) +extern TMPL_FAR_NM(Bs3SwitchToPP16_32) +extern TMPL_FAR_NM(Bs3SwitchToPP16_V86) +extern TMPL_FAR_NM(Bs3SwitchToPP32) +extern TMPL_FAR_NM(Bs3SwitchToPP32_16) +extern TMPL_FAR_NM(Bs3SwitchToPPV86) +extern TMPL_FAR_NM(Bs3SwitchToPAE16) +extern TMPL_FAR_NM(Bs3SwitchToPAE16_32) +extern TMPL_FAR_NM(Bs3SwitchToPAE16_V86) +extern TMPL_FAR_NM(Bs3SwitchToPAE32) +extern TMPL_FAR_NM(Bs3SwitchToPAE32_16) +extern TMPL_FAR_NM(Bs3SwitchToPAEV86) +extern TMPL_FAR_NM(Bs3SwitchToLM16) +extern TMPL_FAR_NM(Bs3SwitchToLM32) +extern TMPL_FAR_NM(Bs3SwitchToLM64) +extern RT_CONCAT3(_Bs3SwitchTo,TMPL_MODE_UNAME,_rm_far) +extern RT_CONCAT3(_Bs3SwitchTo,TMPL_MODE_UNAME,_pe16_far) +extern RT_CONCAT3(_Bs3SwitchTo,TMPL_MODE_UNAME,_pe16_v86_far) +extern RT_CONCAT3(_Bs3SwitchTo,TMPL_MODE_UNAME,_pe32_16_far) +extern RT_CONCAT3(_Bs3SwitchTo,TMPL_MODE_UNAME,_pev86_far) +extern RT_CONCAT3(_Bs3SwitchTo,TMPL_MODE_UNAME,_pp16_far) +extern RT_CONCAT3(_Bs3SwitchTo,TMPL_MODE_UNAME,_pp16_v86_far) +extern RT_CONCAT3(_Bs3SwitchTo,TMPL_MODE_UNAME,_pp32_16_far) +extern RT_CONCAT3(_Bs3SwitchTo,TMPL_MODE_UNAME,_ppv86_far) +extern RT_CONCAT3(_Bs3SwitchTo,TMPL_MODE_UNAME,_pae16_far) +extern RT_CONCAT3(_Bs3SwitchTo,TMPL_MODE_UNAME,_pae16_v86_far) +extern RT_CONCAT3(_Bs3SwitchTo,TMPL_MODE_UNAME,_pae32_16_far) +extern RT_CONCAT3(_Bs3SwitchTo,TMPL_MODE_UNAME,_paev86_far) +extern RT_CONCAT3(_Bs3SwitchTo,TMPL_MODE_UNAME,_lm16_far) +%else +BS3_BEGIN_TEXT16 +extern TMPL_NM(Bs3SwitchToRM) +extern TMPL_NM(Bs3SwitchToPE16) +extern TMPL_NM(Bs3SwitchToPE16_32) +extern TMPL_NM(Bs3SwitchToPE16_V86) +extern TMPL_NM(Bs3SwitchToPE32) +extern TMPL_NM(Bs3SwitchToPE32_16) +extern TMPL_NM(Bs3SwitchToPEV86) +extern TMPL_NM(Bs3SwitchToPP16) +extern TMPL_NM(Bs3SwitchToPP16_32) +extern TMPL_NM(Bs3SwitchToPP16_V86) +extern TMPL_NM(Bs3SwitchToPP32) +extern TMPL_NM(Bs3SwitchToPP32_16) +extern TMPL_NM(Bs3SwitchToPPV86) +extern TMPL_NM(Bs3SwitchToPAE16) +extern TMPL_NM(Bs3SwitchToPAE16_32) +extern TMPL_NM(Bs3SwitchToPAE16_V86) +extern TMPL_NM(Bs3SwitchToPAE32) +extern TMPL_NM(Bs3SwitchToPAE32_16) +extern TMPL_NM(Bs3SwitchToPAEV86) +extern TMPL_NM(Bs3SwitchToLM16) +extern TMPL_NM(Bs3SwitchToLM32) +extern TMPL_NM(Bs3SwitchToLM64) +extern RT_CONCAT3(_Bs3SwitchTo,TMPL_MODE_UNAME,_Safe_rm) +extern RT_CONCAT3(_Bs3SwitchTo,TMPL_MODE_UNAME,_Safe_pe16) +extern RT_CONCAT3(_Bs3SwitchTo,TMPL_MODE_UNAME,_Safe_pe16_v86) +extern RT_CONCAT3(_Bs3SwitchTo,TMPL_MODE_UNAME,_Safe_pe32_16) +extern RT_CONCAT3(_Bs3SwitchTo,TMPL_MODE_UNAME,_Safe_pev86) +extern RT_CONCAT3(_Bs3SwitchTo,TMPL_MODE_UNAME,_Safe_pp16) +extern RT_CONCAT3(_Bs3SwitchTo,TMPL_MODE_UNAME,_Safe_pp16_v86) +extern RT_CONCAT3(_Bs3SwitchTo,TMPL_MODE_UNAME,_Safe_pp32_16) +extern RT_CONCAT3(_Bs3SwitchTo,TMPL_MODE_UNAME,_Safe_ppv86) +extern RT_CONCAT3(_Bs3SwitchTo,TMPL_MODE_UNAME,_Safe_pae16) +extern RT_CONCAT3(_Bs3SwitchTo,TMPL_MODE_UNAME,_Safe_pae16_v86) +extern RT_CONCAT3(_Bs3SwitchTo,TMPL_MODE_UNAME,_Safe_pae32_16) +extern RT_CONCAT3(_Bs3SwitchTo,TMPL_MODE_UNAME,_Safe_paev86) +extern RT_CONCAT3(_Bs3SwitchTo,TMPL_MODE_UNAME,_Safe_lm16) +%endif +BS3_BEGIN_TEXT16 +extern RT_CONCAT3(_Bs3SwitchTo,TMPL_MODE_UNAME,_Safe_pe16_32):wrt BS3FLAT +extern RT_CONCAT3(_Bs3SwitchTo,TMPL_MODE_UNAME,_Safe_pe32):wrt BS3FLAT +extern RT_CONCAT3(_Bs3SwitchTo,TMPL_MODE_UNAME,_Safe_pp16_32):wrt BS3FLAT +extern RT_CONCAT3(_Bs3SwitchTo,TMPL_MODE_UNAME,_Safe_pp32):wrt BS3FLAT +extern RT_CONCAT3(_Bs3SwitchTo,TMPL_MODE_UNAME,_Safe_pae16_32):wrt BS3FLAT +extern RT_CONCAT3(_Bs3SwitchTo,TMPL_MODE_UNAME,_Safe_pae32):wrt BS3FLAT +extern RT_CONCAT3(_Bs3SwitchTo,TMPL_MODE_UNAME,_Safe_lm32):wrt BS3FLAT +extern RT_CONCAT3(_Bs3SwitchTo,TMPL_MODE_UNAME,_Safe_lm64):wrt BS3FLAT + + +MY_BEGIN_TEXT16 ; need the group definition +MY_BEGIN_TEXT + +;; +; Shared prologue code. +; @param xAX Where to jump to for the main event. +; +BS3_GLOBAL_NAME_EX TMPL_NM(bs3TestCallDoerPrologue), , 0 + BS3_CALL_CONV_PROLOG 1 + push xBP + mov xBP, xSP + xPUSHF + + ; Save non-volatile registers so the DO function doesn't have to. + push xBX + push xCX + push xDX + push xSI + push xDI +%if TMPL_BITS != 64 + push ds + push es + push ss + %if TMPL_BITS != 16 + push fs + push gs + %endif +%endif +%if TMPL_BITS == 64 + push r8 + push r9 + push r10 + push r11 + push r12 + push r13 + push r14 + push r15 +%endif + + ; Jump to the main code. + jmp xAX + +;; +; Shared epilogue code. +; @param xAX Return code. +; +BS3_GLOBAL_NAME_EX TMPL_NM(bs3TestCallDoerEpilogue), , 0 + ; Restore registers. +%if TMPL_BITS == 16 + sub bp, (1+5+3)*2 + mov sp, bp +%elif TMPL_BITS == 32 + lea xSP, [xBP - (1+5+5)*4] +%else + lea xSP, [xBP - (1+5+8)*8] + pop r15 + pop r14 + pop r13 + pop r12 + pop r11 + pop r10 + pop r9 + pop r8 +%endif +%if TMPL_BITS != 64 + %if TMPL_BITS != 16 + pop gs + pop fs + %endif + pop ss + pop es + pop ds +%endif + pop xDI + pop xSI + pop xDX + pop xCX + pop xBX + xPOPF + pop xBP + ret + +; +; For checking that the mode switching macros doesn't screw up GPRs. +; Note! Does not work on pre 286 hardware! So, for debugging only. +; +%if 0 + %macro STRICT_SAVE_REGS 0 + movzx esp, sp + sub esp, BS3REGCTX_size + mov [esp + BS3REGCTX.rax], eax + mov dword [esp + BS3REGCTX.rax+4], 0xdead0000 + mov [esp + BS3REGCTX.rcx], ecx + mov dword [esp + BS3REGCTX.rcx+4], 0xdead0001 + mov [esp + BS3REGCTX.rdx], edx + mov dword [esp + BS3REGCTX.rdx+4], 0xdead0002 + mov [esp + BS3REGCTX.rbx], ebx + mov dword [esp + BS3REGCTX.rbx+4], 0xdead0003 + mov [esp + BS3REGCTX.rbp], ebp + mov [esp + BS3REGCTX.rsp], esp + mov [esp + BS3REGCTX.rsi], esi + mov [esp + BS3REGCTX.rdi], edi + %endmacro + + %macro STRICT_CHECK_REGS 0 +%%_esp: cmp [esp + BS3REGCTX.rsp], esp + jne %%_esp +%%_eax: cmp [esp + BS3REGCTX.rax], eax + jne %%_eax +%%_ecx: mov [esp + BS3REGCTX.rcx], ecx + jne %%_ecx +%%_edx: cmp [esp + BS3REGCTX.rdx], edx + jne %%_edx +%%_ebx: cmp [esp + BS3REGCTX.rbx], ebx + jne %%_ebx +%%_ebp: cmp [esp + BS3REGCTX.rbp], ebp + jne %%_ebp +%%_esi: cmp [esp + BS3REGCTX.rsi], esi + jne %%_esi +%%_edi: cmp [esp + BS3REGCTX.rdi], edi + jne %%_edi + add esp, BS3REGCTX_size + %endmacro +%else + + %macro STRICT_SAVE_REGS 0 + %endmacro + %macro STRICT_CHECK_REGS 0 + %endmacro +%endif + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Real mode +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; +; @cproto BS3_DECL(uint8_t) Bs3TestCallDoerInRM(uint16_t offBs3Text16); +; @uses rax +BS3_PROC_BEGIN_MODE Bs3TestCallDoerInRM, BS3_PBC_NEAR + BS3_LEA_MOV_WRT_RIP(xAX, MY_TEXT16_WRT(.doit)) + jmp TMPL_NM(bs3TestCallDoerPrologue) +MY_BEGIN_TEXT16 +BS3_SET_BITS TMPL_BITS +BS3_GLOBAL_LOCAL_LABEL .doit + mov ax, [xBP + xCB + cbCurRetAddr] ; Load far function pointer. + mov dx, [xBP + xCB + cbCurRetAddr + 2] + + ; Mode switch, make the call, switch back. + STRICT_SAVE_REGS +%if TMPL_MODE == BS3_MODE_RM + call far TMPL_FAR_NM(Bs3SwitchToRM) +%else + call TMPL_NM(Bs3SwitchToRM) +%endif + BS3_SET_BITS 16 + STRICT_CHECK_REGS + + mov cx, BS3_MODE_RM + push cx + push cs + mov cx, .return + push cx + push dx + push ax + retf +.return: + + STRICT_SAVE_REGS +%if TMPL_MODE == BS3_MODE_RM + call far RT_CONCAT3(_Bs3SwitchTo,TMPL_MODE_UNAME,_rm_far) +%else + call RT_CONCAT3(_Bs3SwitchTo,TMPL_MODE_UNAME,_Safe_rm) +%endif + BS3_SET_BITS TMPL_BITS + STRICT_CHECK_REGS + jmp TMPL_NM(bs3TestCallDoerEpilogue) +MY_BEGIN_TEXT +BS3_PROC_END_MODE Bs3TestCallDoerInRM + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Unpage protection mode. +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; +; @cproto BS3_DECL(uint8_t) Bs3TestCallDoerInPE16(uint16_t offBs3Text16); +; @uses rax +BS3_PROC_BEGIN_MODE Bs3TestCallDoerInPE16, BS3_PBC_NEAR + BS3_LEA_MOV_WRT_RIP(xAX, MY_TEXT16_WRT(.doit)) + jmp TMPL_NM(bs3TestCallDoerPrologue) +MY_BEGIN_TEXT16 +BS3_SET_BITS TMPL_BITS +BS3_GLOBAL_LOCAL_LABEL .doit + mov ax, [xBP + xCB + cbCurRetAddr] ; Load far function pointer. + mov dx, [xBP + xCB + cbCurRetAddr + 2] + + ; Mode switch, make the call, switch back. + STRICT_SAVE_REGS +%if TMPL_MODE == BS3_MODE_RM + call far TMPL_FAR_NM(Bs3SwitchToPE16) +%else + call TMPL_NM(Bs3SwitchToPE16) +%endif + BS3_SET_BITS 16 + STRICT_CHECK_REGS + + push BS3_MODE_PE16 + push cs + push .return + push dx + push ax + retf +.return: + + STRICT_SAVE_REGS +%if TMPL_MODE == BS3_MODE_RM + call far RT_CONCAT3(_Bs3SwitchTo,TMPL_MODE_UNAME,_pe16_far) +%else + call RT_CONCAT3(_Bs3SwitchTo,TMPL_MODE_UNAME,_Safe_pe16) +%endif + BS3_SET_BITS TMPL_BITS + jmp TMPL_NM(bs3TestCallDoerEpilogue) +MY_BEGIN_TEXT +BS3_PROC_END_MODE Bs3TestCallDoerInPE16 + +;; +; @cproto BS3_DECL(uint8_t) Bs3TestCallDoerInPE16_32(uint32_t FlatWorkerAddr, uint8_t bMode); +; @uses rax +BS3_PROC_BEGIN_MODE Bs3TestCallDoerInPE16_32, BS3_PBC_NEAR + BS3_LEA_MOV_WRT_RIP(xAX, MY_TEXT16_WRT(.doit)) + jmp TMPL_NM(bs3TestCallDoerPrologue) +.doit: + mov eax, [xBP + xCB + cbCurRetAddr] ; Load function pointer. + movzx edx, byte [xBP + xCB + cbCurRetAddr + sCB] ; bMode + + ; Mode switch, make the call, switch back. + STRICT_SAVE_REGS +%if TMPL_MODE == BS3_MODE_RM + call far TMPL_FAR_NM(Bs3SwitchToPE16_32) +%else + call TMPL_NM(Bs3SwitchToPE16_32) +%endif + BS3_SET_BITS 32 + STRICT_CHECK_REGS + + push edx ; bMode + call eax + + STRICT_SAVE_REGS + call RT_CONCAT3(_Bs3SwitchTo,TMPL_MODE_UNAME,_Safe_pe16_32) + BS3_SET_BITS TMPL_BITS + STRICT_CHECK_REGS + jmp TMPL_NM(bs3TestCallDoerEpilogue) +BS3_PROC_END_MODE Bs3TestCallDoerInPE16_32 + +;; +; @cproto BS3_DECL(uint8_t) Bs3TestCallDoerInPE16_V86(uint16_t offBs3Text16); +; @uses rax +BS3_PROC_BEGIN_MODE Bs3TestCallDoerInPE16_V86, BS3_PBC_NEAR + BS3_LEA_MOV_WRT_RIP(xAX, MY_TEXT16_WRT(.doit)) + jmp TMPL_NM(bs3TestCallDoerPrologue) +MY_BEGIN_TEXT16 +BS3_SET_BITS TMPL_BITS +BS3_GLOBAL_LOCAL_LABEL .doit + mov ax, [xBP + xCB + cbCurRetAddr] ; Load far function pointer. + mov dx, [xBP + xCB + cbCurRetAddr + 2] + + ; Mode switch, make the call, switch back. + STRICT_SAVE_REGS +%if TMPL_MODE == BS3_MODE_RM + call far TMPL_FAR_NM(Bs3SwitchToPE16_V86) +%else + call TMPL_NM(Bs3SwitchToPE16_V86) +%endif + BS3_SET_BITS 16 + STRICT_CHECK_REGS + + push BS3_MODE_PE16_V86 + push cs + push .return + push dx + push ax + retf +.return: + + STRICT_SAVE_REGS +%if TMPL_MODE == BS3_MODE_RM + call far RT_CONCAT3(_Bs3SwitchTo,TMPL_MODE_UNAME,_pe16_v86_far) +%else + call RT_CONCAT3(_Bs3SwitchTo,TMPL_MODE_UNAME,_Safe_pe16_v86) +%endif + BS3_SET_BITS TMPL_BITS + STRICT_CHECK_REGS + jmp TMPL_NM(bs3TestCallDoerEpilogue) +MY_BEGIN_TEXT +BS3_PROC_END_MODE Bs3TestCallDoerInPE16_V86 + +;; +; @cproto BS3_DECL(uint8_t) Bs3TestCallDoerInPE32(uint32_t FlatWorkerAddr, uint8_t bMode); +; @uses rax +BS3_PROC_BEGIN_MODE Bs3TestCallDoerInPE32, BS3_PBC_NEAR + BS3_LEA_MOV_WRT_RIP(xAX, MY_TEXT16_WRT(.doit)) + jmp TMPL_NM(bs3TestCallDoerPrologue) +.doit: + mov eax, [xBP + xCB + cbCurRetAddr] ; Load function pointer. + movzx edx, byte [xBP + xCB + cbCurRetAddr + sCB] ; bMode + + ; Mode switch, make the call, switch back. + STRICT_SAVE_REGS +%if TMPL_MODE == BS3_MODE_RM + call far TMPL_FAR_NM(Bs3SwitchToPE32) +%else + call TMPL_NM(Bs3SwitchToPE32) +%endif + BS3_SET_BITS 32 + STRICT_CHECK_REGS + + push edx ; bMode + call eax + + STRICT_SAVE_REGS + call RT_CONCAT3(_Bs3SwitchTo,TMPL_MODE_UNAME,_Safe_pe32) + BS3_SET_BITS TMPL_BITS + STRICT_CHECK_REGS + jmp TMPL_NM(bs3TestCallDoerEpilogue) +BS3_PROC_END_MODE Bs3TestCallDoerInPE32 + +;; +; @cproto BS3_DECL(uint8_t) Bs3TestCallDoerInPE32_16(uint16_t offBs3Text16); +; @uses rax +BS3_PROC_BEGIN_MODE Bs3TestCallDoerInPE32_16, BS3_PBC_NEAR + BS3_LEA_MOV_WRT_RIP(xAX, MY_TEXT16_WRT(.doit)) + jmp TMPL_NM(bs3TestCallDoerPrologue) +MY_BEGIN_TEXT16 +BS3_SET_BITS TMPL_BITS +BS3_GLOBAL_LOCAL_LABEL .doit + mov ax, [xBP + xCB + cbCurRetAddr] ; Load far function pointer. + mov dx, [xBP + xCB + cbCurRetAddr + 2] + + ; Mode switch, make the call, switch back. + STRICT_SAVE_REGS +%if TMPL_MODE == BS3_MODE_RM + call far TMPL_FAR_NM(Bs3SwitchToPE32_16) +%else + call TMPL_NM(Bs3SwitchToPE32_16) +%endif + BS3_SET_BITS 16 + STRICT_CHECK_REGS + + push BS3_MODE_PE32_16 + push cs + push .return + push dx + push ax + retf +.return: + + STRICT_SAVE_REGS +%if TMPL_MODE == BS3_MODE_RM + call far RT_CONCAT3(_Bs3SwitchTo,TMPL_MODE_UNAME,_pe32_16_far) +%else + call RT_CONCAT3(_Bs3SwitchTo,TMPL_MODE_UNAME,_Safe_pe32_16) +%endif + BS3_SET_BITS TMPL_BITS + STRICT_CHECK_REGS + jmp TMPL_NM(bs3TestCallDoerEpilogue) +MY_BEGIN_TEXT +BS3_PROC_END_MODE Bs3TestCallDoerInPE32_16 + +;; +; @cproto BS3_DECL(uint8_t) Bs3TestCallDoerInPEV86(uint16_t offBs3Text16); +; @uses rax +BS3_PROC_BEGIN_MODE Bs3TestCallDoerInPEV86, BS3_PBC_NEAR + BS3_LEA_MOV_WRT_RIP(xAX, MY_TEXT16_WRT(.doit)) + jmp TMPL_NM(bs3TestCallDoerPrologue) +MY_BEGIN_TEXT16 +BS3_SET_BITS TMPL_BITS +BS3_GLOBAL_LOCAL_LABEL .doit + mov ax, [xBP + xCB + cbCurRetAddr] ; Load far function pointer. + mov dx, [xBP + xCB + cbCurRetAddr + 2] + + ; Mode switch, make the call, switch back. + STRICT_SAVE_REGS +%if TMPL_MODE == BS3_MODE_RM + call far TMPL_FAR_NM(Bs3SwitchToPEV86) +%else + call TMPL_NM(Bs3SwitchToPEV86) +%endif + BS3_SET_BITS 16 + STRICT_CHECK_REGS + + push BS3_MODE_PEV86 + push cs + push .return + push dx + push ax + retf +.return: + + STRICT_SAVE_REGS +%if TMPL_MODE == BS3_MODE_RM + call far RT_CONCAT3(_Bs3SwitchTo,TMPL_MODE_UNAME,_pev86_far) +%else + call RT_CONCAT3(_Bs3SwitchTo,TMPL_MODE_UNAME,_Safe_pev86) +%endif + BS3_SET_BITS TMPL_BITS + STRICT_CHECK_REGS + jmp TMPL_NM(bs3TestCallDoerEpilogue) +MY_BEGIN_TEXT +BS3_PROC_END_MODE Bs3TestCallDoerInPEV86 + + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Page protection mode. +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; +; @cproto BS3_DECL(uint8_t) Bs3TestCallDoerInPP16(uint16_t offBs3Text16); +; @uses rax +BS3_PROC_BEGIN_MODE Bs3TestCallDoerInPP16, BS3_PBC_NEAR + BS3_LEA_MOV_WRT_RIP(xAX, MY_TEXT16_WRT(.doit)) + jmp TMPL_NM(bs3TestCallDoerPrologue) +MY_BEGIN_TEXT16 +BS3_SET_BITS TMPL_BITS +BS3_GLOBAL_LOCAL_LABEL .doit + mov ax, [xBP + xCB + cbCurRetAddr] ; Load far function pointer. + mov dx, [xBP + xCB + cbCurRetAddr + 2] + + ; Mode switch, make the call, switch back. + STRICT_SAVE_REGS +%if TMPL_MODE == BS3_MODE_RM + call far TMPL_FAR_NM(Bs3SwitchToPP16) +%else + call TMPL_NM(Bs3SwitchToPP16) +%endif + BS3_SET_BITS 16 + STRICT_CHECK_REGS + + push BS3_MODE_PP16 + push cs + push .return + push dx + push ax + retf +.return: + + STRICT_SAVE_REGS +%if TMPL_MODE == BS3_MODE_RM + call far RT_CONCAT3(_Bs3SwitchTo,TMPL_MODE_UNAME,_pp16_far) +%else + call RT_CONCAT3(_Bs3SwitchTo,TMPL_MODE_UNAME,_Safe_pp16) +%endif + BS3_SET_BITS TMPL_BITS + STRICT_CHECK_REGS + jmp TMPL_NM(bs3TestCallDoerEpilogue) +MY_BEGIN_TEXT +BS3_PROC_END_MODE Bs3TestCallDoerInPP16 + +;; +; @cproto BS3_DECL(uint8_t) Bs3TestCallDoerInPP16_32(uint32_t uFlatWorkerAddr, uint8_t bMode); +; @uses rax +BS3_PROC_BEGIN_MODE Bs3TestCallDoerInPP16_32, BS3_PBC_NEAR + BS3_LEA_MOV_WRT_RIP(xAX, MY_TEXT16_WRT(.doit)) + jmp TMPL_NM(bs3TestCallDoerPrologue) +.doit: + mov eax, [xBP + xCB + cbCurRetAddr] ; Load function pointer. + movzx edx, byte [xBP + xCB + cbCurRetAddr + sCB] ; bMode + + ; Mode switch, make the call, switch back. + STRICT_SAVE_REGS +%if TMPL_MODE == BS3_MODE_RM + call far TMPL_FAR_NM(Bs3SwitchToPP16_32) +%else + call TMPL_NM(Bs3SwitchToPP16_32) +%endif + BS3_SET_BITS 32 + STRICT_CHECK_REGS + + push edx + call eax + + STRICT_SAVE_REGS + call RT_CONCAT3(_Bs3SwitchTo,TMPL_MODE_UNAME,_Safe_pp16_32) + BS3_SET_BITS TMPL_BITS + STRICT_CHECK_REGS + jmp TMPL_NM(bs3TestCallDoerEpilogue) +BS3_PROC_END_MODE Bs3TestCallDoerInPP16_32 + +;; +; @cproto BS3_DECL(uint8_t) Bs3TestCallDoerInPP16_V86(uint16_t offBs3Text16); +; @uses rax +BS3_PROC_BEGIN_MODE Bs3TestCallDoerInPP16_V86, BS3_PBC_NEAR + BS3_LEA_MOV_WRT_RIP(xAX, MY_TEXT16_WRT(.doit)) + jmp TMPL_NM(bs3TestCallDoerPrologue) +MY_BEGIN_TEXT16 +BS3_SET_BITS TMPL_BITS +BS3_GLOBAL_LOCAL_LABEL .doit + mov ax, [xBP + xCB + cbCurRetAddr] ; Load far function pointer. + mov dx, [xBP + xCB + cbCurRetAddr + 2] + + ; Mode switch, make the call, switch back. + STRICT_SAVE_REGS +%if TMPL_MODE == BS3_MODE_RM + call far TMPL_FAR_NM(Bs3SwitchToPP16_V86) +%else + call TMPL_NM(Bs3SwitchToPP16_V86) +%endif + BS3_SET_BITS 16 + STRICT_CHECK_REGS + + push BS3_MODE_PP16_V86 + push cs + push .return + push dx + push ax + retf +.return: + + STRICT_SAVE_REGS +%if TMPL_MODE == BS3_MODE_RM + call far RT_CONCAT3(_Bs3SwitchTo,TMPL_MODE_UNAME,_pp16_v86_far) +%else + call RT_CONCAT3(_Bs3SwitchTo,TMPL_MODE_UNAME,_Safe_pp16_v86) +%endif + BS3_SET_BITS TMPL_BITS + STRICT_CHECK_REGS + jmp TMPL_NM(bs3TestCallDoerEpilogue) +MY_BEGIN_TEXT +BS3_PROC_END_MODE Bs3TestCallDoerInPP16_V86 + +;; +; @cproto BS3_DECL(uint8_t) Bs3TestCallDoerInPP32(uint32_t uFlatWorkerAddr, uint8_t bMode); +; @uses rax +BS3_PROC_BEGIN_MODE Bs3TestCallDoerInPP32, BS3_PBC_NEAR + BS3_LEA_MOV_WRT_RIP(xAX, MY_TEXT16_WRT(.doit)) + jmp TMPL_NM(bs3TestCallDoerPrologue) +.doit: + mov eax, [xBP + xCB + cbCurRetAddr] ; Load function pointer. + movzx edx, byte [xBP + xCB + cbCurRetAddr + sCB] ; bMode + + ; Mode switch, make the call, switch back. + STRICT_SAVE_REGS +%if TMPL_MODE == BS3_MODE_RM + call far TMPL_FAR_NM(Bs3SwitchToPP32) +%else + call TMPL_NM(Bs3SwitchToPP32) +%endif + BS3_SET_BITS 32 + STRICT_CHECK_REGS + + push edx ; bMode + call eax + + STRICT_SAVE_REGS + call RT_CONCAT3(_Bs3SwitchTo,TMPL_MODE_UNAME,_Safe_pp32) + BS3_SET_BITS TMPL_BITS + STRICT_CHECK_REGS + jmp TMPL_NM(bs3TestCallDoerEpilogue) +BS3_PROC_END_MODE Bs3TestCallDoerInPP32 + +;; +; @cproto BS3_DECL(uint8_t) Bs3TestCallDoerInPP32_16(uint16_t offBs3Text16); +; @uses rax +BS3_PROC_BEGIN_MODE Bs3TestCallDoerInPP32_16, BS3_PBC_NEAR + BS3_LEA_MOV_WRT_RIP(xAX, MY_TEXT16_WRT(.doit)) + jmp TMPL_NM(bs3TestCallDoerPrologue) +MY_BEGIN_TEXT16 +BS3_SET_BITS TMPL_BITS +BS3_GLOBAL_LOCAL_LABEL .doit + mov ax, [xBP + xCB + cbCurRetAddr] ; Load far function pointer. + mov dx, [xBP + xCB + cbCurRetAddr + 2] + + ; Mode switch, make the call, switch back. + STRICT_SAVE_REGS +%if TMPL_MODE == BS3_MODE_RM + call far TMPL_FAR_NM(Bs3SwitchToPP32_16) +%else + call TMPL_NM(Bs3SwitchToPP32_16) +%endif + BS3_SET_BITS 16 + STRICT_CHECK_REGS + + push BS3_MODE_PP32_16 + push cs + push .return + push dx + push ax + retf +.return: + + STRICT_SAVE_REGS +%if TMPL_MODE == BS3_MODE_RM + call far RT_CONCAT3(_Bs3SwitchTo,TMPL_MODE_UNAME,_pp32_16_far) +%else + call RT_CONCAT3(_Bs3SwitchTo,TMPL_MODE_UNAME,_Safe_pp32_16) +%endif + BS3_SET_BITS TMPL_BITS + STRICT_CHECK_REGS + jmp TMPL_NM(bs3TestCallDoerEpilogue) +MY_BEGIN_TEXT +BS3_PROC_END_MODE Bs3TestCallDoerInPP32_16 + +;; +; @cproto BS3_DECL(uint8_t) Bs3TestCallDoerInPPV86(uint16_t offBs3Text16); +; @uses rax +BS3_PROC_BEGIN_MODE Bs3TestCallDoerInPPV86, BS3_PBC_NEAR + BS3_LEA_MOV_WRT_RIP(xAX, MY_TEXT16_WRT(.doit)) + jmp TMPL_NM(bs3TestCallDoerPrologue) +MY_BEGIN_TEXT16 +BS3_SET_BITS TMPL_BITS +BS3_GLOBAL_LOCAL_LABEL .doit + mov ax, [xBP + xCB + cbCurRetAddr] ; Load far function pointer. + mov dx, [xBP + xCB + cbCurRetAddr + 2] + + ; Mode switch, make the call, switch back. + STRICT_SAVE_REGS +%if TMPL_MODE == BS3_MODE_RM + call far TMPL_FAR_NM(Bs3SwitchToPPV86) +%else + call TMPL_NM(Bs3SwitchToPPV86) +%endif + BS3_SET_BITS 16 + STRICT_CHECK_REGS + + push BS3_MODE_PPV86 + push cs + push .return + push dx + push ax + retf +.return: + + STRICT_SAVE_REGS +%if TMPL_MODE == BS3_MODE_RM + call far RT_CONCAT3(_Bs3SwitchTo,TMPL_MODE_UNAME,_ppv86_far) +%else + call RT_CONCAT3(_Bs3SwitchTo,TMPL_MODE_UNAME,_Safe_ppv86) +%endif + BS3_SET_BITS TMPL_BITS + STRICT_CHECK_REGS + jmp TMPL_NM(bs3TestCallDoerEpilogue) +MY_BEGIN_TEXT +BS3_PROC_END_MODE Bs3TestCallDoerInPPV86 + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; PAE paged protection mode. +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; +; @cproto BS3_DECL(uint8_t) Bs3TestCallDoerInPAE16(uint16_t offBs3Text16); +; @uses rax +BS3_PROC_BEGIN_MODE Bs3TestCallDoerInPAE16, BS3_PBC_NEAR + BS3_LEA_MOV_WRT_RIP(xAX, MY_TEXT16_WRT(.doit)) + jmp TMPL_NM(bs3TestCallDoerPrologue) +MY_BEGIN_TEXT16 +BS3_SET_BITS TMPL_BITS +BS3_GLOBAL_LOCAL_LABEL .doit + mov ax, [xBP + xCB + cbCurRetAddr] ; Load far function pointer. + mov dx, [xBP + xCB + cbCurRetAddr + 2] + + ; Mode switch, make the call, switch back. + STRICT_SAVE_REGS +%if TMPL_MODE == BS3_MODE_RM + call far TMPL_FAR_NM(Bs3SwitchToPAE16) +%else + call TMPL_NM(Bs3SwitchToPAE16) +%endif + BS3_SET_BITS 16 + STRICT_CHECK_REGS + + push BS3_MODE_PAE16 + push cs + push .return + push dx + push ax + retf +.return: + + STRICT_SAVE_REGS +%if TMPL_MODE == BS3_MODE_RM + call far RT_CONCAT3(_Bs3SwitchTo,TMPL_MODE_UNAME,_pae16_far) +%else + call RT_CONCAT3(_Bs3SwitchTo,TMPL_MODE_UNAME,_Safe_pae16) +%endif + BS3_SET_BITS TMPL_BITS + STRICT_CHECK_REGS + jmp TMPL_NM(bs3TestCallDoerEpilogue) +MY_BEGIN_TEXT +BS3_PROC_END_MODE Bs3TestCallDoerInPAE16 + +;; +; @cproto BS3_DECL(uint8_t) Bs3TestCallDoerInPAE16_32(uint32_t uFlatWorkerAddr, uint8_t bMode); +; @uses rax +BS3_PROC_BEGIN_MODE Bs3TestCallDoerInPAE16_32, BS3_PBC_NEAR + BS3_LEA_MOV_WRT_RIP(xAX, MY_TEXT16_WRT(.doit)) + jmp TMPL_NM(bs3TestCallDoerPrologue) +.doit: + mov eax, [xBP + xCB + cbCurRetAddr] ; Load function pointer. + movzx edx, byte [xBP + xCB + cbCurRetAddr + sCB] ; bMode + + ; Mode switch, make the call, switch back. + STRICT_SAVE_REGS +%if TMPL_MODE == BS3_MODE_RM + call far TMPL_FAR_NM(Bs3SwitchToPAE16_32) +%else + call TMPL_NM(Bs3SwitchToPAE16_32) +%endif + BS3_SET_BITS 32 + STRICT_CHECK_REGS + + push edx ; bMode + call eax + + STRICT_SAVE_REGS + call RT_CONCAT3(_Bs3SwitchTo,TMPL_MODE_UNAME,_Safe_pae16_32) + BS3_SET_BITS TMPL_BITS + STRICT_CHECK_REGS + jmp TMPL_NM(bs3TestCallDoerEpilogue) +BS3_PROC_END_MODE Bs3TestCallDoerInPAE16_32 + +;; +; @cproto BS3_DECL(uint8_t) Bs3TestCallDoerInPAE16_V86(uint16_t offBs3Text16); +; @uses rax +BS3_PROC_BEGIN_MODE Bs3TestCallDoerInPAE16_V86, BS3_PBC_NEAR + BS3_LEA_MOV_WRT_RIP(xAX, MY_TEXT16_WRT(.doit)) + jmp TMPL_NM(bs3TestCallDoerPrologue) +MY_BEGIN_TEXT16 +BS3_SET_BITS TMPL_BITS +BS3_GLOBAL_LOCAL_LABEL .doit + mov ax, [xBP + xCB + cbCurRetAddr] ; Load far function pointer. + mov dx, [xBP + xCB + cbCurRetAddr + 2] + + ; Mode switch, make the call, switch back. + STRICT_SAVE_REGS +%if TMPL_MODE == BS3_MODE_RM + call far TMPL_FAR_NM(Bs3SwitchToPAE16_V86) +%else + call TMPL_NM(Bs3SwitchToPAE16_V86) +%endif + BS3_SET_BITS 16 + STRICT_CHECK_REGS + + push BS3_MODE_PAE16_V86 + push cs + push .return + push dx + push ax + retf +.return: + + STRICT_SAVE_REGS +%if TMPL_MODE == BS3_MODE_RM + call far RT_CONCAT3(_Bs3SwitchTo,TMPL_MODE_UNAME,_pae16_v86_far) +%else + call RT_CONCAT3(_Bs3SwitchTo,TMPL_MODE_UNAME,_Safe_pae16_v86) +%endif + BS3_SET_BITS TMPL_BITS + STRICT_CHECK_REGS + jmp TMPL_NM(bs3TestCallDoerEpilogue) +MY_BEGIN_TEXT +BS3_PROC_END_MODE Bs3TestCallDoerInPAE16_V86 + +;; +; @cproto BS3_DECL(uint8_t) Bs3TestCallDoerInPAE32(uint32_t uFlatWorkerAddr, uint8_t bMode); +; @uses rax +BS3_PROC_BEGIN_MODE Bs3TestCallDoerInPAE32, BS3_PBC_NEAR + BS3_LEA_MOV_WRT_RIP(xAX, MY_TEXT16_WRT(.doit)) + jmp TMPL_NM(bs3TestCallDoerPrologue) +.doit: + mov eax, [xBP + xCB + cbCurRetAddr] ; Load function pointer. + movzx edx, byte [xBP + xCB + cbCurRetAddr + sCB] ; bMode + + ; Mode switch, make the call, switch back. + STRICT_SAVE_REGS +%if TMPL_MODE == BS3_MODE_RM + call far TMPL_FAR_NM(Bs3SwitchToPAE32) +%else + call TMPL_NM(Bs3SwitchToPAE32) +%endif + BS3_SET_BITS 32 + STRICT_CHECK_REGS + + push edx ; bMode + call eax + + STRICT_SAVE_REGS + call RT_CONCAT3(_Bs3SwitchTo,TMPL_MODE_UNAME,_Safe_pae32) + BS3_SET_BITS TMPL_BITS + STRICT_CHECK_REGS + jmp TMPL_NM(bs3TestCallDoerEpilogue) +BS3_PROC_END_MODE Bs3TestCallDoerInPAE32 + +;; +; @cproto BS3_DECL(uint8_t) Bs3TestCallDoerInPAE32_16(uint16_t offBs3Text16); +; @uses rax +BS3_PROC_BEGIN_MODE Bs3TestCallDoerInPAE32_16, BS3_PBC_NEAR + BS3_LEA_MOV_WRT_RIP(xAX, MY_TEXT16_WRT(.doit)) + jmp TMPL_NM(bs3TestCallDoerPrologue) +MY_BEGIN_TEXT16 +BS3_SET_BITS TMPL_BITS +BS3_GLOBAL_LOCAL_LABEL .doit + mov ax, [xBP + xCB + cbCurRetAddr] ; Load far function pointer. + mov dx, [xBP + xCB + cbCurRetAddr + 2] + + ; Mode switch, make the call, switch back. + STRICT_SAVE_REGS +%if TMPL_MODE == BS3_MODE_RM + call far TMPL_FAR_NM(Bs3SwitchToPAE32_16) +%else + call TMPL_NM(Bs3SwitchToPAE32_16) +%endif + BS3_SET_BITS 16 + STRICT_CHECK_REGS + + push BS3_MODE_PAE32_16 + push cs + push .return + push dx + push ax + retf +.return: + + STRICT_SAVE_REGS +%if TMPL_MODE == BS3_MODE_RM + call far RT_CONCAT3(_Bs3SwitchTo,TMPL_MODE_UNAME,_pae32_16_far) +%else + call RT_CONCAT3(_Bs3SwitchTo,TMPL_MODE_UNAME,_Safe_pae32_16) +%endif + BS3_SET_BITS TMPL_BITS + STRICT_CHECK_REGS + jmp TMPL_NM(bs3TestCallDoerEpilogue) +MY_BEGIN_TEXT +BS3_PROC_END_MODE Bs3TestCallDoerInPAE32_16 + +;; +; @cproto BS3_DECL(uint8_t) Bs3TestCallDoerInPAEV86(uint16_t offBs3Text16); +; @uses rax +BS3_PROC_BEGIN_MODE Bs3TestCallDoerInPAEV86, BS3_PBC_NEAR + BS3_LEA_MOV_WRT_RIP(xAX, MY_TEXT16_WRT(.doit)) + jmp TMPL_NM(bs3TestCallDoerPrologue) +MY_BEGIN_TEXT16 +BS3_SET_BITS TMPL_BITS +BS3_GLOBAL_LOCAL_LABEL .doit + mov ax, [xBP + xCB + cbCurRetAddr] ; Load far function pointer. + mov dx, [xBP + xCB + cbCurRetAddr + 2] + + ; Mode switch, make the call, switch back. + STRICT_SAVE_REGS +%if TMPL_MODE == BS3_MODE_RM + call far TMPL_FAR_NM(Bs3SwitchToPAEV86) +%else + call TMPL_NM(Bs3SwitchToPAEV86) +%endif + BS3_SET_BITS 16 + STRICT_CHECK_REGS + + push BS3_MODE_PAEV86 + push cs + push .return + push dx + push ax + retf +.return: + + STRICT_SAVE_REGS +%if TMPL_MODE == BS3_MODE_RM + call far RT_CONCAT3(_Bs3SwitchTo,TMPL_MODE_UNAME,_paev86_far) +%else + call RT_CONCAT3(_Bs3SwitchTo,TMPL_MODE_UNAME,_Safe_paev86) +%endif + BS3_SET_BITS TMPL_BITS + STRICT_CHECK_REGS + jmp TMPL_NM(bs3TestCallDoerEpilogue) +MY_BEGIN_TEXT +BS3_PROC_END_MODE Bs3TestCallDoerInPAEV86 + + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Long mode +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; +; @cproto BS3_DECL(uint8_t) Bs3TestCallDoerInLM16(uint16_t offBs3Text16); +; @uses rax +BS3_PROC_BEGIN_MODE Bs3TestCallDoerInLM16, BS3_PBC_NEAR + BS3_LEA_MOV_WRT_RIP(xAX, MY_TEXT16_WRT(.doit)) + jmp TMPL_NM(bs3TestCallDoerPrologue) +MY_BEGIN_TEXT16 +BS3_SET_BITS TMPL_BITS +BS3_GLOBAL_LOCAL_LABEL .doit + mov ax, [xBP + xCB + cbCurRetAddr] ; Load far function pointer. + mov dx, [xBP + xCB + cbCurRetAddr + 2] + + ; Mode switch, make the call, switch back. + STRICT_SAVE_REGS +%if TMPL_MODE == BS3_MODE_RM + call far TMPL_FAR_NM(Bs3SwitchToLM16) +%else + call TMPL_NM(Bs3SwitchToLM16) +%endif + BS3_SET_BITS 16 + STRICT_CHECK_REGS + + push BS3_MODE_LM16 + push cs + push .return + push dx + push ax + retf +.return: + + STRICT_SAVE_REGS +%if TMPL_MODE == BS3_MODE_RM + call far RT_CONCAT3(_Bs3SwitchTo,TMPL_MODE_UNAME,_lm16_far) +%else + call RT_CONCAT3(_Bs3SwitchTo,TMPL_MODE_UNAME,_Safe_lm16) +%endif + BS3_SET_BITS TMPL_BITS + STRICT_CHECK_REGS + jmp TMPL_NM(bs3TestCallDoerEpilogue) +MY_BEGIN_TEXT +BS3_PROC_END_MODE Bs3TestCallDoerInLM16 + +;; +; @cproto BS3_DECL(uint8_t) Bs3TestCallDoerInLM32(uint16_t offBs3Text16); +; @uses rax +BS3_PROC_BEGIN_MODE Bs3TestCallDoerInLM32, BS3_PBC_NEAR + BS3_LEA_MOV_WRT_RIP(xAX, MY_TEXT16_WRT(.doit)) + jmp TMPL_NM(bs3TestCallDoerPrologue) +.doit: + mov eax, [xBP + xCB + cbCurRetAddr] ; Load function pointer. + + ; Mode switch, make the call, switch back. + STRICT_SAVE_REGS +%if TMPL_MODE == BS3_MODE_RM + call far TMPL_FAR_NM(Bs3SwitchToLM32) +%else + call TMPL_NM(Bs3SwitchToLM32) +%endif + BS3_SET_BITS 32 + STRICT_CHECK_REGS + + and esp, ~03h + push BS3_MODE_LM32 + call eax + + STRICT_SAVE_REGS + call RT_CONCAT3(_Bs3SwitchTo,TMPL_MODE_UNAME,_Safe_lm32) + BS3_SET_BITS TMPL_BITS + STRICT_CHECK_REGS + jmp TMPL_NM(bs3TestCallDoerEpilogue) +BS3_PROC_END_MODE Bs3TestCallDoerInLM32 + +;; +; @cproto BS3_DECL(uint8_t) Bs3TestCallDoerInLM64(uint32_t uFlatWorkerAddr, uint8_t bMode); +; @uses rax +BS3_PROC_BEGIN_MODE Bs3TestCallDoerInLM64, BS3_PBC_NEAR + BS3_LEA_MOV_WRT_RIP(xAX, MY_TEXT16_WRT(.doit)) + jmp TMPL_NM(bs3TestCallDoerPrologue) +.doit: + mov eax, [xBP + xCB + cbCurRetAddr] ; Load function pointer. + movzx edx, byte [xBP + xCB + cbCurRetAddr + sCB] ; bMode + + ; Mode switch, make the call, switch back. + STRICT_SAVE_REGS +%if TMPL_MODE == BS3_MODE_RM + call far TMPL_FAR_NM(Bs3SwitchToLM64) +%else + call TMPL_NM(Bs3SwitchToLM64) +%endif + BS3_SET_BITS 64 + STRICT_CHECK_REGS + + and rsp, ~0fh + sub rsp, 18h + push rdx ; bMode + BS3_CALL rax, 1 + + STRICT_SAVE_REGS + call RT_CONCAT3(_Bs3SwitchTo,TMPL_MODE_UNAME,_Safe_lm64) + BS3_SET_BITS TMPL_BITS + STRICT_CHECK_REGS + jmp TMPL_NM(bs3TestCallDoerEpilogue) +BS3_PROC_END_MODE Bs3TestCallDoerInLM64 + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-TestDoModesStub.asm b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-TestDoModesStub.asm new file mode 100644 index 00000000..ce4ca134 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-TestDoModesStub.asm @@ -0,0 +1,53 @@ +; $Id: bs3-mode-TestDoModesStub.asm $ +;; @file +; BS3Kit - Bs3TestDoModes near stub. +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + +;********************************************************************************************************************************* +;* Header Files * +;********************************************************************************************************************************* +%include "bs3kit-template-header.mac" + +; +; Near stub for the API call (16-bit only). +; +%if TMPL_BITS == 16 + %if TMPL_MODE == BS3_MODE_RM +BS3_BEGIN_RMTEXT16 + %endif +BS3_BEGIN_TEXT16_NEARSTUBS +BS3_PROC_BEGIN_MODE Bs3TestDoModes, BS3_PBC_NEAR + pop ax + push cs + push ax + %if TMPL_MODE == BS3_MODE_RM + extern TMPL_FAR_NM(Bs3TestDoModes):wrt BS3GROUPRMTEXT16 + jmp far TMPL_FAR_NM(Bs3TestDoModes) + %else + extern TMPL_FAR_NM(Bs3TestDoModes):wrt CGROUP16 + jmp TMPL_NM(Bs3TestDoModes) + %endif +BS3_PROC_END_MODE Bs3TestDoModes +%endif + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-TrapInit.c b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-TrapInit.c new file mode 100644 index 00000000..cde27b34 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-TrapInit.c @@ -0,0 +1,51 @@ +/* $Id: bs3-mode-TrapInit.c $ */ +/** @file + * BS3Kit - Bs3TrapInit + */ + +/* + * Copyright (C) 2007-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include "bs3kit-template-header.h" + + +#undef Bs3TrapInit +BS3_MODE_DEF(void, Bs3TrapInit,(void)) +{ +#if BS3_MODE_IS_RM_SYS(TMPL_MODE) + Bs3TrapRmV86Init(); +#elif BS3_MODE_IS_16BIT_SYS(TMPL_MODE) + Bs3TrapRmV86Init(); + Bs3Trap16Init(); +#elif BS3_MODE_IS_32BIT_SYS(TMPL_MODE) + Bs3TrapRmV86Init(); + Bs3Trap32Init(); +#elif BS3_MODE_IS_64BIT_SYS(TMPL_MODE) + Bs3Trap64Init(); +#else +# error "TMPL_MODE" +#endif +} + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-TrapSystemCallHandler.asm b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-TrapSystemCallHandler.asm new file mode 100644 index 00000000..c3b06fe9 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-TrapSystemCallHandler.asm @@ -0,0 +1,879 @@ +; $Id: bs3-mode-TrapSystemCallHandler.asm $ +;; @file +; BS3Kit - System call trap handler. +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + +;********************************************************************************************************************************* +;* Header Files * +;********************************************************************************************************************************* +%include "bs3kit-template-header.mac" + + +;********************************************************************************************************************************* +;* External Symbols * +;********************************************************************************************************************************* +BS3_EXTERN_DATA16 g_bBs3CurrentMode +%if TMPL_BITS != 64 +BS3_EXTERN_DATA16 g_uBs3CpuDetected +%endif +%if TMPL_BITS == 16 +BS3_EXTERN_DATA16 g_uBs3TrapEipHint +%endif +TMPL_BEGIN_TEXT + +BS3_EXTERN_CMN Bs3SelProtFar32ToFlat32 +BS3_EXTERN_CMN Bs3RegCtxConvertToRingX +BS3_EXTERN_CMN Bs3RegCtxRestore +BS3_EXTERN_CMN Bs3Panic + +BS3_BEGIN_TEXT16 +extern Bs3PrintStrN_c16_CX_Bytes_At_DS_SI +TMPL_BEGIN_TEXT + + +;; +; System call handler. +; +; This is an assembly trap handler that is called in response to a system call +; request from 'user' code. The only fixed parameter is [ER]AX which contains +; the system call number. Other registers are assigned on a per system call +; basis, ditto for which registers are preserved and which are used to return +; stuff. Generally, though, we preserve all registers not used as return +; values or otherwise implicitly transformed by the call. +; +; Note! The 16-bit versions of this code must be careful with using extended +; registers as we wish this code to work on real 80286 (maybe even 8086) +; CPUs too! +; +BS3_PROC_BEGIN_MODE Bs3TrapSystemCallHandler, BS3_PBC_NEAR ; Near because we'll probably only ever need this from CGROUP16. + ; + ; This prologue is kind of complicated because of 80286 and older CPUs + ; as well as different requirements for 64-bit and the other modes. + ; +%define VAR_CALLER_BP [xBP] +%if TMPL_BITS != 64 + %define VAR_CALLER_DS [xBP - xCB] +%endif +%define VAR_CALLER_BX [xBP - sCB*1 - xCB] ; Note! the upper word is not clean on pre-386 (16-bit mode). +%define VAR_CALLER_AX [xBP - sCB*2 - xCB] +%define VAR_CALLER_CX [xBP - sCB*3 - xCB] +%define VAR_CALLER_DX [xBP - sCB*4 - xCB] +%define VAR_CALLER_SI [xBP - sCB*5 - xCB] +%define VAR_CALLER_SI_HI [xBP - sCB*5 - xCB + 2] +%define VAR_CALLER_DI [xBP - sCB*6 - xCB] +%define VAR_CALLER_DI_HI [xBP - sCB*6 - xCB + 2] +%if TMPL_BITS == 16 + %define VAR_CALLER_EBP [xBP - sCB*7 - xCB] + %define VAR_CALLER_ESP [xBP - sCB*8 - xCB] + %define VAR_CALLER_EFLAGS [xBP - sCB*9 - xCB] + %define VAR_CALLER_MODE [xBP - sCB*9 - xCB*2] + %define BP_TOP_STACK_EXPR xBP - sCB*9 - xCB*2 +%else + %define VAR_CALLER_MODE [xBP - sCB*6 - xCB*2] + %define BP_TOP_STACK_EXPR xBP - sCB*6 - xCB*2 +%endif + push xBP + mov xBP, xSP +%if TMPL_BITS == 64 + push 0 + mov [rsp+2], es + mov [rsp], ds +%else + push ds + %ifdef TMPL_CMN_R86 + push BS3_SEL_DATA16 + %else + push RT_CONCAT(BS3_SEL_R0_DS,TMPL_BITS) + %endif + pop ds ; DS = BS3KIT_GRPNM_DATA16 or FLAT and we can safely access data + %if TMPL_BITS == 16 && (TMPL_MODE == BS3_MODE_RM || TMPL_MODE == BS3_MODE_PE16) + cmp byte [BS3_DATA16_WRT(g_uBs3CpuDetected)], BS3CPU_80286 + jbe .prologue_pre_80386 + %endif +%endif + push sBX + push sAX + push sCX + push sDX + push sSI + push sDI +%if TMPL_BITS == 16 + push ebp + push esp + pushfd + %if TMPL_MODE == BS3_MODE_RM || TMPL_MODE == BS3_MODE_PE16 + jmp .prologue_end + +.prologue_pre_80386: + push bx ; dummy + push bx + xor bx, bx + push bx ; dummy + push ax + push bx ; dummy + push cx + push bx ; dummy + push dx + push bx ; dummy + push si + push bx ; dummy + push di + sub sp, 0ch ; dummy + %endif +%endif +.prologue_end: + + ; + ; VAR_CALLER_MODE: Save the current mode (important for v8086 with 16-bit kernel). + ; + xor xBX, xBX + mov bl, [BS3_DATA16_WRT(g_bBs3CurrentMode)] + push xBX + + ; + ; Dispatch the system call. + ; + cmp ax, BS3_SYSCALL_LAST + ja .invalid_syscall +%if TMPL_BITS == 16 + mov bx, ax + shl bx, 1 + jmp word [cs:.aoffSyscallHandlers + bx] +%else + movzx ebx, ax + mov ebx, [.aoffSyscallHandlers + ebx * 4] + jmp xBX +%endif +.aoffSyscallHandlers: +%ifdef TMPL_16BIT + dw .invalid_syscall wrt CGROUP16 + dw .print_chr wrt CGROUP16 + dw .print_str wrt CGROUP16 + dw .to_ringX wrt CGROUP16 + dw .to_ringX wrt CGROUP16 + dw .to_ringX wrt CGROUP16 + dw .to_ringX wrt CGROUP16 + dw .restore_ctx wrt CGROUP16 +%else + dd .invalid_syscall wrt FLAT + dd .print_chr wrt FLAT + dd .print_str wrt FLAT + dd .to_ringX wrt FLAT + dd .to_ringX wrt FLAT + dd .to_ringX wrt FLAT + dd .to_ringX wrt FLAT + dd .restore_ctx wrt FLAT +%endif + + ; + ; Invalid system call. + ; +.invalid_syscall: + int3 + jmp .return + + ; + ; Print char in the CL register. + ; + ; We use the vga bios teletype interrupt to do the writing, so we must + ; be in some kind of real mode for this to work. 16-bit code segment + ; requried for the mode switching code. + ; +BS3_BEGIN_TEXT16 + BS3_SET_BITS TMPL_BITS +.print_chr: +%if TMPL_BITS != 64 + push es + mov di, ss ; Must save and restore SS for supporting 16/32 and 32/16 caller/kernel ring-0 combinations. +%endif +%ifndef TMPL_CMN_R86 + ; Switch to real mode (20h param scratch area not required). + extern TMPL_NM(Bs3SwitchToRM) + call TMPL_NM(Bs3SwitchToRM) + BS3_SET_BITS 16 +%endif + + ; Print the character, turning '\n' into '\r\n'. + cmp cl, 0ah ; \n + je .print_chr_newline + mov ah, 0eh + mov al, cl + mov bx, 0ff00h + int 10h + jmp .print_chr_done + +.print_chr_newline: + mov ax, 0e0dh ; cmd + \r + mov bx, 0ff00h + int 10h + mov ax, 0e0ah ; cmd + \n + mov bx, 0ff00h + int 10h + +.print_chr_done: +%ifndef TMPL_CMN_R86 + ; Switch back (20h param scratch area not required). + extern RT_CONCAT3(_Bs3SwitchTo,TMPL_MODE_UNAME,_rm) + call RT_CONCAT3(_Bs3SwitchTo,TMPL_MODE_UNAME,_rm) + BS3_SET_BITS TMPL_BITS +%endif +%if TMPL_BITS != 64 + mov ss, di + pop es +%endif + jmp .return +TMPL_BEGIN_TEXT + + + ; + ; Prints DX chars from the string pointed to by CX:xSI to the screen. + ; + ; We use the vga bios teletype interrupt to do the writing, so we must + ; be in some kind of real mode for this to work. The string must be + ; accessible from real mode too. + ; +.print_str: +%if TMPL_BITS != 64 + push es +%endif + ; Convert the incoming pointer to real mode (assuming caller checked + ; that real mode can access it). + call .convert_ptr_arg_to_real_mode_ax_si + mov cx, VAR_CALLER_DX + + ; Switch to real mode (no 20h scratch required) +%ifndef TMPL_CMN_R86 + %if TMPL_BITS != 16 + jmp .print_str_to_16bit +BS3_BEGIN_TEXT16 +.print_str_to_16bit: + BS3_SET_BITS TMPL_BITS + %endif + extern TMPL_NM(Bs3SwitchToRM) + call TMPL_NM(Bs3SwitchToRM) + BS3_SET_BITS 16 +%endif + ; Call code in Bs3PrintStrN to do the work. + mov ds, ax + call Bs3PrintStrN_c16_CX_Bytes_At_DS_SI + + ; Switch back (20h param scratch area not required). +%ifndef TMPL_CMN_R86 + extern RT_CONCAT3(_Bs3SwitchTo,TMPL_MODE_UNAME,_rm) + call RT_CONCAT3(_Bs3SwitchTo,TMPL_MODE_UNAME,_rm) + %if TMPL_BITS != 16 + BS3_SET_BITS TMPL_BITS + jmp .print_str_end +TMPL_BEGIN_TEXT + %endif +.print_str_end: +%endif +%if TMPL_BITS != 64 + pop es +%endif + jmp .return + + + ; + ; Switch the caller to ring-0, ring-1, ring-2 or ring-3. + ; + ; This implement this by saving the entire register context, calling + ; a transformation function (C) and restoring the modified register + ; context using a generic worker. + ; +.to_ringX: + sub xSP, BS3REGCTX_size + mov xBX, xSP ; xBP = BS3REGCTX pointer. + call .save_context + +%if TMPL_BITS == 32 + ; Convert xBP to flat pointer in 32-bit + push ss + push xBX + call Bs3SelProtFar32ToFlat32 + add sSP, 8 + mov xBX, xAX +%endif + push xBX ; Save pointer for the final restore call. + + ; Convert the register context from whatever it is to ring-0. +BONLY64 sub rsp, 10h + mov ax, VAR_CALLER_AX + sub ax, BS3_SYSCALL_TO_RING0 + push xAX +BONLY16 push ss + push xBX + BS3_CALL Bs3RegCtxConvertToRingX, 2 + add xSP, sCB + xCB BS3_ONLY_64BIT(+ 10h) + + ; Restore the register context (does not return). + pop xBX ; restore saved pointer. +BONLY64 sub rsp, 18h +BONLY16 push ss + push xBX + BS3_CALL Bs3RegCtxRestore, 1 + jmp Bs3Panic + + + ; + ; Restore context pointed to by cx:xSI. + ; +.restore_ctx: + call .convert_ptr_arg_to_cx_xSI +BONLY64 sub rsp, 10h + mov xDX, VAR_CALLER_DX + push xDX +BONLY16 push cx + push xSI + BS3_CALL Bs3RegCtxRestore, 2 + jmp Bs3Panic + + ; + ; Return. + ; +.return: + pop xBX ; saved mode + mov [BS3_DATA16_WRT(g_bBs3CurrentMode)], bl +%if TMPL_BITS == 16 + and bl, BS3_MODE_CODE_MASK + cmp bl, BS3_MODE_CODE_V86 + je .return_to_v8086_from_16bit_krnl + cmp bl, BS3_MODE_CODE_32 + je .return_to_32bit_from_16bit_krnl + %if TMPL_MODE == BS3_MODE_RM || TMPL_MODE == BS3_MODE_PE16 + cmp byte [BS3_DATA16_WRT(g_uBs3CpuDetected)], BS3CPU_80286 + jbe .return_pre_80386 + %endif + + popfd + pop esp + pop ebp +%endif + pop sDI + pop sSI + pop sDX + pop sCX + pop sAX + pop sBX +%if TMPL_BITS != 64 + pop ds + leave + iret +%else + mov es, [rsp+2] + mov ds, [rsp] + leave ; skips ds + iretq +%endif + +%if TMPL_BITS == 16 + %if TMPL_MODE == BS3_MODE_RM || TMPL_MODE == BS3_MODE_PE16 + ; Variant of the above for 80286 and older. +.return_pre_80386: + add sp, 0ch + pop di + pop bx ; dummy + pop si + pop bx ; dummy + pop dx + pop bx ; dummy + pop cx + pop bx ; dummy + pop ax + pop bx ; dummy + pop bx ; pushed twice + pop bx + pop ds + pop bp + iret + %endif + +.return_to_v8086_from_16bit_krnl: + int3 + jmp .return_to_v8086_from_16bit_krnl + + ; + ; Returning to 32-bit code may require us to expand and seed the eip + ; and esp addresses in the iret frame since these are truncated when + ; using a 16-bit interrupt handler. + ; + ; Incoming stack: New stack diff cpl: + ; bp + 0ah: [ss] + ; bp + 08h: [sp] bx + 38h: [ss] New stack same cpl: + ; bp + 06h: flags + ; bp + 04h: cs bx + 34h: [esp] bx + 30h: eflags + ; bp + 02h: ip + ; -------------- bx + 30h: eflags bx + 2ch: cs + ; bp + 00h: bp + ; bp - 02h: ds bx + 2ch: cs bx + 28h: eip + ; ------------- + ; bp - 06h: ebx bx + 28h: eip bx + 26h: bp + ; -------------- bx + 24h: ds + ; bp - 0ah: eax bx + 26h: bp + ; bx + 24h: ds bx + 20h: ebx + ; bp - 0eh: ecx + ; bx + 20h: ebx bx + 1ch: eax + ; bp - 12h: edx + ; bx + 1ch: eax bx + 18h: ecx + ; bp - 16h: esi + ; bx + 18h: ecx bx + 14h: edx + ; bp - 1ah: edi + ; bx + 14h: edx bx + 10h: esi + ; bp - 1eh: esp + ; bx + 10h: esi bx + 0ch: edi + ; bp - 22h: ebp + ; bx + 0ch: edi bx + 08h: esp + ; bp - 26h: eflags + ; bx + 08h: esp bx + 04h: ebp + ; + ; bx + 04h: ebp bx + 00h: eflags + ; + ; bx + 00h: eflags + ; + ; + ; If we're returning to the same CPL, we're still using the stack of + ; the 32-bit caller. The high ESP word does not need restoring. + ; + ; If we're returning to a lower CPL, there on a 16-bit ring-0 stack, + ; however, the high ESP word is still that of the caller. + ; +.return_to_32bit_from_16bit_krnl: + mov ax, cs + and al, 3 + mov ah, 3 + and ah, [xBP + xCB*2] + ; The iret frame doubles in size, so allocate more stack. + cmp al, ah + je .return_to_32bit_from_16bit_krnl_same_cpl_sub_sp + sub sp, 2*2 +.return_to_32bit_from_16bit_krnl_same_cpl_sub_sp: + sub sp, 3*2 + mov bx, sp + ; Copy the saved registers. + xor di, di +.return_to_32bit_from_16bit_krnl_copy_loop: + mov ecx, [bp + di - 26h] + mov [ss:bx + di], ecx + add di, 4 + cmp di, 28h + jb .return_to_32bit_from_16bit_krnl_copy_loop + ; Convert the 16-bit iret frame to a 32-bit iret frame. + mov ecx, [BS3_DATA16_WRT(g_uBs3TrapEipHint)] + mov cx, [bp + 02h] ; ip + mov [ss:bx + 28h], ecx + mov ecx, 0f00d0000h + mov cx, [bp + 04h] ; cs + mov [ss:bx + 2ch], ecx + mov ecx, [ss:bx] ; caller eflags + mov cx, [bp + 06h] ; flags + mov [ss:bx + 30h], ecx + cmp al, ah + jz .return_to_32bit_from_16bit_krnl_do_return + mov ecx, [ss:bx + 08h] ; caller esp + mov cx, [bp + 08h] ; sp + mov [ss:bx + 34h], ecx + mov ecx, 0f00d0000h + mov cx, [bp + 0ah] ; ss + mov [ss:bx + 38h], ecx +.return_to_32bit_from_16bit_krnl_do_return: + popfd + pop ecx ; esp - only the high bits! + mov cx, sp + mov esp, ecx + pop ebp + lea bp, [bx + 26h] + pop edi + pop esi + pop edx + pop ecx + pop eax + pop ebx + pop ds + leave + iretd + +%endif ; 16-bit + + + ; + ; Internal function. ss:xBX = Pointer to register frame (BS3REGCTX). + ; @uses xAX + ; +.save_context: +%if TMPL_BITS == 16 + cmp byte [BS3_DATA16_WRT(g_uBs3CpuDetected)], BS3CPU_80386 + jae .save_context_full + + ; + ; 80286 or earlier. + ; + + ; Clear the state area first. + push di + xor di, di +.save_context_16_clear_loop: + mov word [ss:bx + di], 0 + mov word [ss:bx + di + 2], 0 + mov word [ss:bx + di + 4], 0 + mov word [ss:bx + di + 6], 0 + add di, 8 + cmp di, BS3REGCTX_size + jb .save_context_16_clear_loop + pop di + + ; Do the 8086/80186/80286 state saving. + mov ax, VAR_CALLER_AX + mov [ss:bx + BS3REGCTX.rax], ax + mov cx, VAR_CALLER_CX + mov [ss:bx + BS3REGCTX.rcx], ax + mov ax, VAR_CALLER_DX + mov [ss:bx + BS3REGCTX.rdx], ax + mov ax, VAR_CALLER_BX + mov [ss:bx + BS3REGCTX.rbx], ax + mov [ss:bx + BS3REGCTX.rsi], si + mov [ss:bx + BS3REGCTX.rdi], di + mov ax, VAR_CALLER_BP + mov [ss:bx + BS3REGCTX.rbp], ax + mov ax, VAR_CALLER_DS + mov [ss:bx + BS3REGCTX.ds], ax + mov [ss:bx + BS3REGCTX.es], es + mov ax, [xBP + xCB] + mov [ss:bx + BS3REGCTX.rip], ax + mov ax, [xBP + xCB*2] + mov [ss:bx + BS3REGCTX.cs], ax + and al, X86_SEL_RPL + mov [ss:bx + BS3REGCTX.bCpl], al + cmp al, 0 + je .save_context_16_same + mov ax, [xBP + xCB*4] + mov [ss:bx + BS3REGCTX.rsp], ax + mov ax, [xBP + xCB*5] + mov [ss:bx + BS3REGCTX.ss], ax + jmp .save_context_16_done_stack +.save_context_16_same: + mov ax, bp + add ax, xCB * (1 + 3) + mov [ss:bx + BS3REGCTX.rsp], ax + mov ax, ss + mov [ss:bx + BS3REGCTX.ss], ax +.save_context_16_done_stack: + mov ax, [xBP + xCB*3] + mov [ss:bx + BS3REGCTX.rflags], ax + mov al, VAR_CALLER_MODE + mov [ss:bx + BS3REGCTX.bMode], al + cmp byte [BS3_DATA16_WRT(g_uBs3CpuDetected)], BS3CPU_80286 + jne .save_context_16_return + smsw [ss:bx + BS3REGCTX.cr0] + str [ss:bx + BS3REGCTX.tr] + sldt [ss:bx + BS3REGCTX.ldtr] +.save_context_16_return: + or byte [ss:bx + BS3REGCTX.fbFlags], BS3REG_CTX_F_NO_AMD64 | BS3REG_CTX_F_NO_CR4 + ret +%endif ; TMPL_BITS == 16 + + ; + ; 80386 or later. + ; +.save_context_full: + + ; Clear the state area. + push xDI + xor xDI, xDI + AssertCompileSizeAlignment(BS3REGCTX, 16) +.save_context_full_clear_loop: +%if TMPL_BITS != 64 + mov dword [ss:xBX + xDI], 0 + mov dword [ss:xBX + xDI + 4], 0 + add xDI, 8 +%else + mov qword [xBX + xDI], 0 + mov qword [xBX + xDI + 8], 0 + add xDI, 10h +%endif + cmp xDI, BS3REGCTX_size + jb .save_context_full_clear_loop + pop xDI + + ; Do the 386+ state saving. +%if TMPL_BITS == 16 ; save the high word of registered pushed on the stack. + mov ecx, VAR_CALLER_AX + mov [ss:bx + BS3REGCTX.rax], ecx + mov ecx, VAR_CALLER_CX + mov [ss:bx + BS3REGCTX.rcx], ecx + mov ecx, VAR_CALLER_DX + mov [ss:bx + BS3REGCTX.rdx], ecx + mov ecx, VAR_CALLER_BX + mov [ss:bx + BS3REGCTX.rbx], ecx + mov ecx, VAR_CALLER_EBP + mov [ss:bx + BS3REGCTX.rbp], ecx + mov ecx, VAR_CALLER_ESP + mov [ss:bx + BS3REGCTX.rsp], ecx + mov ecx, VAR_CALLER_SI + mov [ss:bx + BS3REGCTX.rsi], ecx + mov ecx, VAR_CALLER_DI + mov [ss:bx + BS3REGCTX.rdi], ecx + mov ecx, VAR_CALLER_EFLAGS + mov [ss:bx + BS3REGCTX.rflags], ecx + + ; Seed high EIP word if 32-bit CS. + lar ecx, [bp + 4] + jnz .save_context_full_done_16bit_high_word + test ecx, X86LAR_F_D + jz .save_context_full_done_16bit_high_word + mov ecx, [BS3_DATA16_WRT(g_uBs3TrapEipHint)] + mov [ss:bx + BS3REGCTX.rip], ecx +.save_context_full_done_16bit_high_word: +%endif ; 16-bit + mov xAX, VAR_CALLER_AX + mov [BS3_NOT_64BIT(ss:) xBX + BS3REGCTX.rax], xAX + mov xCX, VAR_CALLER_CX + mov [BS3_NOT_64BIT(ss:) xBX + BS3REGCTX.rcx], xCX + mov xAX, VAR_CALLER_DX + mov [BS3_NOT_64BIT(ss:) xBX + BS3REGCTX.rdx], xAX + mov xAX, VAR_CALLER_BX + mov [BS3_NOT_64BIT(ss:) xBX + BS3REGCTX.rbx], xAX + mov [BS3_NOT_64BIT(ss:) xBX + BS3REGCTX.rsi], sSI + mov [BS3_NOT_64BIT(ss:) xBX + BS3REGCTX.rdi], sDI + mov xAX, VAR_CALLER_BP + mov [BS3_NOT_64BIT(ss:) xBX + BS3REGCTX.rbp], xAX +%if TMPL_BITS != 64 + mov ax, VAR_CALLER_DS + mov [BS3_NOT_64BIT(ss:) xBX + BS3REGCTX.ds], ax +%else + mov [BS3_NOT_64BIT(ss:) xBX + BS3REGCTX.ds], ds +%endif + mov [BS3_NOT_64BIT(ss:) xBX + BS3REGCTX.es], es + mov [BS3_NOT_64BIT(ss:) xBX + BS3REGCTX.fs], fs + mov [BS3_NOT_64BIT(ss:) xBX + BS3REGCTX.gs], gs + mov xAX, [xBP + xCB] + mov [BS3_NOT_64BIT(ss:) xBX + BS3REGCTX.rip], xAX + mov ax, [xBP + xCB*2] + mov [BS3_NOT_64BIT(ss:) xBX + BS3REGCTX.cs], ax +%if TMPL_MODE != BS3_MODE_RM + and al, X86_SEL_RPL + mov [BS3_NOT_64BIT(ss:) xBX + BS3REGCTX.bCpl], al + cmp al, 0 + je .save_context_full_same + mov xAX, [xBP + xCB*4] + mov [BS3_NOT_64BIT(ss:) xBX + BS3REGCTX.rsp], xAX + mov ax, [xBP + xCB*5] + mov [BS3_NOT_64BIT(ss:) xBX + BS3REGCTX.ss], ax + jmp .save_context_full_done_stack +%else + mov byte [BS3_NOT_64BIT(ss:) xBX + BS3REGCTX.bCpl], 0 +%endif +.save_context_full_same: + mov xAX, xBP + add xAX, xCB * (1 + 3) + mov [BS3_NOT_64BIT(ss:) xBX + BS3REGCTX.rsp], xAX + mov ax, ss + mov [BS3_NOT_64BIT(ss:) xBX + BS3REGCTX.ss], ax +.save_context_full_done_stack: + mov xAX, [xBP + xCB*3] + mov [BS3_NOT_64BIT(ss:) xBX + BS3REGCTX.rflags], xAX + + mov al, VAR_CALLER_MODE + mov [BS3_NOT_64BIT(ss:) xBX + BS3REGCTX.bMode], al +%if TMPL_BITS == 64 + mov [BS3_NOT_64BIT(ss:) xBX + BS3REGCTX.r8], r8 + mov [BS3_NOT_64BIT(ss:) xBX + BS3REGCTX.r9], r9 + mov [BS3_NOT_64BIT(ss:) xBX + BS3REGCTX.r10], r10 + mov [BS3_NOT_64BIT(ss:) xBX + BS3REGCTX.r11], r11 + mov [BS3_NOT_64BIT(ss:) xBX + BS3REGCTX.r12], r12 + mov [BS3_NOT_64BIT(ss:) xBX + BS3REGCTX.r13], r13 + mov [BS3_NOT_64BIT(ss:) xBX + BS3REGCTX.r14], r14 + mov [BS3_NOT_64BIT(ss:) xBX + BS3REGCTX.r15], r15 +%endif + str [BS3_NOT_64BIT(ss:) xBX + BS3REGCTX.tr] + sldt [BS3_NOT_64BIT(ss:) xBX + BS3REGCTX.ldtr] + mov sAX, cr0 + mov [BS3_NOT_64BIT(ss:) xBX + BS3REGCTX.cr0], sAX + mov sAX, cr2 + mov [BS3_NOT_64BIT(ss:) xBX + BS3REGCTX.cr2], sAX + mov sAX, cr3 + mov [BS3_NOT_64BIT(ss:) xBX + BS3REGCTX.cr3], sAX +%if TMPL_BITS != 64 + test byte [BS3_DATA16_WRT(g_uBs3CpuDetected)], (BS3CPU_F_CPUID >> 8) + jnz .have_cr4 + or byte [BS3_NOT_64BIT(ss:) xBX + BS3REGCTX.fbFlags], BS3REG_CTX_F_NO_CR4 + jmp .done_cr4 +.have_cr4: +%endif + mov sAX, cr4 + mov [BS3_NOT_64BIT(ss:) xBX + BS3REGCTX.cr4], sAX +%if TMPL_BITS != 64 +.done_cr4: + or byte [ss:xBX + BS3REGCTX.fbFlags], BS3REG_CTX_F_NO_AMD64 + + ; Deal with extended v8086 frame. + %if TMPL_BITS == 32 + test dword [BS3_NOT_64BIT(ss:) xBX + BS3REGCTX.rflags], X86_EFL_VM + jz .save_context_full_return + %else + test byte VAR_CALLER_MODE, BS3_MODE_CODE_V86 + jz .save_context_full_return + mov dword [BS3_NOT_64BIT(ss:) xBX + BS3REGCTX.rflags], X86_EFL_VM + %endif + mov xAX, [xBP + xCB*4] + mov [BS3_NOT_64BIT(ss:) xBX + BS3REGCTX.rsp], xAX + mov ax, [xBP + xCB*5] + mov [BS3_NOT_64BIT(ss:) xBX + BS3REGCTX.ss], ax + mov ax, [xBP + xCB*6] + mov [BS3_NOT_64BIT(ss:) xBX + BS3REGCTX.es], ax + mov ax, [xBP + xCB*7] + mov [BS3_NOT_64BIT(ss:) xBX + BS3REGCTX.ds], ax + mov ax, [xBP + xCB*8] + mov [BS3_NOT_64BIT(ss:) xBX + BS3REGCTX.fs], ax + mov ax, [xBP + xCB*9] + mov [BS3_NOT_64BIT(ss:) xBX + BS3REGCTX.gs], ax + mov byte [BS3_NOT_64BIT(ss:) xBX + BS3REGCTX.bCpl], 3 + jmp .save_context_full_return + +%endif ; !64-bit + +.save_context_full_return: + ret + +%if TMPL_BITS == 16 + CPU 286 +%endif + + ; + ; Internal function for converting a syscall pointer parameter (cx:xSI) + ; to a pointer we can use here in this context. + ; + ; Returns the result in cx:xSI. + ; @uses xAX, xCX, xDX + ; +.convert_ptr_arg_to_cx_xSI: + call .convert_ptr_arg_to_flat +%if TMPL_BITS == 16 + ; Convert to tiled address. + mov si, ax ; offset. + shl dx, X86_SEL_SHIFT + add dx, BS3_SEL_TILED + mov cx, dx +%else + ; Just supply a flat selector. + mov xSI, xAX + mov cx, ds +%endif + ret + + ; + ; Internal function for converting a syscall pointer parameter (caller CX:xSI) + ; to a real mode pointer. + ; + ; Returns the result in AX:SI. + ; @uses xAX, xCX, xDX + ; +.convert_ptr_arg_to_real_mode_ax_si: + call .convert_ptr_arg_to_flat + mov si, ax +%if TMPL_BITS == 16 + mov ax, dx +%else + shr eax, 16 +%endif + shl ax, 12 + ret + + ; + ; Internal function for the above that wraps the Bs3SelProtFar32ToFlat32 call. + ; + ; @returns eax (32-bit, 64-bit), dx+ax (16-bit). + ; @uses eax, ecx, edx + ; +.convert_ptr_arg_to_flat: +%if TMPL_BITS == 16 + ; Convert to (32-bit) flat address first. + test byte VAR_CALLER_MODE, BS3_MODE_CODE_V86 + jz .convert_ptr_arg_to_flat_prot_16 + + mov ax, VAR_CALLER_CX + mov dx, ax + shl ax, 4 + shr dx, 12 + add ax, VAR_CALLER_SI + adc dx, 0 + ret + +.convert_ptr_arg_to_flat_prot_16: + push es + push bx + push word VAR_CALLER_CX ; selector + xor ax, ax + test byte VAR_CALLER_MODE, BS3_MODE_CODE_16 + jnz .caller_is_16_bit + mov ax, VAR_CALLER_SI_HI +.caller_is_16_bit: + push ax ; offset high + push word VAR_CALLER_SI ; offset low + call Bs3SelProtFar32ToFlat32 + add sp, 2*3 + pop bx + pop es + ret + +%else ; 32 or 64 bit + test byte VAR_CALLER_MODE, BS3_MODE_CODE_V86 + jz .convert_ptr_arg_to_cx_xSI_prot + + ; Convert real mode address to flat address and return it. + movzx eax, word VAR_CALLER_CX + shl eax, 4 + movzx edx, word VAR_CALLER_SI + add eax, edx + ret + + ; Convert to (32-bit) flat address. +.convert_ptr_arg_to_cx_xSI_prot: + %if TMPL_BITS == 64 + push r11 + push r10 + push r9 + push r8 + sub rsp, 10h + %endif + movzx ecx, word VAR_CALLER_CX + push xCX + mov eax, VAR_CALLER_SI + test byte VAR_CALLER_MODE, BS3_MODE_CODE_16 + jz .no_masking_offset + and eax, 0ffffh +.no_masking_offset: + push xAX + BS3_CALL Bs3SelProtFar32ToFlat32,2 + add xSP, xCB*2 BS3_ONLY_64BIT(+ 10h) + %if TMPL_BITS == 64 + pop r8 + pop r9 + pop r10 + pop r11 + %endif +%endif + ret + +BS3_PROC_END_MODE Bs3TrapSystemCallHandler + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-rm-InitAll.c b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-rm-InitAll.c new file mode 100644 index 00000000..f280270e --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-rm-InitAll.c @@ -0,0 +1,90 @@ +/* $Id: bs3-rm-InitAll.c $ */ +/** @file + * BS3Kit - Initialize all components, real mode. + */ + +/* + * Copyright (C) 2007-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +//#define BS3_USE_RM_TEXT_SEG 1 +#include "bs3kit-template-header.h" +#include "bs3-cmn-test.h" +#include <iprt/asm-amd64-x86.h> + +BS3_MODE_PROTO_NOSB(void, Bs3EnteredMode,(void)); + + +BS3_DECL(void) Bs3InitAll_rm(void) +{ + uint8_t volatile BS3_FAR *pcTicksFlpyOff; + + /* + * Detect CPU first as the memory init code will otherwise use 386 + * instrunctions and cause trouble on older CPUs. + */ + Bs3CpuDetect_rm_far(); + Bs3InitMemory_rm_far(); + Bs3InitGdt_rm_far(); + + /* + * Before we disable all interrupts, try convince the BIOS to stop the + * floppy motor, as it is kind of disturbing when the floppy light remains + * on for the whole testcase execution. + */ + ASMIntDisable(); /* (probably already disabled, but no guarantees) */ + pcTicksFlpyOff = (uint8_t volatile BS3_FAR *)BS3_FP_MAKE(0x40, 0x40); + if (*pcTicksFlpyOff) + { + uint32_t volatile BS3_FAR *pcTicks = (uint32_t volatile BS3_FAR *)BS3_FP_MAKE(0x40, 0x6c); + uint32_t cInitialTicks; + + *pcTicksFlpyOff = 1; /* speed up the countdown, don't want to wait for two seconds here. */ + cInitialTicks = *pcTicks; + ASMIntEnable(); + + while (*pcTicks == cInitialTicks) + ASMHalt(); + } + ASMIntDisable(); + Bs3PicSetup(); + + /* + * Initialize IDTs and such. + */ + if (g_uBs3CpuDetected & BS3CPU_F_LONG_MODE) + Bs3Trap64Init(); + if ((g_uBs3CpuDetected & BS3CPU_TYPE_MASK) >= BS3CPU_80386) + Bs3Trap32Init(); + if ((g_uBs3CpuDetected & BS3CPU_TYPE_MASK) >= BS3CPU_80286) + Bs3Trap16Init(); + Bs3TrapRmV86Init(); + + /* + * Perform a real-mode enter to make some final environment adjustments + * (like installing our syscall). + */ + Bs3EnteredMode_rm(); +} + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-rm-InitGdt.c b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-rm-InitGdt.c new file mode 100644 index 00000000..46a61f2d --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-rm-InitGdt.c @@ -0,0 +1,61 @@ +/* $Id: bs3-rm-InitGdt.c $ */ +/** @file + * BS3Kit - Bs3InitGdt + */ + +/* + * Copyright (C) 2007-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#define BS3_USE_RM_TEXT_SEG 1 +#include "bs3kit-template-header.h" +#include <iprt/asm.h> + + +/********************************************************************************************************************************* +* Global Variables * +*********************************************************************************************************************************/ + + +BS3_DECL_FAR(void) Bs3InitGdt_rm_far(void) +{ +#if 1 + Bs3Gdte_R0_CS16.Gen.u16LimitLow = Bs3Text16_Size - 1; + Bs3Gdte_R1_CS16.Gen.u16LimitLow = Bs3Text16_Size - 1; + Bs3Gdte_R2_CS16.Gen.u16LimitLow = Bs3Text16_Size - 1; + Bs3Gdte_R3_CS16.Gen.u16LimitLow = Bs3Text16_Size - 1; +#endif + Bs3Gdte_RMTEXT16_CS.Gen.u16LimitLow = Bs3RmText16_Size - 1; + Bs3Gdte_X0TEXT16_CS.Gen.u16LimitLow = Bs3X0Text16_Size - 1; + Bs3Gdte_X1TEXT16_CS.Gen.u16LimitLow = Bs3X1Text16_Size - 1; + + Bs3Gdte_RMTEXT16_CS.Gen.u16BaseLow = (uint16_t)Bs3RmText16_FlatAddr; + Bs3Gdte_X0TEXT16_CS.Gen.u16BaseLow = (uint16_t)Bs3X0Text16_FlatAddr; + Bs3Gdte_X1TEXT16_CS.Gen.u16BaseLow = (uint16_t)Bs3X1Text16_FlatAddr; + + Bs3Gdte_RMTEXT16_CS.Gen.u8BaseHigh1 = (uint8_t)(Bs3RmText16_FlatAddr >> 16); + Bs3Gdte_X0TEXT16_CS.Gen.u8BaseHigh1 = (uint8_t)(Bs3X0Text16_FlatAddr >> 16); + Bs3Gdte_X1TEXT16_CS.Gen.u8BaseHigh1 = (uint8_t)(Bs3X1Text16_FlatAddr >> 16); +} + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-rm-InitMemory.c b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-rm-InitMemory.c new file mode 100644 index 00000000..af58e5fc --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-rm-InitMemory.c @@ -0,0 +1,372 @@ +/* $Id: bs3-rm-InitMemory.c $ */ +/** @file + * BS3Kit - Bs3InitMemory + */ + +/* + * Copyright (C) 2007-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#define BS3_USE_RM_TEXT_SEG 1 +#include "bs3kit-template-header.h" +#include "bs3-cmn-memory.h" +#include <iprt/asm.h> +#include <VBox/VMMDevTesting.h> + + +/********************************************************************************************************************************* +* Structures and Typedefs * +*********************************************************************************************************************************/ + +typedef struct INT15E820ENTRY +{ + uint64_t uBaseAddr; + uint64_t cbRange; + /** Memory type this entry describes, see INT15E820_TYPE_XXX. */ + uint32_t uType; + uint32_t fAcpi3; +} INT15E820ENTRY; +AssertCompileSize(INT15E820ENTRY,24); + + +/** @name INT15E820_TYPE_XXX - Memory types returned by int 15h function 0xe820. + * @{ */ +#define INT15E820_TYPE_USABLE 1 /**< Usable RAM. */ +#define INT15E820_TYPE_RESERVED 2 /**< Reserved by the system, unusable. */ +#define INT15E820_TYPE_ACPI_RECLAIMABLE 3 /**< ACPI reclaimable memory, whatever that means. */ +#define INT15E820_TYPE_ACPI_NVS 4 /**< ACPI non-volatile storage? */ +#define INT15E820_TYPE_BAD 5 /**< Bad memory, unusable. */ +/** @} */ + + +/** + * Performs a int 15h function 0xe820 call. + * + * @returns Continuation value on success, 0 on failure. + * (Because of the way the API works, EBX should never be zero when + * data is returned.) + * @param pEntry The return buffer. + * @param cbEntry The size of the buffer (min 20 bytes). + * @param uContinuationValue Zero the first time, the return value from the + * previous call after that. + */ +BS3_DECL(uint32_t) Bs3BiosInt15hE820(INT15E820ENTRY BS3_FAR *pEntry, size_t cbEntry, uint32_t uContinuationValue); +#pragma aux Bs3BiosInt15hE820 = \ + ".386" \ + "shl ebx, 10h" \ + "mov bx, ax" /* ebx = continutation */ \ + "movzx ecx, cx" \ + "movzx edi, di" \ + "mov edx, 0534d4150h" /*SMAP*/ \ + "mov eax, 0xe820" \ + "int 15h" \ + "jc failed" \ + "cmp eax, 0534d4150h" \ + "jne failed" \ + "cmp cx, 20" \ + "jb failed" \ + "mov ax, bx" \ + "shr ebx, 10h" /* ax:bx = continuation */ \ + "jmp done" \ + "failed:" \ + "xor ax, ax" \ + "xor bx, bx" \ + "done:" \ + parm [es di] [cx] [ax bx] \ + value [ax bx] \ + modify exact [ax bx cx dx di es]; + +/** + * Performs a int 15h function 0x88 call. + * + * @returns UINT32_MAX on failure, number of KBs above 1MB otherwise. + */ +BS3_DECL(uint32_t) Bs3BiosInt15h88(void); +#pragma aux Bs3BiosInt15h88 = \ + ".286" \ + "clc" \ + "mov ax, 08800h" \ + "int 15h" \ + "jc failed" \ + "xor dx, dx" \ + "jmp done" \ + "failed:" \ + "xor ax, ax" \ + "dec ax" \ + "mov dx, ax" \ + "done:" \ + value [ax dx] \ + modify exact [ax bx cx dx es]; + + +/********************************************************************************************************************************* +* Global Variables * +*********************************************************************************************************************************/ +/** Slab control structure for the 4K management of low memory (< 1MB). */ +BS3SLABCTLLOW g_Bs3Mem4KLow; +/** Slab control structure for the 4K management of tiled upper memory, + * between 1 MB and 16MB. */ +BS3SLABCTLUPPERTILED g_Bs3Mem4KUpperTiled; + + +/** Translates a power of two request size to an slab list index. */ +uint8_t const g_aiBs3SlabListsByPowerOfTwo[12] = +{ + /* 2^0 = 1 */ 0, + /* 2^1 = 2 */ 0, + /* 2^2 = 4 */ 0, + /* 2^3 = 8 */ 0, + /* 2^4 = 16 */ 0, + /* 2^5 = 32 */ 1, + /* 2^6 = 64 */ 2, + /* 2^7 = 128 */ 3, + /* 2^8 = 256 */ 4, + /* 2^9 = 512 */ 5, + /* 2^10 = 1024 */ -1 + /* 2^11 = 2048 */ -1 +}; + +/** The slab list chunk sizes. */ +uint16_t const g_acbBs3SlabLists[BS3_MEM_SLAB_LIST_COUNT] = +{ + 16, + 32, + 64, + 128, + 256, + 512, +}; + +/** Low memory slab lists, sizes given by g_acbBs3SlabLists. */ +BS3SLABHEAD g_aBs3LowSlabLists[BS3_MEM_SLAB_LIST_COUNT]; +/** Upper tiled memory slab lists, sizes given by g_acbBs3SlabLists. */ +BS3SLABHEAD g_aBs3UpperTiledSlabLists[BS3_MEM_SLAB_LIST_COUNT]; + +/** Slab control structure sizes for the slab lists. + * This is to help the allocator when growing a list. */ +uint16_t const g_cbBs3SlabCtlSizesforLists[BS3_MEM_SLAB_LIST_COUNT] = +{ + RT_ALIGN(sizeof(BS3SLABCTL) - 4 + (4096 / 16 / 8 /*=32*/), 16), + RT_ALIGN(sizeof(BS3SLABCTL) - 4 + (4096 / 32 / 8 /*=16*/), 32), + RT_ALIGN(sizeof(BS3SLABCTL) - 4 + (4096 / 64 / 8 /*=8*/), 64), + RT_ALIGN(sizeof(BS3SLABCTL) - 4 + (4096 / 128 / 8 /*=4*/), 128), + RT_ALIGN(sizeof(BS3SLABCTL) - 4 + (4096 / 256 / 8 /*=2*/), 256), + RT_ALIGN(sizeof(BS3SLABCTL) - 4 + (4096 / 512 / 8 /*=1*/), 512), +}; + + +/** The last RAM address below 4GB (approximately). */ +uint32_t g_uBs3EndOfRamBelow4G = 0; + + + +/** + * Adds a range of memory to the tiled slabs. + * + * @param uRange Start of range. + * @param cbRange Size of range. + */ +static void bs3InitMemoryAddRange32(uint32_t uRange, uint32_t cbRange) +{ + uint32_t uRangeEnd = uRange + cbRange; + if (uRangeEnd < uRange) + uRangeEnd = UINT32_MAX; + + /* Raise the end-of-ram-below-4GB marker? */ + if (uRangeEnd > g_uBs3EndOfRamBelow4G) + g_uBs3EndOfRamBelow4G = uRangeEnd; + + /* Applicable to tiled memory? */ + if ( uRange < BS3_SEL_TILED_AREA_SIZE + && ( uRange >= _1M + || uRangeEnd >= _1M)) + { + uint16_t cPages; + + /* Adjust the start of the range such that it's at or above 1MB and page aligned. */ + if (uRange < _1M) + { + cbRange -= _1M - uRange; + uRange = _1M; + } + else if (uRange & (_4K - 1U)) + { + cbRange -= uRange & (_4K - 1U); + uRange = RT_ALIGN_32(uRange, _4K); + } + + /* Adjust the end/size of the range such that it's page aligned and not beyond the tiled area. */ + if (uRangeEnd > BS3_SEL_TILED_AREA_SIZE) + { + cbRange -= uRangeEnd - BS3_SEL_TILED_AREA_SIZE; + uRangeEnd = BS3_SEL_TILED_AREA_SIZE; + } + else if (uRangeEnd & (_4K - 1U)) + { + cbRange -= uRangeEnd & (_4K - 1U); + uRangeEnd &= ~(uint32_t)(_4K - 1U); + } + + /* If there is still something, enable it. + (We're a bit paranoid here don't trust the BIOS to only report a page once.) */ + cPages = cbRange >> 12; /*div 4K*/ + if (cPages) + { + unsigned i; + uRange -= _1M; + i = uRange >> 12; /*div _4K*/ + while (cPages-- > 0) + { + uint16_t uLineToLong = ASMBitTestAndClear(g_Bs3Mem4KUpperTiled.Core.bmAllocated, i); + g_Bs3Mem4KUpperTiled.Core.cFreeChunks += uLineToLong; + i++; + } + } + } +} + + +BS3_DECL(void) BS3_FAR_CODE Bs3InitMemory_rm_far(void) +{ + uint16_t i; + uint16_t cPages; + uint32_t u32; + INT15E820ENTRY Entry; + uint32_t BS3_FAR *pu32Mmio; + + /* + * Enable the A20 gate. + */ + Bs3A20Enable(); + + /* + * Low memory (4K chunks). + * - 0x00000 to 0x004ff - Interrupt Vector table, BIOS data area. + * - 0x01000 to 0x0ffff - Stacks. + * - 0x10000 to 0x1yyyy - BS3TEXT16 + * - 0x20000 to 0x26fff - BS3SYSTEM16 + * - 0x29000 to 0xzzzzz - BS3DATA16, BS3TEXT32, BS3TEXT64, BS3DATA32, BS3DATA64 (in that order). + * - 0xzzzzZ to 0x9fdff - Free conventional memory. + * - 0x9fc00 to 0x9ffff - Extended BIOS data area (exact start may vary). + * - 0xa0000 to 0xbffff - VGA MMIO + * - 0xc0000 to 0xc7fff - VGA BIOS + * - 0xc8000 to 0xeffff - ROMs, tables, unusable. + * - 0xf0000 to 0xfffff - PC BIOS. + */ + Bs3SlabInit(&g_Bs3Mem4KLow.Core, sizeof(g_Bs3Mem4KLow), 0 /*uFlatSlabPtr*/, 0xA0000 /* 640 KB*/, _4K); + + /* Mark the stacks and whole image as allocated. */ + cPages = (Bs3TotalImageSize + _4K - 1U) >> 12; + ASMBitSetRange(g_Bs3Mem4KLow.Core.bmAllocated, 0, 0x10 + cPages); + + /* Mark any unused pages between BS3TEXT16 and BS3SYSTEM16 as free. */ + cPages = (Bs3Text16_Size + (uint32_t)_4K - 1U) >> 12; + ASMBitClearRange(g_Bs3Mem4KLow.Core.bmAllocated, 0x10U + cPages, 0x20U); + + /* In case the system has less than 640KB of memory, check the BDA variable for it. */ + cPages = *(uint16_t BS3_FAR *)BS3_FP_MAKE(0x0000, 0x0413); /* KB of low memory */ + if (cPages < 640) + { + cPages = 640 - cPages; + cPages = RT_ALIGN(cPages, 4); + cPages >>= 2; + ASMBitSetRange(g_Bs3Mem4KLow.Core.bmAllocated, 0xA0 - cPages, 0xA0); + } + else + ASMBitSet(g_Bs3Mem4KLow.Core.bmAllocated, 0x9F); + + /* Recalc free pages. */ + cPages = 0; + i = g_Bs3Mem4KLow.Core.cChunks; + while (i-- > 0) + cPages += !ASMBitTest(g_Bs3Mem4KLow.Core.bmAllocated, i); + g_Bs3Mem4KLow.Core.cFreeChunks = cPages; + + /* + * First 16 MB of memory above 1MB. We start out by marking it all allocated. + */ + Bs3SlabInit(&g_Bs3Mem4KUpperTiled.Core, sizeof(g_Bs3Mem4KUpperTiled), _1M, BS3_SEL_TILED_AREA_SIZE - _1M, _4K); + + ASMBitSetRange(g_Bs3Mem4KUpperTiled.Core.bmAllocated, 0, g_Bs3Mem4KUpperTiled.Core.cChunks); + g_Bs3Mem4KUpperTiled.Core.cFreeChunks = 0; + + /* Ask the BIOS about where there's memory, and make pages in between 1MB + and BS3_SEL_TILED_AREA_SIZE present. This means we're only interested + in entries describing usable memory, ASSUMING of course no overlaps. */ + if ( (g_uBs3CpuDetected & BS3CPU_TYPE_MASK) >= BS3CPU_80386 + && Bs3BiosInt15hE820(&Entry, sizeof(Entry), 0) != 0) + { + uint32_t uCont = 0; + i = 0; + while ( (uCont = Bs3BiosInt15hE820(&Entry, sizeof(Entry), uCont)) != 0 + && i++ < 2048) + if (Entry.uType == INT15E820_TYPE_USABLE) + if (!(Entry.uBaseAddr >> 32)) + /* Convert from 64-bit to 32-bit value and record it. */ + bs3InitMemoryAddRange32((uint32_t)Entry.uBaseAddr, + (Entry.cbRange >> 32) ? UINT32_C(0xfffff000) : (uint32_t)Entry.cbRange); + } + /* Try the 286+ API for getting memory above 1MB and (usually) below 16MB. */ + else if ( (g_uBs3CpuDetected & BS3CPU_TYPE_MASK) >= BS3CPU_80386 + && (u32 = Bs3BiosInt15h88()) != UINT32_MAX + && u32 > 0) + bs3InitMemoryAddRange32(_1M, u32 * _1K); + + /* + * Check if we've got the VMMDev MMIO testing memory mapped above 1MB. + */ + pu32Mmio = (uint32_t BS3_FAR *)BS3_FP_MAKE(VMMDEV_TESTING_MMIO_RM_SEL, + VMMDEV_TESTING_MMIO_RM_OFF2(VMMDEV_TESTING_MMIO_OFF_NOP)); + if (*pu32Mmio == VMMDEV_TESTING_NOP_RET) + { + Bs3Printf("Memory: Found VMMDev MMIO testing region\n"); + if (!ASMBitTestAndSet(g_Bs3Mem4KUpperTiled.Core.bmAllocated, 1)) + g_Bs3Mem4KUpperTiled.Core.cFreeChunks--; + + } + + /* + * Initialize the slab lists. + */ + for (i = 0; i < BS3_MEM_SLAB_LIST_COUNT; i++) + { + Bs3SlabListInit(&g_aBs3LowSlabLists[i], g_acbBs3SlabLists[i]); + Bs3SlabListInit(&g_aBs3UpperTiledSlabLists[i], g_acbBs3SlabLists[i]); + } + +#if 0 + /* + * For debugging. + */ + Bs3Printf("Memory-low: %u/%u chunks bmAllocated[]=", g_Bs3Mem4KLow.Core.cFreeChunks, g_Bs3Mem4KLow.Core.cChunks); + for (i = 0; i < 20; i++) + Bs3Printf("%02x ", g_Bs3Mem4KLow.Core.bmAllocated[i]); + Bs3Printf("\n"); + Bs3Printf("Memory-upt: %u/%u chunks bmAllocated[]=", g_Bs3Mem4KUpperTiled.Core.cFreeChunks, g_Bs3Mem4KUpperTiled.Core.cChunks); + for (i = 0; i < 32; i++) + Bs3Printf("%02x ", g_Bs3Mem4KUpperTiled.Core.bmAllocated[i]); + Bs3Printf("...\n"); +#endif +} + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-shutdown.c b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-shutdown.c new file mode 100644 index 00000000..c5c8910b --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-shutdown.c @@ -0,0 +1,77 @@ +/* $Id: bs3-shutdown.c $ */ +/** @file + * BS3Kit - Shutdown VM from PE16 - proof of concept (BS3Kit). + */ + +/* + * Copyright (C) 2007-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include "bs3kit.h" +#include <iprt/assert.h> +#include <iprt/asm-amd64-x86.h> + +AssertCompileSize(uint16_t, 2); +AssertCompileSize(uint32_t, 4); +AssertCompileSize(uint64_t, 8); + +extern uint16_t ASMGetMsw(); +#pragma aux ASMGetMsw = \ + ".286" \ + "smsw ax" \ + value [ax] \ + modify exact; + +extern void ASMSetMsw(uint16_t uMsw); +#pragma aux ASMSetMsw = \ + ".286p" \ + "lmsw ax" \ + parm [ax] \ + modify exact; + +/* Just a sample. */ +BS3_DECL(void) Main_pe16(void) +{ + uint16_t uMsw = ASMGetMsw(); + Bs3Printf("msw=%#x cr0=%RX32 g_uBs3CpuDetected=%#x\n", uMsw, ASMGetCR0(), g_uBs3CpuDetected); + Bs3Printf("cr2=%RX32 cr3=%RX32\n", ASMGetCR2(), ASMGetCR3()); + ASMSetMsw(X86_CR0_PE); + Bs3Printf("lmsw(PE) => msw=%#x cr0=%RX32\n", ASMGetMsw(), ASMGetCR0()); + ASMSetMsw(UINT16_MAX); + Bs3Printf("lmsw(0xffff) => msw=%#x cr0=%RX32\n", ASMGetMsw(), ASMGetCR0()); + ASMSetCR0(X86_CR0_PE); + Bs3Printf("ASMSetCR0(X86_CR0_PE) => msw=%#x cr0=%RX32\n", ASMGetMsw(), ASMGetCR0()); + ASMSetCR0(UINT32_C(0x7fffffff)); + Bs3Printf("ASMSetCR0(0x7fffffff) => msw=%#x cr0=%RX32\n", ASMGetMsw(), ASMGetCR0()); + + Bs3TestInit("bs3-shutdown"); + Bs3TestPrintf("detected cpu: %#x\n", g_uBs3CpuDetected); +#if 1 + ASMHalt(); +#else + Bs3Shutdown(); +#endif + return; +} + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-system-data.asm b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-system-data.asm new file mode 100644 index 00000000..dd793de4 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-system-data.asm @@ -0,0 +1,1046 @@ +; $Id: bs3-system-data.asm $ +;; @file +; BS3Kit - GDT +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + +%include "bs3kit.mac" + +%define BS3_SYSTEM16_BASE_16_23 ((BS3_ADDR_BS3SYSTEM16 >> 16) & 0xff) +%define BS3_SYSTEM16_BASE_LOW(a_DataSym) ((BS3_DATA_NM(a_DataSym) - StartSystem16) & 0xffff) + +;; +; The GDT (X86DESCGENERIC). +; +BS3_BEGIN_SYSTEM16 +StartSystem16: + db 10, 13, 'eye-catcher: SYSTEM16.......', 10, 13 ; 32 bytes long +BS3_GLOBAL_DATA Bs3Gdt, 4000h - 20h + +;; Macro for checking GDT offsets as we go along. +;; @param %1 The expected current offset. +%macro BS3GdtAssertOffset 1 + %ifndef KBUILD_GENERATING_MAKEFILE_DEPENDENCIES + %if ($ - BS3_DATA_NM(Bs3Gdt)) != %1 + %assign offActual ($ - BS3_DATA_NM(Bs3Gdt)) + %error "BS3GdtAssertOffset: Bad offset: " %+ offActual %+ ", expected " %+ %1 + %endif + %endif +%endmacro + + dw 00000h, 00000h, 00000h, 00000h ; null selector +BS3GdtAssertOffset 8 + + ; + ; 008h..0f8h - System selectors and other stuff + ; + dw 00000h, 00000h, 00000h, 00000h ; Entry 008h - currently unused + +BS3_GLOBAL_DATA Bs3Gdte_Ldt, 16 ; Entry 010h + dw BS3_DATA_NM(Bs3LdtEnd) - BS3_DATA_NM(Bs3Ldt) - 1 + dw BS3_SYSTEM16_BASE_LOW(Bs3Ldt) + db BS3_SYSTEM16_BASE_16_23 + db X86_SEL_TYPE_SYS_LDT | 0x80 + dw 00000h + dw 00000h, 00000h, 00000h, 00000h ; zero for 64-bit mode. + +BS3_GLOBAL_DATA Bs3Gdte_Tss16, 8 ; Entry 020h + dw 0002bh ; 16-bit TSS. + dw BS3_SYSTEM16_BASE_LOW(Bs3Tss16) + db BS3_SYSTEM16_BASE_16_23 + db X86_SEL_TYPE_SYS_286_TSS_AVAIL | 0x80 + dw 0 + +BS3_GLOBAL_DATA Bs3Gdte_Tss16DoubleFault, 8 ; Entry 028h + dw 0002bh ; 16-bit TSS, double fault. + dw BS3_SYSTEM16_BASE_LOW(Bs3Tss16DoubleFault) + db BS3_SYSTEM16_BASE_16_23 + db X86_SEL_TYPE_SYS_286_TSS_AVAIL | 0x80 + dw 0 + +BS3_GLOBAL_DATA Bs3Gdte_Tss16Spare0, 8 ; Entry 030h + dw 0002bh ; 16-bit TSS, spare 0. + dw BS3_SYSTEM16_BASE_LOW(Bs3Tss16Spare0) + db BS3_SYSTEM16_BASE_16_23 + db X86_SEL_TYPE_SYS_286_TSS_AVAIL | 0x80 + dw 0 + +BS3_GLOBAL_DATA Bs3Gdte_Tss16Spare1, 8 ; Entry 038h + dw 0002bh ; 16-bit TSS, spare 0. + dw BS3_SYSTEM16_BASE_LOW(Bs3Tss16Spare1) + db BS3_SYSTEM16_BASE_16_23 + db X86_SEL_TYPE_SYS_286_TSS_AVAIL | 0x80 + dw 0 + +BS3_GLOBAL_DATA Bs3Gdte_Tss32, 8 ; Entry 040h + dw 00067h ; 32-bit TSS. + dw BS3_SYSTEM16_BASE_LOW(Bs3Tss32) + db BS3_SYSTEM16_BASE_16_23 + db X86_SEL_TYPE_SYS_386_TSS_AVAIL | 0x80 + dw 0 + +BS3_GLOBAL_DATA Bs3Gdte_Tss32DoubleFault, 8 ; Entry 048h + dw 00067h ; 32-bit TSS, double fault. + dw BS3_SYSTEM16_BASE_LOW(Bs3Tss32DoubleFault) + db BS3_SYSTEM16_BASE_16_23 + db X86_SEL_TYPE_SYS_386_TSS_AVAIL | 0x80 + dw 0 + +BS3_GLOBAL_DATA Bs3Gdte_Tss32Spare0, 8 ; Entry 050h + dw 00067h ; 32-bit TSS, spare 0. + dw BS3_SYSTEM16_BASE_LOW(Bs3Tss32Spare0) + db BS3_SYSTEM16_BASE_16_23 + db X86_SEL_TYPE_SYS_386_TSS_AVAIL | 0x80 + dw 0 + +BS3_GLOBAL_DATA Bs3Gdte_Tss32Spare1, 8 ; Entry 058h + dw 00067h ; 32-bit TSS, spare 1. + dw BS3_SYSTEM16_BASE_LOW(Bs3Tss32Spare1) + db BS3_SYSTEM16_BASE_16_23 + db X86_SEL_TYPE_SYS_386_TSS_AVAIL | 0x80 + dw 0 + +BS3_GLOBAL_DATA Bs3Gdte_Tss32IobpIntRedirBm, 8 ; Entry 060h + ; 32-bit TSS, with I/O permission & interrupt redirection bitmaps. + dw BS3_DATA_NM(Bs3SharedIobpEnd) - BS3_DATA_NM(Bs3Tss32WithIopb) - 1 + dw BS3_SYSTEM16_BASE_LOW(Bs3Tss32WithIopb) + db BS3_SYSTEM16_BASE_16_23 + db X86_SEL_TYPE_SYS_386_TSS_AVAIL | 0x80 + dw 0 + +BS3_GLOBAL_DATA Bs3Gdte_Tss32IntRedirBm, 8 ; Entry 068h + ; 32-bit TSS, with interrupt redirection bitmap (IOBP stripped by limit). + dw BS3_DATA_NM(Bs3SharedIobp) - BS3_DATA_NM(Bs3Tss32WithIopb) - 1 + dw BS3_SYSTEM16_BASE_LOW(Bs3Tss32WithIopb) + db BS3_SYSTEM16_BASE_16_23 + db X86_SEL_TYPE_SYS_386_TSS_AVAIL | 0x80 + dw 0 + +BS3_GLOBAL_DATA Bs3Gdte_Tss64, 8 ; Entry 070h + dw 00067h ; 64-bit TSS. + dw BS3_SYSTEM16_BASE_LOW(Bs3Tss64) + db BS3_SYSTEM16_BASE_16_23 + db AMD64_SEL_TYPE_SYS_TSS_AVAIL | 0x80 + dw 0 + dw 00000h, 00000h, 00000h, 00000h + +BS3_GLOBAL_DATA Bs3Gdte_Tss64Spare0, 8 ; Entry 080h + dw 00067h ; 64-bit TSS, spare 0. + dw BS3_SYSTEM16_BASE_LOW(Bs3Tss64Spare0) + db BS3_SYSTEM16_BASE_16_23 + db AMD64_SEL_TYPE_SYS_TSS_AVAIL | 0x80 + dw 0 + dw 00000h, 00000h, 00000h, 00000h + +BS3_GLOBAL_DATA Bs3Gdte_Tss64Spare1, 8 ; Entry 090h + dw 00067h ; 64-bit TSS, spare 1. + dw BS3_SYSTEM16_BASE_LOW(Bs3Tss64Spare1) + db BS3_SYSTEM16_BASE_16_23 + db AMD64_SEL_TYPE_SYS_TSS_AVAIL | 0x80 + dw 0 + dw 00000h, 00000h, 00000h, 00000h + +BS3_GLOBAL_DATA Bs3Gdte_Tss64Iobp, 8 ; Entry 0a0h + ; 64-bit TSS, with I/O permission bitmap + dw BS3_DATA_NM(Bs3SharedIobp) - BS3_DATA_NM(Bs3Tss64WithIopb) - 1 + dw BS3_SYSTEM16_BASE_LOW(Bs3Tss64WithIopb) + db BS3_SYSTEM16_BASE_16_23 + db AMD64_SEL_TYPE_SYS_TSS_AVAIL | 0x80 + dw 0 + dw 00000h, 00000h, 00000h, 00000h + +BS3GdtAssertOffset 0b0h + dw 00000h, 00000h, 00000h, 00000h ; Entry 0b0h - currently unused + dw 00000h, 00000h, 00000h, 00000h ; Entry 0b8h - currently unused + dw 00000h, 00000h, 00000h, 00000h ; Entry 0c0h - currently unused + dw 00000h, 00000h, 00000h, 00000h ; Entry 0c8h - currently unused + dw 00000h, 00000h, 00000h, 00000h ; Entry 0d0h - currently unused + dw 00000h, 00000h, 00000h, 00000h ; Entry 0d8h - currently unused + + ; Misc selectors. +BS3_GLOBAL_DATA Bs3Gdte_RMTEXT16_CS, 8 ; Entry 0e0h + dw 0fffeh, 00000h ; 16-bit conforming code (read+exec) segment, accessed. Will be finalized at startup. + dw 09f00h, 00000h +BS3_GLOBAL_DATA Bs3Gdte_X0TEXT16_CS, 8 ; Entry 0e8h + dw 0fffeh, 00000h ; 16-bit conforming code (read+exec) segment, accessed. Will be finalized at startup. + dw 09f00h, 00000h +BS3_GLOBAL_DATA Bs3Gdte_X1TEXT16_CS, 8 ; Entry 0f0h + dw 0fffeh, 00000h ; 16-bit conforming code (read+exec) segment, accessed. Will be finalized at startup. + dw 09f00h, 00000h +BS3_GLOBAL_DATA Bs3Gdte_R0_MMIO16, 8 ; Entry 0f8h + dw 0ffffh, 00000h, 09310h, 00000h ; 16-bit VMMDev MMIO segment with base 0100000h. +BS3GdtAssertOffset 0100h + + +;; +; Macro that defines the selectors for ring-%1. +; +%macro BS3_GDT_RING_X_SELECTORS 1 +BS3_GLOBAL_DATA Bs3Gdte_R %+ %1 %+ _First, 80h +BS3_GLOBAL_DATA Bs3Gdte_R %+ %1 %+ _CS16, 8 ; Entry 100h + dw 0ffffh, (0xffff & BS3_ADDR_BS3TEXT16) ; 16-bit code segment with base 010000h. + dw 09b01h | (%1 << 0dh) | (0xff & (BS3_ADDR_BS3TEXT16 >> 16)), 00000h | (0xff00 & (BS3_ADDR_BS3TEXT16 >> 16)) + +BS3_GLOBAL_DATA Bs3Gdte_R %+ %1 %+ _DS16, 8 ; Entry 108h + dw 0ffffh, (0xffff & BS3_ADDR_BS3DATA16) ; 16-bit data segment with base 029000h. + dw 09300h | (%1 << 0dh) | (0xff & (BS3_ADDR_BS3DATA16 >> 16)), 00000h | (0xff00 & (BS3_ADDR_BS3DATA16 >> 16)) + +BS3_GLOBAL_DATA Bs3Gdte_R %+ %1 %+ _SS16, 8 ; Entry 110h + dw 0ffffh, 00000h ; 16-bit stack segment with base 0. + dw 09300h | (%1 << 0dh), 00000h + +BS3_GLOBAL_DATA Bs3Gdte_R %+ %1 %+ _CS32, 8 ; Entry 118h + dw 0ffffh, 00000h ; 32-bit flat code segment. + dw 09b00h | (%1 << 0dh), 000cfh + +BS3_GLOBAL_DATA Bs3Gdte_R %+ %1 %+ _DS32, 8 ; Entry 120h + dw 0ffffh, 00000h ; 32-bit flat data segment. + dw 09300h | (%1 << 0dh), 000cfh + +BS3_GLOBAL_DATA Bs3Gdte_R %+ %1 %+ _SS32, 8 ; Entry 128h + dw 0ffffh, 00000h ; 32-bit flat stack segment. + dw 09300h | (%1 << 0dh), 000cfh + +BS3_GLOBAL_DATA Bs3Gdte_R %+ %1 %+ _CS64, 8 ; Entry 130h + dw 0ffffh, 00000h ; 64-bit code segment. + dw 09a00h | (%1 << 0dh), 000afh + +BS3_GLOBAL_DATA Bs3Gdte_R %+ %1 %+ _DS64, 8 ; Entry 138h (also SS64) + dw 0ffffh, 00000h ; 64-bit stack and data segment. + dw 09300h | (%1 << 0dh), 000afh + +BS3_GLOBAL_DATA Bs3Gdte_R %+ %1 %+ _CS16_EO, 8 ; Entry 140h + dw 0ffffh, (0xffff & BS3_ADDR_BS3TEXT16) ; 16-bit code segment with base 01000h, not accessed, execute only, short limit. + dw 09800h | (%1 << 0dh) | (0xff & (BS3_ADDR_BS3TEXT16 >> 16)), 00000h | (0xff00 & (BS3_ADDR_BS3TEXT16 >> 16)) + +BS3_GLOBAL_DATA Bs3Gdte_R %+ %1 %+ _CS16_CNF, 8 ; Entry 148h + dw 0ffffh, (0xffff & BS3_ADDR_BS3TEXT16) ; 16-bit code segment with base 01000h, not accessed, execute only, short limit. + dw 09e00h | (%1 << 0dh) | (0xff & (BS3_ADDR_BS3TEXT16 >> 16)), 00000h | (0xff00 & (BS3_ADDR_BS3TEXT16 >> 16)) + +BS3_GLOBAL_DATA Bs3Gdte_R %+ %1 %+ _CS16_CND_EO, 8 ; Entry 150h + dw 0fffeh, 00000h ; 16-bit conforming code segment with base 0, not accessed, execute only, short limit. + dw 09c00h | (%1 << 0dh), 000cfh + +BS3_GLOBAL_DATA Bs3Gdte_R %+ %1 %+ _CS32_EO, 8 ; Entry 158h + dw 0ffffh, 00000h ; 32-bit flat code segment, not accessed, execute only. + dw 09800h | (%1 << 0dh), 000cfh + +BS3_GLOBAL_DATA Bs3Gdte_R %+ %1 %+ _CS32_CNF, 8 ; Entry 160h + dw 0ffffh, 00000h ; 32-bit flat conforming code segment, not accessed. + dw 09e00h | (%1 << 0dh), 000cfh + +BS3_GLOBAL_DATA Bs3Gdte_R %+ %1 %+ _CS32_CNF_EO, 8 ; Entry 168h + dw 0ffffh, 00000h ; 32-bit flat conforming code segment, not accessed, execute only. + dw 09c00h | (%1 << 0dh), 000cfh + +BS3_GLOBAL_DATA Bs3Gdte_R %+ %1 %+ _CS64_EO, 8 ; Entry 170h + dw 0ffffh, 00000h ; 64-bit code segment, not accessed, execute only. + dw 09800h | (%1 << 0dh), 000afh + +BS3_GLOBAL_DATA Bs3Gdte_R %+ %1 %+ _CS64_CNF, 8 ; Entry 178h + dw 0ffffh, 00000h ; 64-bit conforming code segment, not accessed. + dw 09e00h | (%1 << 0dh), 000afh + +BS3_GLOBAL_DATA Bs3Gdte_R %+ %1 %+ _CS64_CNF_EO, 8 ; Entry 180h + dw 0ffffh, 00000h ; 64-bit conforming code segment, execute only, not accessed. + dw 09c00h | (%1 << 0dh), 000afh + +;; @todo expand down segments. + dw 00000h, 00000h, 00000h, 00000h ; Entry 188h - unused. + dw 00000h, 00000h, 00000h, 00000h ; Entry 190h - unused. + dw 00000h, 00000h, 00000h, 00000h ; Entry 198h - unused. + dw 00000h, 00000h, 00000h, 00000h ; Entry 1a0h - unused. + dw 00000h, 00000h, 00000h, 00000h ; Entry 1a8h - unused. + dw 00000h, 00000h, 00000h, 00000h ; Entry 1b0h - unused. + dw 00000h, 00000h, 00000h, 00000h ; Entry 1b8h - unused. + dw 00000h, 00000h, 00000h, 00000h ; Entry 1c0h - unused. + dw 00000h, 00000h, 00000h, 00000h ; Entry 1c8h - unused. + dw 00000h, 00000h, 00000h, 00000h ; Entry 1d0h - unused. + dw 00000h, 00000h, 00000h, 00000h ; Entry 1d8h - unused. + dw 00000h, 00000h, 00000h, 00000h ; Entry 1e0h - unused. + dw 00000h, 00000h, 00000h, 00000h ; Entry 1e8h - unused. + dw 00000h, 00000h, 00000h, 00000h ; Entry 1f0h - unused. + dw 00000h, 00000h, 00000h, 00000h ; Entry 1f8h - unused. +%endmacro + + ; + ; 100h..1f8h - Ring-0 selectors. + ; + BS3_GDT_RING_X_SELECTORS 0 + + ; + ; 200h..2f8h - Ring-1 selectors. + ; + BS3_GDT_RING_X_SELECTORS 1 + + ; + ; 300h..3f8h - Ring-2 selectors. + ; + BS3_GDT_RING_X_SELECTORS 2 + + ; + ; 400h..4f8h - Ring-3 selectors. + ; + BS3_GDT_RING_X_SELECTORS 3 + + ; + ; 500..5f8h - Named spare GDT entries. + ; +BS3GdtAssertOffset 0500h +BS3_GLOBAL_DATA Bs3GdteSpare00, 8 ; Entry 500h + dq 0 +BS3_GLOBAL_DATA Bs3GdteSpare01, 8 ; Entry 508h + dq 0 +BS3_GLOBAL_DATA Bs3GdteSpare02, 8 ; Entry 510h + dq 0 +BS3_GLOBAL_DATA Bs3GdteSpare03, 8 ; Entry 518h + dq 0 +BS3_GLOBAL_DATA Bs3GdteSpare04, 8 ; Entry 520h + dq 0 +BS3_GLOBAL_DATA Bs3GdteSpare05, 8 ; Entry 528h + dq 0 +BS3_GLOBAL_DATA Bs3GdteSpare06, 8 ; Entry 530h + dq 0 +BS3_GLOBAL_DATA Bs3GdteSpare07, 8 ; Entry 538h + dq 0 +BS3_GLOBAL_DATA Bs3GdteSpare08, 8 ; Entry 540h + dq 0 +BS3_GLOBAL_DATA Bs3GdteSpare09, 8 ; Entry 548h + dq 0 +BS3_GLOBAL_DATA Bs3GdteSpare0a, 8 ; Entry 550h + dq 0 +BS3_GLOBAL_DATA Bs3GdteSpare0b, 8 ; Entry 558h + dq 0 +BS3_GLOBAL_DATA Bs3GdteSpare0c, 8 ; Entry 560h + dq 0 +BS3_GLOBAL_DATA Bs3GdteSpare0d, 8 ; Entry 568h + dq 0 +BS3_GLOBAL_DATA Bs3GdteSpare0e, 8 ; Entry 570h + dq 0 +BS3_GLOBAL_DATA Bs3GdteSpare0f, 8 ; Entry 578h + dq 0 +BS3_GLOBAL_DATA Bs3GdteSpare10, 8 ; Entry 580h + dq 0 +BS3_GLOBAL_DATA Bs3GdteSpare11, 8 ; Entry 588h + dq 0 +BS3_GLOBAL_DATA Bs3GdteSpare12, 8 ; Entry 590h + dq 0 +BS3_GLOBAL_DATA Bs3GdteSpare13, 8 ; Entry 598h + dq 0 +BS3_GLOBAL_DATA Bs3GdteSpare14, 8 ; Entry 5a0h + dq 0 +BS3_GLOBAL_DATA Bs3GdteSpare15, 8 ; Entry 5a8h + dq 0 +BS3_GLOBAL_DATA Bs3GdteSpare16, 8 ; Entry 5b0h + dq 0 +BS3_GLOBAL_DATA Bs3GdteSpare17, 8 ; Entry 5b8h + dq 0 +BS3_GLOBAL_DATA Bs3GdteSpare18, 8 ; Entry 5c0h + dq 0 +BS3_GLOBAL_DATA Bs3GdteSpare19, 8 ; Entry 5c8h + dq 0 +BS3_GLOBAL_DATA Bs3GdteSpare1a, 8 ; Entry 5d0h + dq 0 +BS3_GLOBAL_DATA Bs3GdteSpare1b, 8 ; Entry 5d8h + dq 0 +BS3_GLOBAL_DATA Bs3GdteSpare1c, 8 ; Entry 5e0h + dq 0 +BS3_GLOBAL_DATA Bs3GdteSpare1d, 8 ; Entry 5e8h + dq 0 +BS3_GLOBAL_DATA Bs3GdteSpare1e, 8 ; Entry 5f0h + dq 0 +BS3_GLOBAL_DATA Bs3GdteSpare1f, 8 ; Entry 5f8h + dq 0 + + ; + ; 600..df8h - 16-bit DPL=3 data segments covering the first 16MB of memory. + ; +BS3_GLOBAL_DATA Bs3GdteTiled, 8 ; Entry 600h +%assign u8HighBase 0 +%rep 256 + dw 0ffffh, 00000h, 0f300h | u8HighBase, 00000h +%assign u8HighBase u8HighBase + 1 +%endrep + ; + ; e00..ff8h - Free GDTEs. + ; +BS3GdtAssertOffset 0e00h +BS3_GLOBAL_DATA Bs3GdteFreePart1, 200h + times 200h db 0 + + ; + ; 1000h - the real mode segment number for BS3TEXT16. DPL=0, BASE=0x10000h, conforming, exec, read. + ; +BS3GdtAssertOffset 01000h +BS3_GLOBAL_DATA Bs3Gdte_CODE16, 8h + dw 0ffffh, 00000h, 09f01h, 00000h + + ; + ; 1008..17f8h - Free GDTEs. + ; +BS3GdtAssertOffset 01008h +BS3_GLOBAL_DATA Bs3GdteFreePart2, 07f8h + times 07f8h db 0 + + ; + ; 1800..1ff8h - 16-bit DPL=0 data/stack segments covering the first 16MB of memory. + ; +BS3GdtAssertOffset 01800h +BS3_GLOBAL_DATA Bs3GdteTiledR0, 8 ; Entry 1800h +%assign u8HighBase 0 +%rep 256 + dw 0ffffh, 00000h, 09300h | u8HighBase, 00000h +%assign u8HighBase u8HighBase + 1 +%endrep + + ; + ; 2000h - the real mode segment number for BS3SYSTEM. DPL=3. BASE=0x20000h + ; +BS3GdtAssertOffset 02000h +BS3_GLOBAL_DATA Bs3Gdte_SYSTEM16, 8h + dw 0ffffh, 00000h, 0f302h, 00000h + + ; + ; 2008..28f8h - Free GDTEs. + ; +BS3_GLOBAL_DATA Bs3GdteFreePart3, 08f8h + times 08f8h db 0 + + ; + ; 2900h - the real mode segment number for BS3KIT_GRPNM_DATA16. DPL=3. BASE=0x29000h + ; +BS3GdtAssertOffset 02900h +BS3_GLOBAL_DATA Bs3Gdte_DATA16, 8h + dw 0ffffh, 09000h, 0f302h, 00000h + + ; + ; 2908..2f98h - Free GDTEs. + ; +BS3GdtAssertOffset 02908h +BS3_GLOBAL_DATA Bs3GdteFreePart4, 698h + times 698h db 0 + + ; + ; 2be0..2fe0h - 8 spare entries preceeding the test page which we're free + ; to mess with page table protection. + ; +BS3GdtAssertOffset 02fa0h +BS3_GLOBAL_DATA Bs3GdtePreTestPage08, 8 + dq 0 +BS3_GLOBAL_DATA Bs3GdtePreTestPage07, 8 + dq 0 +BS3_GLOBAL_DATA Bs3GdtePreTestPage06, 8 + dq 0 +BS3_GLOBAL_DATA Bs3GdtePreTestPage05, 8 + dq 0 +BS3_GLOBAL_DATA Bs3GdtePreTestPage04, 8 + dq 0 +BS3_GLOBAL_DATA Bs3GdtePreTestPage03, 8 + dq 0 +BS3_GLOBAL_DATA Bs3GdtePreTestPage02, 8 + dq 0 +BS3_GLOBAL_DATA Bs3GdtePreTestPage01, 8 + dq 0 + + ; + ; 2fe0..3fd8h - 16 Test entries at the start of the page where we're free + ; to mess with page table protection. + ; +BS3GdtAssertOffset 02fe0h +AssertCompile(($ - $$) == 0x3000) +BS3_GLOBAL_DATA Bs3GdteTestPage, 0 +BS3_GLOBAL_DATA Bs3GdteTestPage00, 8 + dq 0 +BS3_GLOBAL_DATA Bs3GdteTestPage01, 8 + dq 0 +BS3_GLOBAL_DATA Bs3GdteTestPage02, 8 + dq 0 +BS3_GLOBAL_DATA Bs3GdteTestPage03, 8 + dq 0 +BS3_GLOBAL_DATA Bs3GdteTestPage04, 8 + dq 0 +BS3_GLOBAL_DATA Bs3GdteTestPage05, 8 + dq 0 +BS3_GLOBAL_DATA Bs3GdteTestPage06, 8 + dq 0 +BS3_GLOBAL_DATA Bs3GdteTestPage07, 8 + dq 0 +BS3GdtAssertOffset 3020h + times 0fb8h db 0 +BS3GdtAssertOffset 3fd8h +BS3_GLOBAL_DATA Bs3GdtEnd, 0 + db 10, 13, 'GDTE', 10, 13 ; alignment padding (next address on 16 byte boundrary). +BS3GdtAssertOffset 4000h - 20h ; We're at a page boundrary here! Only GDT and eyecatchers on page starting at 3000h! +AssertCompile(($ - $$) == 0x4000) + + + +;; +; The 16-bit TSS. +; +BS3_GLOBAL_DATA Bs3Tss16, X86TSS16_size +istruc X86TSS16 + at X86TSS16.selPrev, dw 0 + at X86TSS16.sp0, dw BS3_ADDR_STACK_R0 + at X86TSS16.ss0, dw BS3_SEL_R0_SS16 + at X86TSS16.sp1, dw BS3_ADDR_STACK_R1 + at X86TSS16.ss1, dw BS3_SEL_R1_SS16 + at X86TSS16.sp2, dw BS3_ADDR_STACK_R2 + at X86TSS16.ss2, dw BS3_SEL_R2_SS16 + at X86TSS16.ip, dw 0 + at X86TSS16.flags, dw 0 + at X86TSS16.ax, dw 0 + at X86TSS16.cx, dw 0 + at X86TSS16.dx, dw 0 + at X86TSS16.bx, dw 0 + at X86TSS16.sp, dw 0 + at X86TSS16.bp, dw 0 + at X86TSS16.si, dw 0 + at X86TSS16.di, dw 0 + at X86TSS16.es, dw 0 + at X86TSS16.cs, dw 0 + at X86TSS16.ss, dw 0 + at X86TSS16.ds, dw 0 + at X86TSS16.selLdt, dw 0 +iend + +;; +; 16-bit TSS for (trying to) handle double faults. +BS3_GLOBAL_DATA Bs3Tss16DoubleFault, X86TSS16_size +istruc X86TSS16 + at X86TSS16.selPrev, dw 0 + at X86TSS16.sp0, dw BS3_ADDR_STACK_R0 + at X86TSS16.ss0, dw BS3_SEL_R0_SS16 + at X86TSS16.sp1, dw BS3_ADDR_STACK_R1 + at X86TSS16.ss1, dw BS3_SEL_R1_SS16 + at X86TSS16.sp2, dw BS3_ADDR_STACK_R2 + at X86TSS16.ss2, dw BS3_SEL_R2_SS16 + at X86TSS16.ip, dw 0 ; Will be filled in by routine setting up 16-bit mode w/ traps++. + at X86TSS16.flags, dw X86_EFL_1 + at X86TSS16.ax, dw 0 + at X86TSS16.cx, dw 0 + at X86TSS16.dx, dw 0 + at X86TSS16.bx, dw 0 + at X86TSS16.sp, dw BS3_ADDR_STACK_R0_IST1 + at X86TSS16.bp, dw 0 + at X86TSS16.si, dw 0 + at X86TSS16.di, dw 0 + at X86TSS16.es, dw BS3_SEL_R0_DS16 + at X86TSS16.cs, dw BS3_SEL_R0_CS16 + at X86TSS16.ss, dw BS3_SEL_R0_SS16 + at X86TSS16.ds, dw BS3_SEL_R0_DS16 + at X86TSS16.selLdt, dw 0 +iend + +;; +; A spare 16-bit TSS for testcases to play around with. +BS3_GLOBAL_DATA Bs3Tss16Spare0, X86TSS16_size +istruc X86TSS16 + at X86TSS16.selPrev, dw 0 + at X86TSS16.sp0, dw BS3_ADDR_STACK_R0 + at X86TSS16.ss0, dw BS3_SEL_R0_SS16 + at X86TSS16.sp1, dw BS3_ADDR_STACK_R1 + at X86TSS16.ss1, dw BS3_SEL_R1_SS16 + at X86TSS16.sp2, dw BS3_ADDR_STACK_R2 + at X86TSS16.ss2, dw BS3_SEL_R2_SS16 + at X86TSS16.ip, dw 0 ; Will be filled in by routine setting up 16-bit mode w/ traps++. + at X86TSS16.flags, dw X86_EFL_1 + at X86TSS16.ax, dw 0 + at X86TSS16.cx, dw 0 + at X86TSS16.dx, dw 0 + at X86TSS16.bx, dw 0 + at X86TSS16.sp, dw BS3_ADDR_STACK_R0_IST2 + at X86TSS16.bp, dw 0 + at X86TSS16.si, dw 0 + at X86TSS16.di, dw 0 + at X86TSS16.es, dw BS3_SEL_R0_DS16 + at X86TSS16.cs, dw BS3_SEL_R0_CS16 + at X86TSS16.ss, dw BS3_SEL_R0_SS16 + at X86TSS16.ds, dw BS3_SEL_R0_DS16 + at X86TSS16.selLdt, dw 0 +iend + +;; +; A spare 16-bit TSS for testcases to play around with. +BS3_GLOBAL_DATA Bs3Tss16Spare1, X86TSS16_size +istruc X86TSS16 + at X86TSS16.selPrev, dw 0 + at X86TSS16.sp0, dw BS3_ADDR_STACK_R0 + at X86TSS16.ss0, dw BS3_SEL_R0_SS16 + at X86TSS16.sp1, dw BS3_ADDR_STACK_R1 + at X86TSS16.ss1, dw BS3_SEL_R1_SS16 + at X86TSS16.sp2, dw BS3_ADDR_STACK_R2 + at X86TSS16.ss2, dw BS3_SEL_R2_SS16 + at X86TSS16.ip, dw 0 ; Will be filled in by routine setting up 16-bit mode w/ traps++. + at X86TSS16.flags, dw X86_EFL_1 + at X86TSS16.ax, dw 0 + at X86TSS16.cx, dw 0 + at X86TSS16.dx, dw 0 + at X86TSS16.bx, dw 0 + at X86TSS16.sp, dw BS3_ADDR_STACK_R0_IST4 + at X86TSS16.bp, dw 0 + at X86TSS16.si, dw 0 + at X86TSS16.di, dw 0 + at X86TSS16.es, dw BS3_SEL_R0_DS16 + at X86TSS16.cs, dw BS3_SEL_R0_CS16 + at X86TSS16.ss, dw BS3_SEL_R0_SS16 + at X86TSS16.ds, dw BS3_SEL_R0_DS16 + at X86TSS16.selLdt, dw 0 +iend + + +;; +; The 32-bit TSS. +; +BS3_GLOBAL_DATA Bs3Tss32, X86TSS32_size +istruc X86TSS32 + at X86TSS32.selPrev, dw 0 + at X86TSS32.padding1, dw 0 + at X86TSS32.esp0, dd BS3_ADDR_STACK_R0 + at X86TSS32.ss0, dw BS3_SEL_R0_SS32 + at X86TSS32.padding_ss0, dw 1 + at X86TSS32.esp1, dd 1 + at X86TSS32.ss1, dw BS3_SEL_R1_SS32 + at X86TSS32.padding_ss1, dw 1 + at X86TSS32.esp2, dd 1 + at X86TSS32.ss2, dw BS3_SEL_R2_SS32 + at X86TSS32.padding_ss2, dw 1 + at X86TSS32.cr3, dd 0 + at X86TSS32.eip, dd 0 + at X86TSS32.eflags, dd X86_EFL_1 + at X86TSS32.eax, dd 0 + at X86TSS32.ecx, dd 0 + at X86TSS32.edx, dd 0 + at X86TSS32.ebx, dd 0 + at X86TSS32.esp, dd 0 + at X86TSS32.ebp, dd 0 + at X86TSS32.esi, dd 0 + at X86TSS32.edi, dd 0 + at X86TSS32.es, dw 0 + at X86TSS32.padding_es, dw 0 + at X86TSS32.cs, dw 0 + at X86TSS32.padding_cs, dw 0 + at X86TSS32.ss, dw 0 + at X86TSS32.padding_ss, dw 0 + at X86TSS32.ds, dw 0 + at X86TSS32.padding_ds, dw 0 + at X86TSS32.fs, dw 0 + at X86TSS32.padding_fs, dw 0 + at X86TSS32.gs, dw 0 + at X86TSS32.padding_gs, dw 0 + at X86TSS32.selLdt, dw 0 + at X86TSS32.padding_ldt, dw 0 + at X86TSS32.fDebugTrap, dw 0 + at X86TSS32.offIoBitmap, dw (BS3_DATA_NM(Bs3SharedIobp) - BS3_DATA_NM(Bs3Tss32WithIopb)) +iend + +;; +; The 32-bit TSS for handling double faults. +BS3_GLOBAL_DATA Bs3Tss32DoubleFault, X86TSS32_size +istruc X86TSS32 + at X86TSS32.selPrev, dw 0 + at X86TSS32.padding1, dw 0 + at X86TSS32.esp0, dd BS3_ADDR_STACK_R0 + at X86TSS32.ss0, dw BS3_SEL_R0_SS32 + at X86TSS32.padding_ss0, dw 1 + at X86TSS32.esp1, dd 1 + at X86TSS32.ss1, dw BS3_SEL_R1_SS32 + at X86TSS32.padding_ss1, dw 1 + at X86TSS32.esp2, dd 1 + at X86TSS32.ss2, dw BS3_SEL_R2_SS32 + at X86TSS32.padding_ss2, dw 1 + at X86TSS32.cr3, dd 0 ; Will be filled in by routine setting up paged 32-bit mode w/ traps++. + at X86TSS32.eip, dd 0 ; Will be filled in by routine setting up 32-bit mode w/ traps++. + at X86TSS32.eflags, dd X86_EFL_1 + at X86TSS32.eax, dd 0 + at X86TSS32.ecx, dd 0 + at X86TSS32.edx, dd 0 + at X86TSS32.ebx, dd 0 + at X86TSS32.esp, dd BS3_ADDR_STACK_R0_IST1 + at X86TSS32.ebp, dd 0 + at X86TSS32.esi, dd 0 + at X86TSS32.edi, dd 0 + at X86TSS32.es, dw BS3_SEL_R0_DS32 + at X86TSS32.padding_es, dw 0 + at X86TSS32.cs, dw BS3_SEL_R0_CS32 + at X86TSS32.padding_cs, dw 0 + at X86TSS32.ss, dw BS3_SEL_R0_SS32 + at X86TSS32.padding_ss, dw 0 + at X86TSS32.ds, dw BS3_SEL_R0_DS32 + at X86TSS32.padding_ds, dw 0 + at X86TSS32.fs, dw BS3_SEL_R0_DS32 + at X86TSS32.padding_fs, dw 0 + at X86TSS32.gs, dw BS3_SEL_R0_DS32 + at X86TSS32.padding_gs, dw 0 + at X86TSS32.selLdt, dw 0 + at X86TSS32.padding_ldt, dw 0 + at X86TSS32.fDebugTrap, dw 0 + at X86TSS32.offIoBitmap, dw 0 +iend + +;; +; A spare 32-bit TSS testcases to play around with. +BS3_GLOBAL_DATA Bs3Tss32Spare0, X86TSS32_size +istruc X86TSS32 + at X86TSS32.selPrev, dw 0 + at X86TSS32.padding1, dw 0 + at X86TSS32.esp0, dd BS3_ADDR_STACK_R0 + at X86TSS32.ss0, dw BS3_SEL_R0_SS32 + at X86TSS32.padding_ss0, dw 1 + at X86TSS32.esp1, dd 1 + at X86TSS32.ss1, dw BS3_SEL_R1_SS32 + at X86TSS32.padding_ss1, dw 1 + at X86TSS32.esp2, dd 1 + at X86TSS32.ss2, dw BS3_SEL_R2_SS32 + at X86TSS32.padding_ss2, dw 1 + at X86TSS32.cr3, dd 0 ; Will be filled in by routine setting up paged 32-bit mode w/ traps++. + at X86TSS32.eip, dd 0 ; Will be filled in by routine setting up 32-bit mode w/ traps++. + at X86TSS32.eflags, dd X86_EFL_1 + at X86TSS32.eax, dd 0 + at X86TSS32.ecx, dd 0 + at X86TSS32.edx, dd 0 + at X86TSS32.ebx, dd 0 + at X86TSS32.esp, dd BS3_ADDR_STACK_R0_IST2 + at X86TSS32.ebp, dd 0 + at X86TSS32.esi, dd 0 + at X86TSS32.edi, dd 0 + at X86TSS32.es, dw BS3_SEL_R0_DS32 + at X86TSS32.padding_es, dw 0 + at X86TSS32.cs, dw BS3_SEL_R0_CS32 + at X86TSS32.padding_cs, dw 0 + at X86TSS32.ss, dw BS3_SEL_R0_SS32 + at X86TSS32.padding_ss, dw 0 + at X86TSS32.ds, dw BS3_SEL_R0_DS32 + at X86TSS32.padding_ds, dw 0 + at X86TSS32.fs, dw BS3_SEL_R0_DS32 + at X86TSS32.padding_fs, dw 0 + at X86TSS32.gs, dw BS3_SEL_R0_DS32 + at X86TSS32.padding_gs, dw 0 + at X86TSS32.selLdt, dw 0 + at X86TSS32.padding_ldt, dw 0 + at X86TSS32.fDebugTrap, dw 0 + at X86TSS32.offIoBitmap, dw 0 +iend + +;; +; A spare 32-bit TSS testcases to play around with. +BS3_GLOBAL_DATA Bs3Tss32Spare1, X86TSS32_size +istruc X86TSS32 + at X86TSS32.selPrev, dw 0 + at X86TSS32.padding1, dw 0 + at X86TSS32.esp0, dd BS3_ADDR_STACK_R0 + at X86TSS32.ss0, dw BS3_SEL_R0_SS32 + at X86TSS32.padding_ss0, dw 1 + at X86TSS32.esp1, dd 1 + at X86TSS32.ss1, dw BS3_SEL_R1_SS32 + at X86TSS32.padding_ss1, dw 1 + at X86TSS32.esp2, dd 1 + at X86TSS32.ss2, dw BS3_SEL_R2_SS32 + at X86TSS32.padding_ss2, dw 1 + at X86TSS32.cr3, dd 0 ; Will be filled in by routine setting up paged 32-bit mode w/ traps++. + at X86TSS32.eip, dd 0 ; Will be filled in by routine setting up 32-bit mode w/ traps++. + at X86TSS32.eflags, dd X86_EFL_1 + at X86TSS32.eax, dd 0 + at X86TSS32.ecx, dd 0 + at X86TSS32.edx, dd 0 + at X86TSS32.ebx, dd 0 + at X86TSS32.esp, dd BS3_ADDR_STACK_R0_IST4 + at X86TSS32.ebp, dd 0 + at X86TSS32.esi, dd 0 + at X86TSS32.edi, dd 0 + at X86TSS32.es, dw BS3_SEL_R0_DS32 + at X86TSS32.padding_es, dw 0 + at X86TSS32.cs, dw BS3_SEL_R0_CS32 + at X86TSS32.padding_cs, dw 0 + at X86TSS32.ss, dw BS3_SEL_R0_SS32 + at X86TSS32.padding_ss, dw 0 + at X86TSS32.ds, dw BS3_SEL_R0_DS32 + at X86TSS32.padding_ds, dw 0 + at X86TSS32.fs, dw BS3_SEL_R0_DS32 + at X86TSS32.padding_fs, dw 0 + at X86TSS32.gs, dw BS3_SEL_R0_DS32 + at X86TSS32.padding_gs, dw 0 + at X86TSS32.selLdt, dw 0 + at X86TSS32.padding_ldt, dw 0 + at X86TSS32.fDebugTrap, dw 0 + at X86TSS32.offIoBitmap, dw 0 +iend + + + +;; +; 64-bit TSS +BS3_GLOBAL_DATA Bs3Tss64, X86TSS64_size +istruc X86TSS64 + at X86TSS64.u32Reserved, dd 0 + at X86TSS64.rsp0, dq BS3_ADDR_STACK_R0 + at X86TSS64.rsp1, dq BS3_ADDR_STACK_R1 + at X86TSS64.rsp2, dq BS3_ADDR_STACK_R2 + at X86TSS64.u32Reserved2, dd 0 + at X86TSS64.ist1, dq BS3_ADDR_STACK_R0_IST1 + at X86TSS64.ist2, dq BS3_ADDR_STACK_R0_IST2 + at X86TSS64.ist3, dq BS3_ADDR_STACK_R0_IST3 + at X86TSS64.ist4, dq BS3_ADDR_STACK_R0_IST4 + at X86TSS64.ist5, dq BS3_ADDR_STACK_R0_IST5 + at X86TSS64.ist6, dq BS3_ADDR_STACK_R0_IST6 + at X86TSS64.ist7, dq BS3_ADDR_STACK_R0_IST7 + at X86TSS64.u16Reserved, dw 0 + at X86TSS64.offIoBitmap, dw 0 +iend + +;; +; A spare TSS for testcases to play around with. +BS3_GLOBAL_DATA Bs3Tss64Spare0, X86TSS64_size +istruc X86TSS64 + at X86TSS64.u32Reserved, dd 0 + at X86TSS64.rsp0, dq BS3_ADDR_STACK_R0 + at X86TSS64.rsp1, dq BS3_ADDR_STACK_R1 + at X86TSS64.rsp2, dq BS3_ADDR_STACK_R2 + at X86TSS64.u32Reserved2, dd 0 + at X86TSS64.ist1, dq BS3_ADDR_STACK_R0_IST1 + at X86TSS64.ist2, dq BS3_ADDR_STACK_R0_IST2 + at X86TSS64.ist3, dq BS3_ADDR_STACK_R0_IST3 + at X86TSS64.ist4, dq BS3_ADDR_STACK_R0_IST4 + at X86TSS64.ist5, dq BS3_ADDR_STACK_R0_IST5 + at X86TSS64.ist6, dq BS3_ADDR_STACK_R0_IST6 + at X86TSS64.ist7, dq BS3_ADDR_STACK_R0_IST7 + at X86TSS64.u16Reserved, dw 0 + at X86TSS64.offIoBitmap, dw 0 +iend + +;; +; A spare TSS for testcases to play around with. +BS3_GLOBAL_DATA Bs3Tss64Spare1, X86TSS64_size +istruc X86TSS64 + at X86TSS64.u32Reserved, dd 0 + at X86TSS64.rsp0, dq BS3_ADDR_STACK_R0 + at X86TSS64.rsp1, dq BS3_ADDR_STACK_R1 + at X86TSS64.rsp2, dq BS3_ADDR_STACK_R2 + at X86TSS64.u32Reserved2, dd 0 + at X86TSS64.ist1, dq BS3_ADDR_STACK_R0_IST1 + at X86TSS64.ist2, dq BS3_ADDR_STACK_R0_IST2 + at X86TSS64.ist3, dq BS3_ADDR_STACK_R0_IST3 + at X86TSS64.ist4, dq BS3_ADDR_STACK_R0_IST4 + at X86TSS64.ist5, dq BS3_ADDR_STACK_R0_IST5 + at X86TSS64.ist6, dq BS3_ADDR_STACK_R0_IST6 + at X86TSS64.ist7, dq BS3_ADDR_STACK_R0_IST7 + at X86TSS64.u16Reserved, dw 0 + at X86TSS64.offIoBitmap, dw 0 +iend + + + +;; +; 64-bit TSS sharing an I/O permission bitmap (Bs3SharedIobp) with a 32-bit TSS. +; +BS3_GLOBAL_DATA Bs3Tss64WithIopb, X86TSS64_size +istruc X86TSS64 + at X86TSS64.u32Reserved, dd 0 + at X86TSS64.rsp0, dq BS3_ADDR_STACK_R0 + at X86TSS64.rsp1, dq BS3_ADDR_STACK_R1 + at X86TSS64.rsp2, dq BS3_ADDR_STACK_R2 + at X86TSS64.u32Reserved2, dd 0 + at X86TSS64.ist1, dq BS3_ADDR_STACK_R0_IST1 + at X86TSS64.ist2, dq BS3_ADDR_STACK_R0_IST2 + at X86TSS64.ist3, dq BS3_ADDR_STACK_R0_IST3 + at X86TSS64.ist4, dq BS3_ADDR_STACK_R0_IST4 + at X86TSS64.ist5, dq BS3_ADDR_STACK_R0_IST5 + at X86TSS64.ist6, dq BS3_ADDR_STACK_R0_IST6 + at X86TSS64.ist7, dq BS3_ADDR_STACK_R0_IST7 + at X86TSS64.u16Reserved, dw 0 + at X86TSS64.offIoBitmap, dw (BS3_DATA_NM(Bs3SharedIobp) - BS3_DATA_NM(Bs3Tss64WithIopb)) +iend + +;; +; 32-bit TSS sharing an I/O permission bitmap (Bs3SharedIobp) with a 64-bit TSS, +; and sporting an interrupt redirection bitmap (Bs3SharedIntRedirBm). +BS3_GLOBAL_DATA Bs3Tss32WithIopb, X86TSS32_size +istruc X86TSS32 + at X86TSS32.selPrev, dw 0 + at X86TSS32.padding1, dw 0 + at X86TSS32.esp0, dd BS3_ADDR_STACK_R0 + at X86TSS32.ss0, dw BS3_SEL_R0_SS32 + at X86TSS32.padding_ss0, dw 1 + at X86TSS32.esp1, dd 1 + at X86TSS32.ss1, dw BS3_SEL_R1_SS32 + at X86TSS32.padding_ss1, dw 1 + at X86TSS32.esp2, dd 1 + at X86TSS32.ss2, dw BS3_SEL_R2_SS32 + at X86TSS32.padding_ss2, dw 1 + at X86TSS32.cr3, dd 0 ; Will be filled in by routine setting up paged 32-bit mode w/ traps++. + at X86TSS32.eip, dd 0 ; Will be filled in by routine setting up 32-bit mode w/ traps++. + at X86TSS32.eflags, dd X86_EFL_1 + at X86TSS32.eax, dd 0 + at X86TSS32.ecx, dd 0 + at X86TSS32.edx, dd 0 + at X86TSS32.ebx, dd 0 + at X86TSS32.esp, dd 0 + at X86TSS32.ebp, dd 0 + at X86TSS32.esi, dd 0 + at X86TSS32.edi, dd 0 + at X86TSS32.es, dw 0 + at X86TSS32.padding_es, dw 0 + at X86TSS32.cs, dw 0 + at X86TSS32.padding_cs, dw 0 + at X86TSS32.ss, dw 0 + at X86TSS32.padding_ss, dw 0 + at X86TSS32.ds, dw 0 + at X86TSS32.padding_ds, dw 0 + at X86TSS32.fs, dw 0 + at X86TSS32.padding_fs, dw 0 + at X86TSS32.gs, dw 0 + at X86TSS32.padding_gs, dw 0 + at X86TSS32.selLdt, dw 0 + at X86TSS32.padding_ldt, dw 0 + at X86TSS32.fDebugTrap, dw 0 + at X86TSS32.offIoBitmap, dw (BS3_DATA_NM(Bs3SharedIobp) - BS3_DATA_NM(Bs3Tss32WithIopb)) +iend + +; +; We insert 6 bytes before the interrupt redirection bitmap just to make sure +; we've all got the same idea about where it starts (i.e. 32 bytes before IOBP). +; + times 6 db 0ffh + +;; +; Interrupt redirection bitmap (used by 32-bit TSS). +BS3_GLOBAL_DATA Bs3SharedIntRedirBm, 32 + times 32 db 00h + +;; +; Shared I/O permission bitmap used both by Bs3Tss64WithIopb and Bs3Tss32WithIopb. +BS3_GLOBAL_DATA Bs3SharedIobp, 8192+2 + times 8192+2 db 0ffh +BS3_GLOBAL_DATA Bs3SharedIobpEnd, 0 + + +align 128 + +;; +; 16-bit IDT. +; This requires manual setup by code fielding traps, so we'll just reserve the +; memory here. +; +BS3_GLOBAL_DATA Bs3Idt16, 256*8 + times 256 dq 0 + +;; +; 32-bit IDT. +; This requires manual setup by code fielding traps, so we'll just reserve the +; memory here. +; +BS3_GLOBAL_DATA Bs3Idt32, 256*8 + times 256 dq 0 + +;; +; 64-bit IDT. +; This requires manual setup by code fielding traps, so we'll just reserve the +; memory here. +; +BS3_GLOBAL_DATA Bs3Idt64, 256*16 + times 256 dq 0, 0 + + + times 6 db 0 ; Pad the first LIDT correctly. + +;; +; LIDT structure for the 16-bit IDT (8-byte aligned on offset). +BS3_GLOBAL_DATA Bs3Lidt_Idt16, 2+8 + dw 256*8 - 1 ; limit + dw BS3_SYSTEM16_BASE_LOW(Bs3Idt16) ; low offset + dw (BS3_ADDR_BS3SYSTEM16 >> 16) ; high offset + dd 0 ; top32 offset + + times 4 db 0 ; padding the start of the next + +;; +; LIDT structure for the 32-bit IDT (8-byte aligned on offset). +BS3_GLOBAL_DATA Bs3Lidt_Idt32, 2+8 + dw 256*8 - 1 ; limit + dw BS3_SYSTEM16_BASE_LOW(Bs3Idt32) ; low offset + dw (BS3_ADDR_BS3SYSTEM16 >> 16) ; high offset + dd 0 ; top32 offset + + times 4 db 0 ; padding the start of the next + +;; +; LIDT structure for the 64-bit IDT (8-byte aligned on offset). +BS3_GLOBAL_DATA Bs3Lidt_Idt64, 2+8 + dw 256*16 - 1 ; limit + dw BS3_SYSTEM16_BASE_LOW(Bs3Idt64) ; low offset + dw (BS3_ADDR_BS3SYSTEM16 >> 16) ; high offset + dd 0 ; top32 offset + + times 4 db 0 ; padding the start of the next + +;; +; LIDT structure for the real mode IVT at address 0x00000000 (8-byte aligned on offset). +BS3_GLOBAL_DATA Bs3Lidt_Ivt, 2+8 + dw 0ffffh ; limit + dw 0 ; low offset + dw 0 ; high offset + dd 0 ; top32 offset + + times 4 db 0 ; padding the start of the next + +;; +; LGDT structure for the current GDT (8-byte aligned on offset). +BS3_GLOBAL_DATA Bs3Lgdt_Gdt, 2+8 + dw BS3_DATA_NM(Bs3GdtEnd) - BS3_DATA_NM(Bs3Gdt) - 1 ; limit + dw BS3_SYSTEM16_BASE_LOW(Bs3Gdt) ; low offset + dw (BS3_ADDR_BS3SYSTEM16 >> 16) ; high offset + dd 0 ; top32 offset + +;; +; LGDT structure for the default GDT (8-byte aligned on offset). +; This must not be modified, whereas Bs3Lgdt_Gdt can be modified by the user. +BS3_GLOBAL_DATA Bs3LgdtDef_Gdt, 2+8 + dw BS3_DATA_NM(Bs3GdtEnd) - BS3_DATA_NM(Bs3Gdt) - 1 ; limit + dw BS3_SYSTEM16_BASE_LOW(Bs3Gdt) ; low offset + dw (BS3_ADDR_BS3SYSTEM16 >> 16) ; high offset + dd 0 ; top32 offset + + + +align 16 +;; +; LDT filling up the rest of the segment. +; +; Currently this starts at 0x84e0, which leaves us with 0xb20 bytes. We'll use +; the last 32 of those for an eye catcher. +; +BS3_GLOBAL_DATA Bs3Ldt, 0b20h - 32 + times (0b20h - 32) db 0 +BS3_GLOBAL_DATA Bs3LdtEnd, 0 + db 10, 13, 'eye-catcher: SYSTEM16 END', 10, 13, 0, 0, 0 ; 32 bytes long + +; +; Check the segment size. +; +%ifndef KBUILD_GENERATING_MAKEFILE_DEPENDENCIES + %if ($ - $$) != 09000h + %assign offActual ($ - $$) + %error "Bad BS3SYSTEM16 segment size: " %+ offActual %+ ", expected 0x9000 (36864)" + %endif +%endif + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-wc16-I4D.asm b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-wc16-I4D.asm new file mode 100644 index 00000000..bd7711fc --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-wc16-I4D.asm @@ -0,0 +1,70 @@ +; $Id: bs3-wc16-I4D.asm $ +;; @file +; BS3Kit - 16-bit Watcom C/C++, 32-bit signed integer division. +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + +%include "bs3kit-template-header.mac" + + +;; +; 32-bit signed integer division. +; +; @returns DX:AX quotient, CX:BX remainder. +; @param DX:AX Dividend. +; @param CX:BX Divisor +; +; @uses Nothing. +; +global $_?I4D +$_?I4D: +;; @todo no idea if we're getting the negative division stuff right here according to what watcom expectes... +extern TODO_NEGATIVE_SIGNED_DIVISION + ; Move dividend into EDX:EAX + shl eax, 10h + mov ax, dx + sar dx, 0fh + movsx edx, dx + + ; Move divisor into ebx. + shl ebx, 10h + mov bx, cx + + ; Do it! + idiv ebx + + ; Reminder in to CX:BX + mov bx, dx + shr edx, 10h + mov cx, dx + + ; Quotient into DX:AX + mov edx, eax + shr edx, 10h + +%ifdef ASM_MODEL_FAR_CODE + retf +%else + ret +%endif + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-wc16-I8DQ.asm b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-wc16-I8DQ.asm new file mode 100644 index 00000000..a62a0895 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-wc16-I8DQ.asm @@ -0,0 +1,111 @@ +; $Id: bs3-wc16-I8DQ.asm $ +;; @file +; BS3Kit - 16-bit Watcom C/C++, 64-bit unsigned integer division. +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + +%include "bs3kit-template-header.mac" + +BS3_EXTERN_CMN Bs3Int64Div + + +;; +; 64-bit unsigned integer division, SS variant. +; +; @returns ax:bx:cx:dx quotient. (AX is the most significant, DX the least) +; @param ax:bx:cx:dx Dividend. +; @param [ss:si] Divisor +; +; @uses Nothing. +; +global $_?I8DQ +$_?I8DQ: + push es + push ss + pop es +%ifdef ASM_MODEL_FAR_CODE + push cs +%endif + call $_?I8DQE + pop es +%ifdef ASM_MODEL_FAR_CODE + retf +%else + ret +%endif + +;; +; 64-bit unsigned integer division, ES variant. +; +; @returns ax:bx:cx:dx quotient. (AX is the most significant, DX the least) +; @param ax:bx:cx:dx Dividend. +; @param [es:si] Divisor +; +; @uses Nothing. +; +global $_?I8DQE +$_?I8DQE: + push ds + push es + + ; + ; Convert to a C __cdecl call - not doing this in assembly. + ; + + ; Set up a frame of sorts, allocating 16 bytes for the result buffer. + push bp + sub sp, 10h + mov bp, sp + + ; Pointer to the return buffer. + push ss + push bp + add bp, 10h ; Correct bp. + + ; The divisor. + push dword [es:si + 4] + push dword [es:si] + + ; The dividend. + push ax + push bx + push cx + push dx + + call Bs3Int64Div + + ; Load the quotient. + mov ax, [bp - 10h + 8 + 6] + mov bx, [bp - 10h + 8 + 4] + mov cx, [bp - 10h + 8 + 2] + mov dx, [bp - 10h + 8] + + leave + pop es + pop ds +%ifdef ASM_MODEL_FAR_CODE + retf +%else + ret +%endif + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-wc16-I8DR.asm b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-wc16-I8DR.asm new file mode 100644 index 00000000..3c0c180f --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-wc16-I8DR.asm @@ -0,0 +1,111 @@ +; $Id: bs3-wc16-I8DR.asm $ +;; @file +; BS3Kit - 16-bit Watcom C/C++, 64-bit unsigned integer modulo. +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + +%include "bs3kit-template-header.mac" + +BS3_EXTERN_CMN Bs3Int64Div + + +;; +; 64-bit unsigned integer modulo, SS variant. +; +; @returns ax:bx:cx:dx reminder. (AX is the most significant, DX the least) +; @param ax:bx:cx:dx Dividend. +; @param [ss:si] Divisor +; +; @uses Nothing. +; +global $_?I8DR +$_?I8DR: + push es + push ss + pop es +%ifdef ASM_MODEL_FAR_CODE + push cs +%endif + call $_?I8DRE + pop es +%ifdef ASM_MODEL_FAR_CODE + retf +%else + ret +%endif + +;; +; 64-bit unsigned integer modulo, ES variant. +; +; @returns ax:bx:cx:dx reminder. +; @param ax:bx:cx:dx Dividend. +; @param [es:si] Divisor +; +; @uses Nothing. +; +global $_?I8DRE +$_?I8DRE: + push ds + push es + + ; + ; Convert to a C __cdecl call - not doing this in assembly. + ; + + ; Set up a frame of sorts, allocating 16 bytes for the result buffer. + push bp + sub sp, 10h + mov bp, sp + + ; Pointer to the return buffer. + push ss + push bp + add bp, 10h ; Correct bp. + + ; The divisor. + push dword [es:si + 4] + push dword [es:si] + + ; The dividend. + push ax + push bx + push cx + push dx + + call Bs3Int64Div + + ; Load the reminder. + mov ax, [bp - 10h + 8 + 6] + mov bx, [bp - 10h + 8 + 4] + mov cx, [bp - 10h + 8 + 2] + mov dx, [bp - 10h + 8] + + leave + pop es + pop ds +%ifdef ASM_MODEL_FAR_CODE + retf +%else + ret +%endif + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-wc16-I8RS.asm b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-wc16-I8RS.asm new file mode 100644 index 00000000..d231f2cc --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-wc16-I8RS.asm @@ -0,0 +1,68 @@ +; $Id: bs3-wc16-I8RS.asm $ +;; @file +; BS3Kit - 16-bit Watcom C/C++, 64-bit signed integer right shift. +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + +%include "bs3kit-template-header.mac" + + +;; +; 64-bit signed integer left shift. +; +; @returns AX:BX:CX:DX (AX is the most significant, DX the least) +; @param AX:BX:CX:DX Value to shift. +; @param SI Shift count. +; +global $_?I8RS +$_?I8RS: + push si + + ; + ; The 16-bit watcom code differs from the 32-bit one in the way it + ; handles the shift count. All 16-bit bits are used in the 16-bit + ; code, we do the same as the 32-bit one as we don't want to wast + ; time in the below loop. + ; + ; Using 8086 comatible approach here as it's less hazzle to write + ; and smaller. + ; + and si, 3fh + jz .return + +.next_shift: + sar ax, 1 + rcr bx, 1 + rcr cx, 1 + rcr dx, 1 + dec si + jnz .next_shift + +.return: + pop si +%ifdef ASM_MODEL_FAR_CODE + retf +%else + ret +%endif + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-wc16-U4D.asm b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-wc16-U4D.asm new file mode 100644 index 00000000..f9987f02 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-wc16-U4D.asm @@ -0,0 +1,114 @@ +; $Id: bs3-wc16-U4D.asm $ +;; @file +; BS3Kit - 16-bit Watcom C/C++, 32-bit unsigned integer division. +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + +%include "bs3kit-template-header.mac" + + + +;; +; 32-bit unsigned integer division. +; +; @returns DX:AX quotient, CX:BX remainder. +; @param DX:AX Dividend. +; @param CX:BX Divisor +; +; @uses Nothing. +; +%ifdef BS3KIT_WITH_REAL_WATCOM_INTRINSIC_NAMES +global __U4D +__U4D: +%endif +global $_?U4D +$_?U4D: +%if TMPL_BITS >= 32 + ; Move dividend into EDX:EAX + shl eax, 10h + mov ax, dx + xor edx, edx + + ; Move divisor into ebx. + shl ebx, 10h + mov bx, cx + + ; Do it! + div ebx + + ; Reminder in to CX:BX + mov bx, dx + shr edx, 10h + mov cx, dx + + ; Quotient into DX:AX + mov edx, eax + shr edx, 10h +%else + push ds + push es + + ; + ; Convert to a C __cdecl call - too lazy to do this in assembly. + ; + + ; Set up a frame of sorts, allocating 8 bytes for the result buffer. + push bp + sub sp, 08h + mov bp, sp + + ; Pointer to the return buffer. + push ss + push bp + add bp, 08h ; Correct bp. + + ; The divisor. + push cx + push bx + + ; The dividend. + push dx + push ax + + BS3_EXTERN_CMN Bs3UInt32Div + call Bs3UInt32Div + + ; Load the reminder. + mov cx, [bp - 08h + 6] + mov bx, [bp - 08h + 4] + ; Load the quotient. + mov dx, [bp - 08h + 2] + mov ax, [bp - 08h] + + mov sp, bp + pop bp + pop es + pop ds + +%endif +%ifdef ASM_MODEL_FAR_CODE + retf +%else + ret +%endif + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-wc16-U8DQ.asm b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-wc16-U8DQ.asm new file mode 100644 index 00000000..c9d95ba8 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-wc16-U8DQ.asm @@ -0,0 +1,114 @@ +; $Id: bs3-wc16-U8DQ.asm $ +;; @file +; BS3Kit - 16-bit Watcom C/C++, 64-bit unsigned integer division. +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + +%include "bs3kit-template-header.mac" + +BS3_EXTERN_CMN Bs3UInt64Div + + +;; +; 64-bit unsigned integer division, SS variant. +; +; @returns ax:bx:cx:dx quotient. (AX is the most significant, DX the least) +; @param ax:bx:cx:dx Dividend. +; @param [ss:si] Divisor +; +; @uses Nothing. +; +global $_?U8DQ +$_?U8DQ: + push es + push ss + pop es +%ifdef BS3_MODEL_FAR_CODE + push cs +%endif + call $_?U8DQE + pop es +%ifdef BS3_MODEL_FAR_CODE + retf +%else + ret +%endif + +;; +; 64-bit unsigned integer division, ES variant. +; +; @returns ax:bx:cx:dx quotient. (AX is the most significant, DX the least) +; @param ax:bx:cx:dx Dividend. +; @param [es:si] Divisor +; +; @uses Nothing. +; +global $_?U8DQE +$_?U8DQE: + push ds + push es + + ; + ; Convert to a C __cdecl call - not doing this in assembly. + ; + + ; Set up a frame of sorts, allocating 16 bytes for the result buffer. + push bp + sub sp, 10h + mov bp, sp + + ; Pointer to the return buffer. + push ss + push bp + add bp, 10h ; Correct bp. + + ; The divisor. + push word [es:si + 6] + push word [es:si + 4] + push word [es:si + 2] + push word [es:si] + + ; The dividend. + push ax + push bx + push cx + push dx + + call Bs3UInt64Div + + ; Load the quotient. + mov ax, [bp - 10h + 6] + mov bx, [bp - 10h + 4] + mov cx, [bp - 10h + 2] + mov dx, [bp - 10h] + + mov sp, bp + pop bp + pop es + pop ds +%ifdef ASM_MODEL_FAR_CODE + retf +%else + ret +%endif + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-wc16-U8DR.asm b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-wc16-U8DR.asm new file mode 100644 index 00000000..0f85e4e1 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-wc16-U8DR.asm @@ -0,0 +1,114 @@ +; $Id: bs3-wc16-U8DR.asm $ +;; @file +; BS3Kit - 16-bit Watcom C/C++, 64-bit unsigned integer modulo. +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + +%include "bs3kit-template-header.mac" + +BS3_EXTERN_CMN Bs3UInt64Div + + +;; +; 64-bit unsigned integer modulo, SS variant. +; +; @returns ax:bx:cx:dx reminder. (AX is the most significant, DX the least) +; @param ax:bx:cx:dx Dividend. +; @param [ss:si] Divisor +; +; @uses Nothing. +; +global $_?U8DR +$_?U8DR: + push es + push ss + pop es +%ifdef ASM_MODEL_FAR_CODE + push cs +%endif + call $_?U8DRE + pop es +%ifdef ASM_MODEL_FAR_CODE + retf +%else + ret +%endif + +;; +; 64-bit unsigned integer modulo, ES variant. +; +; @returns ax:bx:cx:dx reminder. (AX is the most significant, DX the least) +; @param ax:bx:cx:dx Dividend. +; @param [es:si] Divisor +; +; @uses Nothing. +; +global $_?U8DRE +$_?U8DRE: + push ds + push es + + ; + ; Convert to a C __cdecl call - not doing this in assembly. + ; + + ; Set up a frame of sorts, allocating 16 bytes for the result buffer. + push bp + sub sp, 10h + mov bp, sp + + ; Pointer to the return buffer. + push ss + push bp + add bp, 10h ; Correct bp. + + ; The divisor. + push word [es:si + 6] + push word [es:si + 4] + push word [es:si + 2] + push word [es:si] + + ; The dividend. + push ax + push bx + push cx + push dx + + call Bs3UInt64Div + + ; Load the reminder. + mov ax, [bp - 10h + 8 + 6] + mov bx, [bp - 10h + 8 + 4] + mov cx, [bp - 10h + 8 + 2] + mov dx, [bp - 10h + 8] + + mov sp, bp + pop bp + pop es + pop ds +%ifdef ASM_MODEL_FAR_CODE + retf +%else + ret +%endif + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-wc16-U8LS.asm b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-wc16-U8LS.asm new file mode 100644 index 00000000..2114eae3 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-wc16-U8LS.asm @@ -0,0 +1,70 @@ +; $Id: bs3-wc16-U8LS.asm $ +;; @file +; BS3Kit - 16-bit Watcom C/C++, 64-bit integer left shift. +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + +%include "bs3kit-template-header.mac" + + +;; +; 64-bit integer left shift. +; +; @returns AX:BX:CX:DX (AX is the most significant, DX the least) +; @param AX:BX:CX:DX Value to shift. +; @param SI Shift count. +; +global $_?U8LS +$_?U8LS: +global $_?I8LS +$_?I8LS: + push si + + ; + ; The 16-bit watcom code differs from the 32-bit one in the way it + ; handles the shift count. All 16-bit bits are used in the 16-bit + ; code, we do the same as the 32-bit one as we don't want to wast + ; time in the below loop. + ; + ; Using 8086 compatible approach here as it's less hazzle to write + ; and smaller. + ; + and si, 3fh + + jz .return +.next_shift: + shl dx, 1 + rcl cx, 1 + rcl bx, 1 + rcl ax, 1 + dec si + jnz .next_shift + +.return: + pop si +%ifdef ASM_MODEL_FAR_CODE + retf +%else + ret +%endif + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-wc16-U8RS.asm b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-wc16-U8RS.asm new file mode 100644 index 00000000..6de3ddf4 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-wc16-U8RS.asm @@ -0,0 +1,72 @@ +; $Id: bs3-wc16-U8RS.asm $ +;; @file +; BS3Kit - 16-bit Watcom C/C++, 64-bit unsigned integer right shift. +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + +%include "bs3kit-template-header.mac" + + +;; +; 64-bit unsigned integer left shift. +; +; @returns AX:BX:CX:DX (AX is the most significant, DX the least) +; @param AX:BX:CX:DX Value to shift. +; @param SI Shift count. +; +%ifdef BS3KIT_WITH_REAL_WATCOM_INTRINSIC_NAMES +global __U8RS +__U8RS: +%endif +global $_?U8RS +$_?U8RS: + push si + + ; + ; The 16-bit watcom code differs from the 32-bit one in the way it + ; handles the shift count. All 16-bit bits are used in the 16-bit + ; code, we do the same as the 32-bit one as we don't want to wast + ; time in the below loop. + ; + ; Using 8086 comatible approach here as it's less hazzle to write + ; and smaller. + ; + and si, 3fh + jz .return + +.next_shift: + shr ax, 1 + rcr bx, 1 + rcr cx, 1 + rcr dx, 1 + dec si + jnz .next_shift + +.return: + pop si +%ifdef ASM_MODEL_FAR_CODE + retf +%else + ret +%endif + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-wc32-I8D.asm b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-wc32-I8D.asm new file mode 100644 index 00000000..1785c132 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-wc32-I8D.asm @@ -0,0 +1,71 @@ +; $Id: bs3-wc32-I8D.asm $ +;; @file +; BS3Kit - 32-bit Watcom C/C++, 64-bit signed integer division. +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + +%include "bs3kit-template-header.mac" + +BS3_EXTERN_CMN Bs3Int64Div + + +;; +; 64-bit signed integer division. +; +; @returns EDX:EAX Quotient, ECX:EBX Remainder. +; @param EDX:EAX Dividend. +; @param ECX:EBX Divisor +; +global $??I8D +$??I8D: + ; + ; Convert to a C __cdecl call - not doing this in assembly. + ; + + ; Set up a frame, allocating 16 bytes for the result buffer. + push ebp + mov ebp, esp + sub esp, 10h + + ; Pointer to the return buffer. + push esp + + ; The dividend. + push ecx + push ebx + + ; The dividend. + push edx + push eax + + call Bs3Int64Div + + ; Load the result. + mov ecx, [ebp - 10h + 12] + mov ebx, [ebp - 10h + 8] + mov edx, [ebp - 10h + 4] + mov eax, [ebp - 10h] + + leave + ret + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-wc32-I8RS.asm b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-wc32-I8RS.asm new file mode 100644 index 00000000..08c01c81 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-wc32-I8RS.asm @@ -0,0 +1,60 @@ +; $Id: bs3-wc32-I8RS.asm $ +;; @file +; BS3Kit - 32-bit Watcom C/C++, 64-bit signed integer right shift. +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + +%include "bs3kit-template-header.mac" + + +;; +; 64-bit signed integer left shift. +; +; @returns EDX:EAX +; @param EDX:EAX Value to shift. +; @param BL Shift count (it's specified as ECX:EBX, but we only use BL). +; +global $??I8RS +$??I8RS: + push ecx ; We're allowed to trash ECX, but why bother. + + mov cl, bl + and cl, 3fh + test cl, 20h + jnz .big_shift + + ; Shifting less than 32. + shrd eax, edx, cl + sar edx, cl + +.return: + pop ecx + ret + +.big_shift: + ; Shifting 32 or more. + mov eax, edx + sar eax, cl ; Only uses lower 5 bits. + sar edx, 1fh ; Sign extend it. + jmp .return + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-wc32-U8D.asm b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-wc32-U8D.asm new file mode 100644 index 00000000..55d24509 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-wc32-U8D.asm @@ -0,0 +1,71 @@ +; $Id: bs3-wc32-U8D.asm $ +;; @file +; BS3Kit - 32-bit Watcom C/C++, 64-bit unsigned integer division. +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + +%include "bs3kit-template-header.mac" + +BS3_EXTERN_CMN Bs3UInt64Div + + +;; +; 64-bit unsigned integer division. +; +; @returns EDX:EAX Quotient, ECX:EBX Remainder. +; @param EDX:EAX Dividend. +; @param ECX:EBX Divisor +; +global $??U8D +$??U8D: + ; + ; Convert to a C __cdecl call - not doing this in assembly. + ; + + ; Set up a frame, allocating 16 bytes for the result buffer. + push ebp + mov ebp, esp + sub esp, 10h + + ; Pointer to the return buffer. + push esp + + ; The divisor. + push ecx + push ebx + + ; The dividend. + push edx + push eax + + call Bs3UInt64Div + + ; Load the result. + mov ecx, [ebp - 10h + 12] + mov ebx, [ebp - 10h + 8] + mov edx, [ebp - 10h + 4] + mov eax, [ebp - 10h] + + leave + ret + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-wc32-U8LS.asm b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-wc32-U8LS.asm new file mode 100644 index 00000000..77006ee6 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-wc32-U8LS.asm @@ -0,0 +1,62 @@ +; $Id: bs3-wc32-U8LS.asm $ +;; @file +; BS3Kit - 32-bit Watcom C/C++, 64-bit integer left shift. +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + +%include "bs3kit-template-header.mac" + + +;; +; 64-bit integer left shift. +; +; @returns EDX:EAX +; @param EDX:EAX Value to shift. +; @param BL Shift count (it's specified as ECX:EBX, but we only use BL). +; +global $??U8LS +$??U8LS: +global $??I8LS +$??I8LS: + push ecx ; We're allowed to trash ECX, but why bother. + + mov cl, bl + and cl, 3fh + test cl, 20h + jnz .big_shift + + ; Shifting less than 32. + shld edx, eax, cl + shl eax, cl + +.return: + pop ecx + ret + +.big_shift: + ; Shifting 32 or more. + mov edx, eax + shl edx, cl ; Only uses lower 5 bits. + xor eax, eax + jmp .return + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-wc32-U8RS.asm b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-wc32-U8RS.asm new file mode 100644 index 00000000..c9180f2b --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-wc32-U8RS.asm @@ -0,0 +1,60 @@ +; $Id: bs3-wc32-U8RS.asm $ +;; @file +; BS3Kit - 32-bit Watcom C/C++, 64-bit unsigned integer right shift. +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + +%include "bs3kit-template-header.mac" + + +;; +; 64-bit unsigned integer right shift. +; +; @returns EDX:EAX +; @param EDX:EAX Value to shift. +; @param BL Shift count (it's specified as ECX:EBX, but we only use BL). +; +global $??U8RS +$??U8RS: + push ecx ; We're allowed to trash ECX, but why bother. + + mov cl, bl + and cl, 3fh + test cl, 20h + jnz .big_shift + + ; Shifting less than 32. + shrd eax, edx, cl + shr edx, cl + +.return: + pop ecx + ret + +.big_shift: + ; Shifting 32 or more. + mov eax, edx + shr eax, cl ; Only uses lower 5 bits. + xor edx, edx + jmp .return + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3cpudt.c b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3cpudt.c new file mode 100644 index 00000000..0bdd2187 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3cpudt.c @@ -0,0 +1,61 @@ +/* $Id: bs3cpudt.c $ */ +/** @file + * BS3Kit - Tests Bs3CpuDetect_rm. + */ + +/* + * Copyright (C) 2007-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ + +#include "bs3kit.h" +#include <stdio.h> +#include <stdint.h> + + +unsigned StoreMsw(void); +#pragma aux StoreMsw = \ + ".286" \ + "smsw ax" \ + value [ax]; + +void LoadMsw(unsigned); +#pragma aux LoadMsw = \ + ".286p" \ + "lmsw ax" \ + parm [ax]; + +int main() +{ + uint16_t volatile usCpu = Bs3CpuDetect_rm(); + printf("usCpu=%#x\n", usCpu); + if ((usCpu & BS3CPU_TYPE_MASK) >= BS3CPU_80286) + { + printf("(42=%d) msw=%#x (42=%d)\n", 42, StoreMsw(), 42); + LoadMsw(0); + printf("lmsw 0 => msw=%#x (42=%d)\n", StoreMsw(), 42); + } + return 0; +} + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3kit-autostubs.kmk b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3kit-autostubs.kmk new file mode 100644 index 00000000..b80ef042 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3kit-autostubs.kmk @@ -0,0 +1,143 @@ +# $Id: bs3kit-autostubs.kmk $ +## @file +# BS3Kit - Automatic near/far stubs - generated by the bs3kit-autostubs.kmk makefile rule. +# + +# +# Copyright (C) 2007-2019 Oracle Corporation +# +# This file is part of VirtualBox Open Source Edition (OSE), as +# available from http://www.virtualbox.org. This file is free software; +# you can redistribute it and/or modify it under the terms of the GNU +# General Public License (GPL) as published by the Free Software +# Foundation, in version 2 as it comes in the "COPYING" file of the +# VirtualBox OSE distribution. VirtualBox OSE is distributed in the +# hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +# +# The contents of this file may alternatively be used under the terms +# of the Common Development and Distribution License Version 1.0 +# (CDDL) only, as it comes in the "COPYING.CDDL" file of the +# VirtualBox OSE distribution, in which case the provisions of the +# CDDL are applicable instead of those of the GPL. +# +# You may elect to license modified versions of this file under the +# terms and conditions of either the GPL or the CDDL or both. +# + +$(call BS3KIT_FN_GEN_CMN_FARSTUB,bs3kit-common-16,Bs3SelFlatDataToProtFar16,4) +$(call BS3KIT_FN_GEN_CMN_FARSTUB,bs3kit-common-16,Bs3SelFlatDataToRealMode,4) +$(call BS3KIT_FN_GEN_CMN_FARSTUB,bs3kit-common-16,Bs3SelProtFar16DataToFlat,4) +$(call BS3KIT_FN_GEN_CMN_FARSTUB,bs3kit-common-16,Bs3SelProtFar16DataToRealMode,4) +$(call BS3KIT_FN_GEN_CMN_FARSTUB,bs3kit-common-16,Bs3SelRealModeCodeToFlat,4) +$(call BS3KIT_FN_GEN_CMN_FARSTUB,bs3kit-common-16,Bs3SelRealModeDataToFlat,4) +$(call BS3KIT_FN_GEN_CMN_FARSTUB,bs3kit-common-16,Bs3SelRealModeDataToProtFar16,4) +$(call BS3KIT_FN_GEN_CMN_FARSTUB,bs3kit-common-16,Bs3ExtCtxRestore,4) +$(call BS3KIT_FN_GEN_CMN_FARSTUB,bs3kit-common-16,Bs3ExtCtxSave,4) +$(call BS3KIT_FN_GEN_CMN_FARSTUB,bs3kit-common-16,Bs3SelFar32ToFlat32NoClobber,6) +$(call BS3KIT_FN_GEN_CMN_FARSTUB,bs3kit-common-16,Bs3RegCtxSaveEx,8) +$(call BS3KIT_FN_GEN_CMN_NEARSTUB,bs3kit-common-16,Bs3TestCheckRegCtxEx) +$(call BS3KIT_FN_GEN_CMN_NEARSTUB,bs3kit-common-16,Bs3TestFailed) +$(call BS3KIT_FN_GEN_CMN_NEARSTUB,bs3kit-common-16,Bs3TestFailedF) +$(call BS3KIT_FN_GEN_CMN_NEARSTUB,bs3kit-common-16,Bs3TestFailedV) +$(call BS3KIT_FN_GEN_CMN_NEARSTUB,bs3kit-common-16,Bs3GetCpuVendor) +$(call BS3KIT_FN_GEN_CMN_NEARSTUB,bs3kit-common-16,Bs3StrCpy) +$(call BS3KIT_FN_GEN_CMN_NEARSTUB,bs3kit-common-16,Bs3GetModeName) +$(call BS3KIT_FN_GEN_CMN_NEARSTUB,bs3kit-common-16,Bs3GetModeNameShortLower) +$(call BS3KIT_FN_GEN_CMN_NEARSTUB,bs3kit-common-16,Bs3PagingAlias) +$(call BS3KIT_FN_GEN_CMN_NEARSTUB,bs3kit-common-16,Bs3PagingInitRootForLM) +$(call BS3KIT_FN_GEN_CMN_NEARSTUB,bs3kit-common-16,Bs3PagingInitRootForPAE) +$(call BS3KIT_FN_GEN_CMN_NEARSTUB,bs3kit-common-16,Bs3PagingInitRootForPP) +$(call BS3KIT_FN_GEN_CMN_NEARSTUB,bs3kit-common-16,Bs3PagingProtect) +$(call BS3KIT_FN_GEN_CMN_NEARSTUB,bs3kit-common-16,Bs3PagingProtectPtr) +$(call BS3KIT_FN_GEN_CMN_NEARSTUB,bs3kit-common-16,Bs3PagingQueryAddressInfo) +$(call BS3KIT_FN_GEN_CMN_NEARSTUB,bs3kit-common-16,Bs3PagingUnalias) +$(call BS3KIT_FN_GEN_CMN_NEARSTUB,bs3kit-common-16,Bs3SwitchFromV86To16BitAndCallC) +$(call BS3KIT_FN_GEN_CMN_NEARSTUB,bs3kit-common-16,Bs3ExtCtxAlloc) +$(call BS3KIT_FN_GEN_CMN_NEARSTUB,bs3kit-common-16,Bs3ExtCtxCopy) +$(call BS3KIT_FN_GEN_CMN_NEARSTUB,bs3kit-common-16,Bs3ExtCtxInit) +$(call BS3KIT_FN_GEN_CMN_NEARSTUB,bs3kit-common-16,Bs3TrapSetHandler) +$(call BS3KIT_FN_GEN_CMN_NEARSTUB,bs3kit-common-16,Bs3Printf) +$(call BS3KIT_FN_GEN_CMN_NEARSTUB,bs3kit-common-16,Bs3PrintfV) +$(call BS3KIT_FN_GEN_CMN_NEARSTUB,bs3kit-common-16,Bs3StrFormatV) +$(call BS3KIT_FN_GEN_CMN_NEARSTUB,bs3kit-common-16,Bs3StrLen) +$(call BS3KIT_FN_GEN_CMN_NEARSTUB,bs3kit-common-16,Bs3StrNLen) +$(call BS3KIT_FN_GEN_CMN_NEARSTUB,bs3kit-common-16,Bs3StrPrintf) +$(call BS3KIT_FN_GEN_CMN_NEARSTUB,bs3kit-common-16,Bs3StrPrintfV) +$(call BS3KIT_FN_GEN_CMN_NEARSTUB,bs3kit-common-16,Bs3ExtCtxGetSize) +$(call BS3KIT_FN_GEN_CMN_NEARSTUB,bs3kit-common-16,Bs3PicUpdateMask) +$(call BS3KIT_FN_GEN_CMN_NEARSTUB,bs3kit-common-16,Bs3SlabFree) +$(call BS3KIT_FN_GEN_CMN_NEARSTUB,bs3kit-common-16,Bs3TestSubErrorCount) +$(call BS3KIT_FN_GEN_CMN_NEARSTUB,bs3kit-common-16,Bs3SelFar32ToFlat32) +$(call BS3KIT_FN_GEN_CMN_NEARSTUB,bs3kit-common-16,Bs3SelProtFar32ToFlat32) +$(call BS3KIT_FN_GEN_CMN_NEARSTUB,bs3kit-common-16,Bs3TrapSetDpl) +$(call BS3KIT_FN_GEN_CMN_NEARSTUB,bs3kit-common-16,Bs3MemAlloc) +$(call BS3KIT_FN_GEN_CMN_NEARSTUB,bs3kit-common-16,Bs3MemAllocZ) +$(call BS3KIT_FN_GEN_CMN_NEARSTUB,bs3kit-common-16,Bs3MemCpy) +$(call BS3KIT_FN_GEN_CMN_NEARSTUB,bs3kit-common-16,Bs3MemGuardedTestPageAlloc) +$(call BS3KIT_FN_GEN_CMN_NEARSTUB,bs3kit-common-16,Bs3MemGuardedTestPageAllocEx) +$(call BS3KIT_FN_GEN_CMN_NEARSTUB,bs3kit-common-16,Bs3MemMove) +$(call BS3KIT_FN_GEN_CMN_NEARSTUB,bs3kit-common-16,Bs3MemPCpy) +$(call BS3KIT_FN_GEN_CMN_NEARSTUB,bs3kit-common-16,Bs3PagingGetPte) +$(call BS3KIT_FN_GEN_CMN_NEARSTUB,bs3kit-common-16,Bs3PagingSetupCanonicalTraps) +$(call BS3KIT_FN_GEN_CMN_NEARSTUB,bs3kit-common-16,Bs3SlabAlloc) +$(call BS3KIT_FN_GEN_CMN_NEARSTUB,bs3kit-common-16,Bs3SlabAllocEx) +$(call BS3KIT_FN_GEN_CMN_NEARSTUB,bs3kit-common-16,Bs3SlabListAlloc) +$(call BS3KIT_FN_GEN_CMN_NEARSTUB,bs3kit-common-16,Bs3SlabListAllocEx) +$(call BS3KIT_FN_GEN_CMN_NEARSTUB,bs3kit-common-16,Bs3ExtCtxFree) +$(call BS3KIT_FN_GEN_CMN_NEARSTUB,bs3kit-common-16,Bs3MemFree) +$(call BS3KIT_FN_GEN_CMN_NEARSTUB,bs3kit-common-16,Bs3MemGuardedTestPageFree) +$(call BS3KIT_FN_GEN_CMN_NEARSTUB,bs3kit-common-16,Bs3MemPrintInfo) +$(call BS3KIT_FN_GEN_CMN_NEARSTUB,bs3kit-common-16,Bs3PicMaskAll) +$(call BS3KIT_FN_GEN_CMN_NEARSTUB,bs3kit-common-16,Bs3PicSetup) +$(call BS3KIT_FN_GEN_CMN_NEARSTUB,bs3kit-common-16,Bs3PitDisable) +$(call BS3KIT_FN_GEN_CMN_NEARSTUB,bs3kit-common-16,Bs3PitSetupAndEnablePeriodTimer) +$(call BS3KIT_FN_GEN_CMN_NEARSTUB,bs3kit-common-16,Bs3PrintStr) +$(call BS3KIT_FN_GEN_CMN_NEARSTUB,bs3kit-common-16,Bs3RegCtxConvertToRingX) +$(call BS3KIT_FN_GEN_CMN_NEARSTUB,bs3kit-common-16,Bs3RegCtxPrint) +$(call BS3KIT_FN_GEN_CMN_NEARSTUB,bs3kit-common-16,Bs3RegCtxSetGrpDsFromCurPtr) +$(call BS3KIT_FN_GEN_CMN_NEARSTUB,bs3kit-common-16,Bs3RegCtxSetGrpSegFromCurPtr) +$(call BS3KIT_FN_GEN_CMN_NEARSTUB,bs3kit-common-16,Bs3RegCtxSetGrpSegFromFlat) +$(call BS3KIT_FN_GEN_CMN_NEARSTUB,bs3kit-common-16,Bs3RegCtxSetRipCsFromCurPtr) +$(call BS3KIT_FN_GEN_CMN_NEARSTUB,bs3kit-common-16,Bs3RegCtxSetRipCsFromFlat) +$(call BS3KIT_FN_GEN_CMN_NEARSTUB,bs3kit-common-16,Bs3RegCtxSetRipCsFromLnkPtr) +$(call BS3KIT_FN_GEN_CMN_NEARSTUB,bs3kit-common-16,Bs3SelSetup16BitCode) +$(call BS3KIT_FN_GEN_CMN_NEARSTUB,bs3kit-common-16,Bs3SelSetup16BitData) +$(call BS3KIT_FN_GEN_CMN_NEARSTUB,bs3kit-common-16,Bs3SlabInit) +$(call BS3KIT_FN_GEN_CMN_NEARSTUB,bs3kit-common-16,Bs3SlabListAdd) +$(call BS3KIT_FN_GEN_CMN_NEARSTUB,bs3kit-common-16,Bs3SlabListFree) +$(call BS3KIT_FN_GEN_CMN_NEARSTUB,bs3kit-common-16,Bs3SlabListInit) +$(call BS3KIT_FN_GEN_CMN_NEARSTUB,bs3kit-common-16,Bs3TestHostPrintf) +$(call BS3KIT_FN_GEN_CMN_NEARSTUB,bs3kit-common-16,Bs3TestHostPrintfV) +$(call BS3KIT_FN_GEN_CMN_NEARSTUB,bs3kit-common-16,Bs3TestInit) +$(call BS3KIT_FN_GEN_CMN_NEARSTUB,bs3kit-common-16,Bs3TestPrintf) +$(call BS3KIT_FN_GEN_CMN_NEARSTUB,bs3kit-common-16,Bs3TestPrintfV) +$(call BS3KIT_FN_GEN_CMN_NEARSTUB,bs3kit-common-16,Bs3TestSkipped) +$(call BS3KIT_FN_GEN_CMN_NEARSTUB,bs3kit-common-16,Bs3TestSkippedF) +$(call BS3KIT_FN_GEN_CMN_NEARSTUB,bs3kit-common-16,Bs3TestSkippedV) +$(call BS3KIT_FN_GEN_CMN_NEARSTUB,bs3kit-common-16,Bs3TestSub) +$(call BS3KIT_FN_GEN_CMN_NEARSTUB,bs3kit-common-16,Bs3TestSubDone) +$(call BS3KIT_FN_GEN_CMN_NEARSTUB,bs3kit-common-16,Bs3TestSubF) +$(call BS3KIT_FN_GEN_CMN_NEARSTUB,bs3kit-common-16,Bs3TestSubV) +$(call BS3KIT_FN_GEN_CMN_NEARSTUB,bs3kit-common-16,Bs3TestTerm) +$(call BS3KIT_FN_GEN_CMN_NEARSTUB,bs3kit-common-16,Bs3Trap16Init) +$(call BS3KIT_FN_GEN_CMN_NEARSTUB,bs3kit-common-16,Bs3Trap16InitEx) +$(call BS3KIT_FN_GEN_CMN_NEARSTUB,bs3kit-common-16,Bs3Trap16SetGate) +$(call BS3KIT_FN_GEN_CMN_NEARSTUB,bs3kit-common-16,Bs3Trap32Init) +$(call BS3KIT_FN_GEN_CMN_NEARSTUB,bs3kit-common-16,Bs3Trap32SetGate) +$(call BS3KIT_FN_GEN_CMN_NEARSTUB,bs3kit-common-16,Bs3Trap64Init) +$(call BS3KIT_FN_GEN_CMN_NEARSTUB,bs3kit-common-16,Bs3Trap64SetGate) +$(call BS3KIT_FN_GEN_CMN_NEARSTUB,bs3kit-common-16,Bs3TrapDefaultHandler) +$(call BS3KIT_FN_GEN_CMN_NEARSTUB,bs3kit-common-16,Bs3TrapPrintFrame) +$(call BS3KIT_FN_GEN_CMN_NEARSTUB,bs3kit-common-16,Bs3TrapReInit) +$(call BS3KIT_FN_GEN_CMN_NEARSTUB,bs3kit-common-16,Bs3TrapRmV86Init) +$(call BS3KIT_FN_GEN_CMN_NEARSTUB,bs3kit-common-16,Bs3TrapRmV86InitEx) +$(call BS3KIT_FN_GEN_CMN_NEARSTUB,bs3kit-common-16,Bs3TrapRmV86SetGate) +$(call BS3KIT_FN_GEN_CMN_NEARSTUB,bs3kit-common-16,Bs3TrapSetHandlerEx) +$(call BS3KIT_FN_GEN_CMN_NEARSTUB,bs3kit-common-16,Bs3TrapSetJmpAndRestore) +$(call BS3KIT_FN_GEN_CMN_NEARSTUB,bs3kit-common-16,Bs3TrapUnsetJmp) +$(call BS3KIT_FN_GEN_CMN_NEARSTUB,bs3kit-common-16,Bs3UInt32Div) +$(call BS3KIT_FN_GEN_CMN_NEARSTUB,bs3kit-common-16,Bs3UInt64Div) +$(call BS3KIT_FN_GEN_CMN_NEARSTUB,bs3kit-common-16,bs3PagingGetLegacyPte) +$(call BS3KIT_FN_GEN_CMN_NEARSTUB,bs3kit-common-16,bs3PagingGetPaePte) +$(call BS3KIT_FN_GEN_MODE_NEARSTUB,bs3kit-common-16,Bs3SwitchTo32BitAndCallC) +$(call BS3KIT_FN_GEN_MODE_NEARSTUB,bs3kit-common-16,Bs3TrapInit) diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3kit-docs.c b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3kit-docs.c new file mode 100644 index 00000000..8d1c86cc --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3kit-docs.c @@ -0,0 +1,160 @@ +/* $Id: bs3kit-docs.c $ */ +/** @file + * BS3Kit - Documentation. + */ + +/* + * Copyright (C) 2007-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + + + +/** @page pg_bs3kit BS3Kit - Boot Sector Kit \#3 + * + * The BS3Kit is a framework for bare metal floppy/usb image tests. + * + * The 3rd iteration of the framework includes support for 16-bit and 32-bit + * C/C++ code, with provisions for 64-bit C code to possibly be added later. + * The C code have to do without a runtime library, otherwhat what we can share + * possibly with IPRT. + * + * This iteration also adds a real linker into the picture, which is an + * improvment over early when all had to done in a single assembler run with + * lots of includes and macros controlling what we needed. The functions are no + * in separate files and compiled/assembled into libraries, so the linker will + * only include exactly what is needed. The current linker is the OpenWatcom + * one, wlink, that we're already using when building the BIOSes. If it wasn't + * for the segment/selector fixups in 16-bit code (mostly), maybe we could + * convince the ELF linker from GNU binutils to do the job too (with help from + * the ). + * + * + * @sa grp_bs3kit, grp_bs3kit_tmpl, grp_bs3kit_cmn, grp_bs3kit_mode, + * grp_bs3kit_system + * + * @section sec_calling_convention Calling convention + * + * Because we're not mixing with C code, we will use __cdecl for 16-bit and + * 32-bit code, where as 64-bit code will use the microsoft calling AMD64 + * convention. To avoid unnecessary %ifdef'ing in assembly code, we will use a + * macro to load the RCX, RDX, R8 and R9 registers off the stack in 64-bit + * assembly code. + * + * Register treatment in 16-bit __cdecl, 32-bit __cdecl and 64-bit msabi: + * + * | Register | 16-bit | 32-bit | 64-bit | ASM template | + * | ------------ | ----------- | ---------- | --------------- | ------------ | + * | EAX, RAX | volatile | volatile | volatile | volatile | + * | EBX, RBX | volatile | preserved | preserved | both | + * | ECX, RCX | volatile | volatile | volatile, arg 0 | volatile | + * | EDX, RDX | volatile | volatile | volatile, arg 1 | volatile | + * | ESP, RSP | preserved | preserved | preserved | preserved | + * | EBP, RBP | preserved | preserved | preserved | preserved | + * | EDI, RDI | preserved | preserved | preserved | preserved | + * | ESI, RSI | preserved | preserved | preserved | preserved | + * | R8 | volatile | volatile | volatile, arg 2 | volatile | + * | R9 | volatile | volatile | volatile, arg 3 | volatile | + * | R10 | volatile | volatile | volatile | volatile | + * | R11 | volatile | volatile | volatile | volatile | + * | R12 | volatile | volatile | preserved | preserved(*) | + * | R13 | volatile | volatile | preserved | preserved(*) | + * | R14 | volatile | volatile | preserved | preserved(*) | + * | R15 | volatile | volatile | preserved | preserved(*) | + * | RFLAGS.DF | =0 | =0 | =0 | =0 | + * | CS | preserved | preserved | preserved | preserved | + * | DS | preserved! | preserved? | preserved | both | + * | ES | volatile | volatile | preserved | volatile | + * | FS | preserved | preserved | preserved | preserved | + * | GS | preserved | volatile | preserved | both | + * | SS | preserved | preserved | preserved | preserved | + * + * The 'both' here means that we preserve it wrt to our caller, while at the + * same time assuming anything we call will clobber it. + * + * The 'preserved(*)' marking of R12-R15 indicates that they'll be preserved in + * 64-bit mode, but may be changed in certain cases when running 32-bit or + * 16-bit code. This is especially true if switching CPU mode, e.g. from 32-bit + * protected mode to 32-bit long mode. + * + * Return values are returned in the xAX register, but with the following + * caveats for values larger than ARCH_BITS: + * - 16-bit code: + * - 32-bit values are returned in AX:DX, where AX holds bits 15:0 and + * DX bits 31:16. + * - 64-bit values are returned in DX:CX:BX:AX, where DX holds bits + * 15:0, CX bits 31:16, BX bits 47:32, and AX bits 63:48. + * - 32-bit code: + * - 64-bit values are returned in EAX:EDX, where eax holds the least + * significant bits. + * + * The DS segment register is pegged to BS3DATA16_GROUP in 16-bit code so that + * we don't need to reload it all the time. This allows us to modify it in + * ring-0 and mode switching code without ending up in any serious RPL or DPL + * trouble. In 32-bit and 64-bit mode the DS register is a flat, unlimited, + * writable selector. + * + * In 16-bit and 32-bit code we do not assume anything about ES, FS, and GS. + * + * + * For an in depth coverage of x86 and AMD64 calling convensions, see + * http://homepage.ntlworld.com/jonathan.deboynepollard/FGA/function-calling-conventions.html + * + * + * + * @section sec_modes Execution Modes + * + * BS3Kit defines a number of execution modes in order to be able to test the + * full CPU capabilities (that VirtualBox care about anyways). It currently + * omits system management mode, hardware virtualization modes, and security + * modes as those aren't supported by VirtualBox or are difficult to handle. + * + * The modes are categorized into normal and weird ones. + * + * The normal ones are: + * + RM - Real mode. + * + PE16 - Protected mode running 16-bit code, 16-bit TSS and 16-bit handlers. + * + PE32 - Protected mode running 32-bit code, 32-bit TSS and 32-bit handlers. + * + PEV86 - Protected mode running v8086 code, 32-bit TSS and 32-bit handlers. + * + PP16 - 386 paged mode running 16-bit code, 16-bit TSS and 16-bit handlers. + * + PP32 - 386 paged mode running 32-bit code, 32-bit TSS and 32-bit handlers. + * + PPV86 - 386 paged mode running v8086 code, 32-bit TSS and 32-bit handlers. + * + PAE16 - PAE paged mode running 16-bit code, 16-bit TSS and 16-bit handlers. + * + PAE32 - PAE paged mode running 32-bit code, 32-bit TSS and 32-bit handlers. + * + PAEV86 - PAE paged mode running v8086 code, 32-bit TSS and 32-bit handlers. + * + LM16 - AMD64 long mode running 16-bit code, 64-bit TSS and 64-bit handlers. + * + LM32 - AMD64 long mode running 32-bit code, 64-bit TSS and 64-bit handlers. + * + LM64 - AMD64 long mode running 64-bit code, 64-bit TSS and 64-bit handlers. + * + * The weird ones: + * + PE16_32 - Protected mode running 16-bit code, 16-bit TSS and 16-bit handlers. + * + PE16_V86 - Protected mode running 16-bit code, 16-bit TSS and 16-bit handlers. + * + PE32_16 - Protected mode running 32-bit code, 32-bit TSS and 32-bit handlers. + * + PP16_32 - 386 paged mode running 16-bit code, 16-bit TSS and 16-bit handlers. + * + PP16_V86 - 386 paged mode running 16-bit code, 16-bit TSS and 16-bit handlers. + * + PP32_16 - 386 paged mode running 32-bit code, 32-bit TSS and 32-bit handlers. + * + PAE16_32 - PAE paged mode running 16-bit code, 16-bit TSS and 16-bit handlers. + * + PAE16_V86 - PAE paged mode running 16-bit code, 16-bit TSS and 16-bit handlers. + * + PAE32_16 - PAE paged mode running 32-bit code, 32-bit TSS and 32-bit handlers. + * + * Actually, the PE32_16, PP32_16 and PAE32_16 modes aren't all that weird and fits in + * right next to LM16 and LM32, but this is the way it ended up. :-) + * + */ + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3kit-mangling-code-define.h b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3kit-mangling-code-define.h new file mode 100644 index 00000000..c55a0a44 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3kit-mangling-code-define.h @@ -0,0 +1,203 @@ +/* $Id: bs3kit-mangling-code-define.h $ */ +/** @file + * BS3Kit - Function needing mangling - generated by the bs3kit-mangling-code-define.h makefile rule. + */ + +/* + * Copyright (C) 2007-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + +#define Bs3A20Disable BS3_CMN_MANGLER(Bs3A20Disable) +#define Bs3A20DisableViaKbd BS3_CMN_MANGLER(Bs3A20DisableViaKbd) +#define Bs3A20DisableViaPortA BS3_CMN_MANGLER(Bs3A20DisableViaPortA) +#define Bs3A20Enable BS3_CMN_MANGLER(Bs3A20Enable) +#define Bs3A20EnableViaKbd BS3_CMN_MANGLER(Bs3A20EnableViaKbd) +#define Bs3A20EnableViaPortA BS3_CMN_MANGLER(Bs3A20EnableViaPortA) +#define Bs3ExtCtxAlloc BS3_CMN_MANGLER(Bs3ExtCtxAlloc) +#define Bs3ExtCtxCopy BS3_CMN_MANGLER(Bs3ExtCtxCopy) +#define Bs3ExtCtxFree BS3_CMN_MANGLER(Bs3ExtCtxFree) +#define Bs3ExtCtxGetSize BS3_CMN_MANGLER(Bs3ExtCtxGetSize) +#define Bs3ExtCtxInit BS3_CMN_MANGLER(Bs3ExtCtxInit) +#define Bs3ExtCtxRestore BS3_CMN_MANGLER(Bs3ExtCtxRestore) +#define Bs3ExtCtxSave BS3_CMN_MANGLER(Bs3ExtCtxSave) +#define Bs3GetCpuVendor BS3_CMN_MANGLER(Bs3GetCpuVendor) +#define Bs3GetModeName BS3_CMN_MANGLER(Bs3GetModeName) +#define Bs3GetModeNameShortLower BS3_CMN_MANGLER(Bs3GetModeNameShortLower) +#define Bs3KbdRead BS3_CMN_MANGLER(Bs3KbdRead) +#define Bs3KbdWait BS3_CMN_MANGLER(Bs3KbdWait) +#define Bs3KbdWrite BS3_CMN_MANGLER(Bs3KbdWrite) +#define Bs3MemAlloc BS3_CMN_MANGLER(Bs3MemAlloc) +#define Bs3MemAllocZ BS3_CMN_MANGLER(Bs3MemAllocZ) +#define Bs3MemChr BS3_CMN_MANGLER(Bs3MemChr) +#define Bs3MemCmp BS3_CMN_MANGLER(Bs3MemCmp) +#define Bs3MemCpy BS3_CMN_MANGLER(Bs3MemCpy) +#define Bs3MemFree BS3_CMN_MANGLER(Bs3MemFree) +#define Bs3MemGuardedTestPageAlloc BS3_CMN_MANGLER(Bs3MemGuardedTestPageAlloc) +#define Bs3MemGuardedTestPageAllocEx BS3_CMN_MANGLER(Bs3MemGuardedTestPageAllocEx) +#define Bs3MemGuardedTestPageFree BS3_CMN_MANGLER(Bs3MemGuardedTestPageFree) +#define Bs3MemMove BS3_CMN_MANGLER(Bs3MemMove) +#define Bs3MemPCpy BS3_CMN_MANGLER(Bs3MemPCpy) +#define Bs3MemPrintInfo BS3_CMN_MANGLER(Bs3MemPrintInfo) +#define Bs3MemSet BS3_CMN_MANGLER(Bs3MemSet) +#define Bs3MemZero BS3_CMN_MANGLER(Bs3MemZero) +#define Bs3PagingAlias BS3_CMN_MANGLER(Bs3PagingAlias) +#define bs3PagingGetLegacyPte BS3_CMN_MANGLER(bs3PagingGetLegacyPte) +#define bs3PagingGetPaePte BS3_CMN_MANGLER(bs3PagingGetPaePte) +#define Bs3PagingGetPte BS3_CMN_MANGLER(Bs3PagingGetPte) +#define Bs3PagingInitRootForLM BS3_CMN_MANGLER(Bs3PagingInitRootForLM) +#define Bs3PagingInitRootForPAE BS3_CMN_MANGLER(Bs3PagingInitRootForPAE) +#define Bs3PagingInitRootForPP BS3_CMN_MANGLER(Bs3PagingInitRootForPP) +#define Bs3PagingProtect BS3_CMN_MANGLER(Bs3PagingProtect) +#define Bs3PagingProtectPtr BS3_CMN_MANGLER(Bs3PagingProtectPtr) +#define Bs3PagingQueryAddressInfo BS3_CMN_MANGLER(Bs3PagingQueryAddressInfo) +#define Bs3PagingSetupCanonicalTraps BS3_CMN_MANGLER(Bs3PagingSetupCanonicalTraps) +#define Bs3PagingUnalias BS3_CMN_MANGLER(Bs3PagingUnalias) +#define Bs3Panic BS3_CMN_MANGLER(Bs3Panic) +#define Bs3PicMaskAll BS3_CMN_MANGLER(Bs3PicMaskAll) +#define Bs3PicSetup BS3_CMN_MANGLER(Bs3PicSetup) +#define Bs3PicUpdateMask BS3_CMN_MANGLER(Bs3PicUpdateMask) +#define Bs3PitDisable BS3_CMN_MANGLER(Bs3PitDisable) +#define Bs3PitSetupAndEnablePeriodTimer BS3_CMN_MANGLER(Bs3PitSetupAndEnablePeriodTimer) +#define Bs3PrintChr BS3_CMN_MANGLER(Bs3PrintChr) +#define Bs3Printf BS3_CMN_MANGLER(Bs3Printf) +#define Bs3PrintfV BS3_CMN_MANGLER(Bs3PrintfV) +#define Bs3PrintStr BS3_CMN_MANGLER(Bs3PrintStr) +#define Bs3PrintStrN BS3_CMN_MANGLER(Bs3PrintStrN) +#define Bs3PrintU32 BS3_CMN_MANGLER(Bs3PrintU32) +#define Bs3PrintX32 BS3_CMN_MANGLER(Bs3PrintX32) +#define Bs3RegCtxConvertToRingX BS3_CMN_MANGLER(Bs3RegCtxConvertToRingX) +#define Bs3RegCtxPrint BS3_CMN_MANGLER(Bs3RegCtxPrint) +#define Bs3RegCtxRestore BS3_CMN_MANGLER(Bs3RegCtxRestore) +#define Bs3RegCtxSave BS3_CMN_MANGLER(Bs3RegCtxSave) +#define Bs3RegCtxSaveEx BS3_CMN_MANGLER(Bs3RegCtxSaveEx) +#define Bs3RegCtxSetGrpDsFromCurPtr BS3_CMN_MANGLER(Bs3RegCtxSetGrpDsFromCurPtr) +#define Bs3RegCtxSetGrpSegFromCurPtr BS3_CMN_MANGLER(Bs3RegCtxSetGrpSegFromCurPtr) +#define Bs3RegCtxSetGrpSegFromFlat BS3_CMN_MANGLER(Bs3RegCtxSetGrpSegFromFlat) +#define Bs3RegCtxSetRipCsFromCurPtr BS3_CMN_MANGLER(Bs3RegCtxSetRipCsFromCurPtr) +#define Bs3RegCtxSetRipCsFromFlat BS3_CMN_MANGLER(Bs3RegCtxSetRipCsFromFlat) +#define Bs3RegCtxSetRipCsFromLnkPtr BS3_CMN_MANGLER(Bs3RegCtxSetRipCsFromLnkPtr) +#define Bs3RegGetCr0 BS3_CMN_MANGLER(Bs3RegGetCr0) +#define Bs3RegGetCr2 BS3_CMN_MANGLER(Bs3RegGetCr2) +#define Bs3RegGetCr3 BS3_CMN_MANGLER(Bs3RegGetCr3) +#define Bs3RegGetCr4 BS3_CMN_MANGLER(Bs3RegGetCr4) +#define Bs3RegGetDr0 BS3_CMN_MANGLER(Bs3RegGetDr0) +#define Bs3RegGetDr1 BS3_CMN_MANGLER(Bs3RegGetDr1) +#define Bs3RegGetDr2 BS3_CMN_MANGLER(Bs3RegGetDr2) +#define Bs3RegGetDr3 BS3_CMN_MANGLER(Bs3RegGetDr3) +#define Bs3RegGetDr6 BS3_CMN_MANGLER(Bs3RegGetDr6) +#define Bs3RegGetDr7 BS3_CMN_MANGLER(Bs3RegGetDr7) +#define Bs3RegGetDrX BS3_CMN_MANGLER(Bs3RegGetDrX) +#define Bs3RegGetLdtr BS3_CMN_MANGLER(Bs3RegGetLdtr) +#define Bs3RegGetTr BS3_CMN_MANGLER(Bs3RegGetTr) +#define Bs3RegSetCr0 BS3_CMN_MANGLER(Bs3RegSetCr0) +#define Bs3RegSetCr2 BS3_CMN_MANGLER(Bs3RegSetCr2) +#define Bs3RegSetCr3 BS3_CMN_MANGLER(Bs3RegSetCr3) +#define Bs3RegSetCr4 BS3_CMN_MANGLER(Bs3RegSetCr4) +#define Bs3RegSetDr0 BS3_CMN_MANGLER(Bs3RegSetDr0) +#define Bs3RegSetDr1 BS3_CMN_MANGLER(Bs3RegSetDr1) +#define Bs3RegSetDr2 BS3_CMN_MANGLER(Bs3RegSetDr2) +#define Bs3RegSetDr3 BS3_CMN_MANGLER(Bs3RegSetDr3) +#define Bs3RegSetDr6 BS3_CMN_MANGLER(Bs3RegSetDr6) +#define Bs3RegSetDr7 BS3_CMN_MANGLER(Bs3RegSetDr7) +#define Bs3RegSetDrX BS3_CMN_MANGLER(Bs3RegSetDrX) +#define Bs3RegSetLdtr BS3_CMN_MANGLER(Bs3RegSetLdtr) +#define Bs3RegSetTr BS3_CMN_MANGLER(Bs3RegSetTr) +#define Bs3SelFar32ToFlat32 BS3_CMN_MANGLER(Bs3SelFar32ToFlat32) +#define Bs3SelFar32ToFlat32NoClobber BS3_CMN_MANGLER(Bs3SelFar32ToFlat32NoClobber) +#define Bs3SelFlatCodeToProtFar16 BS3_CMN_MANGLER(Bs3SelFlatCodeToProtFar16) +#define Bs3SelFlatCodeToRealMode BS3_CMN_MANGLER(Bs3SelFlatCodeToRealMode) +#define Bs3SelFlatDataToProtFar16 BS3_CMN_MANGLER(Bs3SelFlatDataToProtFar16) +#define Bs3SelFlatDataToRealMode BS3_CMN_MANGLER(Bs3SelFlatDataToRealMode) +#define Bs3SelProtFar16DataToFlat BS3_CMN_MANGLER(Bs3SelProtFar16DataToFlat) +#define Bs3SelProtFar16DataToRealMode BS3_CMN_MANGLER(Bs3SelProtFar16DataToRealMode) +#define Bs3SelProtFar32ToFlat32 BS3_CMN_MANGLER(Bs3SelProtFar32ToFlat32) +#define Bs3SelProtModeCodeToRealMode BS3_CMN_MANGLER(Bs3SelProtModeCodeToRealMode) +#define Bs3SelRealModeCodeToFlat BS3_CMN_MANGLER(Bs3SelRealModeCodeToFlat) +#define Bs3SelRealModeCodeToProtMode BS3_CMN_MANGLER(Bs3SelRealModeCodeToProtMode) +#define Bs3SelRealModeDataToFlat BS3_CMN_MANGLER(Bs3SelRealModeDataToFlat) +#define Bs3SelRealModeDataToProtFar16 BS3_CMN_MANGLER(Bs3SelRealModeDataToProtFar16) +#define Bs3SelSetup16BitCode BS3_CMN_MANGLER(Bs3SelSetup16BitCode) +#define Bs3SelSetup16BitData BS3_CMN_MANGLER(Bs3SelSetup16BitData) +#define Bs3Shutdown BS3_CMN_MANGLER(Bs3Shutdown) +#define Bs3SlabAlloc BS3_CMN_MANGLER(Bs3SlabAlloc) +#define Bs3SlabAllocEx BS3_CMN_MANGLER(Bs3SlabAllocEx) +#define Bs3SlabFree BS3_CMN_MANGLER(Bs3SlabFree) +#define Bs3SlabInit BS3_CMN_MANGLER(Bs3SlabInit) +#define Bs3SlabListAdd BS3_CMN_MANGLER(Bs3SlabListAdd) +#define Bs3SlabListAlloc BS3_CMN_MANGLER(Bs3SlabListAlloc) +#define Bs3SlabListAllocEx BS3_CMN_MANGLER(Bs3SlabListAllocEx) +#define Bs3SlabListFree BS3_CMN_MANGLER(Bs3SlabListFree) +#define Bs3SlabListInit BS3_CMN_MANGLER(Bs3SlabListInit) +#define Bs3StrCpy BS3_CMN_MANGLER(Bs3StrCpy) +#define Bs3StrFormatV BS3_CMN_MANGLER(Bs3StrFormatV) +#define Bs3StrLen BS3_CMN_MANGLER(Bs3StrLen) +#define Bs3StrNLen BS3_CMN_MANGLER(Bs3StrNLen) +#define Bs3StrPrintf BS3_CMN_MANGLER(Bs3StrPrintf) +#define Bs3StrPrintfV BS3_CMN_MANGLER(Bs3StrPrintfV) +#define Bs3SwitchFromV86To16BitAndCallC BS3_CMN_MANGLER(Bs3SwitchFromV86To16BitAndCallC) +#define Bs3TestCheckRegCtxEx BS3_CMN_MANGLER(Bs3TestCheckRegCtxEx) +#define Bs3TestFailed BS3_CMN_MANGLER(Bs3TestFailed) +#define Bs3TestFailedF BS3_CMN_MANGLER(Bs3TestFailedF) +#define Bs3TestFailedV BS3_CMN_MANGLER(Bs3TestFailedV) +#define Bs3TestHostPrintf BS3_CMN_MANGLER(Bs3TestHostPrintf) +#define Bs3TestHostPrintfV BS3_CMN_MANGLER(Bs3TestHostPrintfV) +#define Bs3TestInit BS3_CMN_MANGLER(Bs3TestInit) +#define Bs3TestPrintf BS3_CMN_MANGLER(Bs3TestPrintf) +#define Bs3TestPrintfV BS3_CMN_MANGLER(Bs3TestPrintfV) +#define Bs3TestSkipped BS3_CMN_MANGLER(Bs3TestSkipped) +#define Bs3TestSkippedF BS3_CMN_MANGLER(Bs3TestSkippedF) +#define Bs3TestSkippedV BS3_CMN_MANGLER(Bs3TestSkippedV) +#define Bs3TestSub BS3_CMN_MANGLER(Bs3TestSub) +#define Bs3TestSubDone BS3_CMN_MANGLER(Bs3TestSubDone) +#define Bs3TestSubErrorCount BS3_CMN_MANGLER(Bs3TestSubErrorCount) +#define Bs3TestSubF BS3_CMN_MANGLER(Bs3TestSubF) +#define Bs3TestSubV BS3_CMN_MANGLER(Bs3TestSubV) +#define Bs3TestTerm BS3_CMN_MANGLER(Bs3TestTerm) +#define Bs3Trap16Init BS3_CMN_MANGLER(Bs3Trap16Init) +#define Bs3Trap16InitEx BS3_CMN_MANGLER(Bs3Trap16InitEx) +#define Bs3Trap16SetGate BS3_CMN_MANGLER(Bs3Trap16SetGate) +#define Bs3Trap32Init BS3_CMN_MANGLER(Bs3Trap32Init) +#define Bs3Trap32SetGate BS3_CMN_MANGLER(Bs3Trap32SetGate) +#define Bs3Trap64Init BS3_CMN_MANGLER(Bs3Trap64Init) +#define Bs3Trap64SetGate BS3_CMN_MANGLER(Bs3Trap64SetGate) +#define Bs3TrapDefaultHandler BS3_CMN_MANGLER(Bs3TrapDefaultHandler) +#define Bs3TrapPrintFrame BS3_CMN_MANGLER(Bs3TrapPrintFrame) +#define Bs3TrapReInit BS3_CMN_MANGLER(Bs3TrapReInit) +#define Bs3TrapRmV86Init BS3_CMN_MANGLER(Bs3TrapRmV86Init) +#define Bs3TrapRmV86InitEx BS3_CMN_MANGLER(Bs3TrapRmV86InitEx) +#define Bs3TrapRmV86SetGate BS3_CMN_MANGLER(Bs3TrapRmV86SetGate) +#define Bs3TrapSetDpl BS3_CMN_MANGLER(Bs3TrapSetDpl) +#define Bs3TrapSetHandler BS3_CMN_MANGLER(Bs3TrapSetHandler) +#define Bs3TrapSetHandlerEx BS3_CMN_MANGLER(Bs3TrapSetHandlerEx) +#define Bs3TrapSetJmp BS3_CMN_MANGLER(Bs3TrapSetJmp) +#define Bs3TrapSetJmpAndRestore BS3_CMN_MANGLER(Bs3TrapSetJmpAndRestore) +#define Bs3TrapUnsetJmp BS3_CMN_MANGLER(Bs3TrapUnsetJmp) +#define Bs3UInt32Div BS3_CMN_MANGLER(Bs3UInt32Div) +#define Bs3UInt64Div BS3_CMN_MANGLER(Bs3UInt64Div) +#define Bs3UtilSetFullGdtr BS3_CMN_MANGLER(Bs3UtilSetFullGdtr) +#define Bs3UtilSetFullIdtr BS3_CMN_MANGLER(Bs3UtilSetFullIdtr) +#ifndef BS3_CMN_ONLY +# define Bs3CpuDetect BS3_MODE_MANGLER(Bs3CpuDetect) +# define Bs3SwitchTo32BitAndCallC BS3_MODE_MANGLER(Bs3SwitchTo32BitAndCallC) +# define Bs3TestDoModes BS3_MODE_MANGLER(Bs3TestDoModes) +# define Bs3TestDoModesByMax BS3_MODE_MANGLER(Bs3TestDoModesByMax) +# define Bs3TestDoModesByOne BS3_MODE_MANGLER(Bs3TestDoModesByOne) +# define Bs3TrapInit BS3_MODE_MANGLER(Bs3TrapInit) +#endif /* !BS3_CMN_ONLY */ diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3kit-mangling-code-undef.h b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3kit-mangling-code-undef.h new file mode 100644 index 00000000..bc2d41f8 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3kit-mangling-code-undef.h @@ -0,0 +1,203 @@ +/* $Id: bs3kit-mangling-code-undef.h $ */ +/** @file + * BS3Kit - Undefining function mangling - automatically generated by the bs3kit-mangling-code-undef.h makefile rule. + */ + +/* + * Copyright (C) 2007-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + +#undef Bs3A20Disable +#undef Bs3A20DisableViaKbd +#undef Bs3A20DisableViaPortA +#undef Bs3A20Enable +#undef Bs3A20EnableViaKbd +#undef Bs3A20EnableViaPortA +#undef Bs3ExtCtxAlloc +#undef Bs3ExtCtxCopy +#undef Bs3ExtCtxFree +#undef Bs3ExtCtxGetSize +#undef Bs3ExtCtxInit +#undef Bs3ExtCtxRestore +#undef Bs3ExtCtxSave +#undef Bs3GetCpuVendor +#undef Bs3GetModeName +#undef Bs3GetModeNameShortLower +#undef Bs3KbdRead +#undef Bs3KbdWait +#undef Bs3KbdWrite +#undef Bs3MemAlloc +#undef Bs3MemAllocZ +#undef Bs3MemChr +#undef Bs3MemCmp +#undef Bs3MemCpy +#undef Bs3MemFree +#undef Bs3MemGuardedTestPageAlloc +#undef Bs3MemGuardedTestPageAllocEx +#undef Bs3MemGuardedTestPageFree +#undef Bs3MemMove +#undef Bs3MemPCpy +#undef Bs3MemPrintInfo +#undef Bs3MemSet +#undef Bs3MemZero +#undef Bs3PagingAlias +#undef bs3PagingGetLegacyPte +#undef bs3PagingGetPaePte +#undef Bs3PagingGetPte +#undef Bs3PagingInitRootForLM +#undef Bs3PagingInitRootForPAE +#undef Bs3PagingInitRootForPP +#undef Bs3PagingProtect +#undef Bs3PagingProtectPtr +#undef Bs3PagingQueryAddressInfo +#undef Bs3PagingSetupCanonicalTraps +#undef Bs3PagingUnalias +#undef Bs3Panic +#undef Bs3PicMaskAll +#undef Bs3PicSetup +#undef Bs3PicUpdateMask +#undef Bs3PitDisable +#undef Bs3PitSetupAndEnablePeriodTimer +#undef Bs3PrintChr +#undef Bs3Printf +#undef Bs3PrintfV +#undef Bs3PrintStr +#undef Bs3PrintStrN +#undef Bs3PrintU32 +#undef Bs3PrintX32 +#undef Bs3RegCtxConvertToRingX +#undef Bs3RegCtxPrint +#undef Bs3RegCtxRestore +#undef Bs3RegCtxSave +#undef Bs3RegCtxSaveEx +#undef Bs3RegCtxSetGrpDsFromCurPtr +#undef Bs3RegCtxSetGrpSegFromCurPtr +#undef Bs3RegCtxSetGrpSegFromFlat +#undef Bs3RegCtxSetRipCsFromCurPtr +#undef Bs3RegCtxSetRipCsFromFlat +#undef Bs3RegCtxSetRipCsFromLnkPtr +#undef Bs3RegGetCr0 +#undef Bs3RegGetCr2 +#undef Bs3RegGetCr3 +#undef Bs3RegGetCr4 +#undef Bs3RegGetDr0 +#undef Bs3RegGetDr1 +#undef Bs3RegGetDr2 +#undef Bs3RegGetDr3 +#undef Bs3RegGetDr6 +#undef Bs3RegGetDr7 +#undef Bs3RegGetDrX +#undef Bs3RegGetLdtr +#undef Bs3RegGetTr +#undef Bs3RegSetCr0 +#undef Bs3RegSetCr2 +#undef Bs3RegSetCr3 +#undef Bs3RegSetCr4 +#undef Bs3RegSetDr0 +#undef Bs3RegSetDr1 +#undef Bs3RegSetDr2 +#undef Bs3RegSetDr3 +#undef Bs3RegSetDr6 +#undef Bs3RegSetDr7 +#undef Bs3RegSetDrX +#undef Bs3RegSetLdtr +#undef Bs3RegSetTr +#undef Bs3SelFar32ToFlat32 +#undef Bs3SelFar32ToFlat32NoClobber +#undef Bs3SelFlatCodeToProtFar16 +#undef Bs3SelFlatCodeToRealMode +#undef Bs3SelFlatDataToProtFar16 +#undef Bs3SelFlatDataToRealMode +#undef Bs3SelProtFar16DataToFlat +#undef Bs3SelProtFar16DataToRealMode +#undef Bs3SelProtFar32ToFlat32 +#undef Bs3SelProtModeCodeToRealMode +#undef Bs3SelRealModeCodeToFlat +#undef Bs3SelRealModeCodeToProtMode +#undef Bs3SelRealModeDataToFlat +#undef Bs3SelRealModeDataToProtFar16 +#undef Bs3SelSetup16BitCode +#undef Bs3SelSetup16BitData +#undef Bs3Shutdown +#undef Bs3SlabAlloc +#undef Bs3SlabAllocEx +#undef Bs3SlabFree +#undef Bs3SlabInit +#undef Bs3SlabListAdd +#undef Bs3SlabListAlloc +#undef Bs3SlabListAllocEx +#undef Bs3SlabListFree +#undef Bs3SlabListInit +#undef Bs3StrCpy +#undef Bs3StrFormatV +#undef Bs3StrLen +#undef Bs3StrNLen +#undef Bs3StrPrintf +#undef Bs3StrPrintfV +#undef Bs3SwitchFromV86To16BitAndCallC +#undef Bs3TestCheckRegCtxEx +#undef Bs3TestFailed +#undef Bs3TestFailedF +#undef Bs3TestFailedV +#undef Bs3TestHostPrintf +#undef Bs3TestHostPrintfV +#undef Bs3TestInit +#undef Bs3TestPrintf +#undef Bs3TestPrintfV +#undef Bs3TestSkipped +#undef Bs3TestSkippedF +#undef Bs3TestSkippedV +#undef Bs3TestSub +#undef Bs3TestSubDone +#undef Bs3TestSubErrorCount +#undef Bs3TestSubF +#undef Bs3TestSubV +#undef Bs3TestTerm +#undef Bs3Trap16Init +#undef Bs3Trap16InitEx +#undef Bs3Trap16SetGate +#undef Bs3Trap32Init +#undef Bs3Trap32SetGate +#undef Bs3Trap64Init +#undef Bs3Trap64SetGate +#undef Bs3TrapDefaultHandler +#undef Bs3TrapPrintFrame +#undef Bs3TrapReInit +#undef Bs3TrapRmV86Init +#undef Bs3TrapRmV86InitEx +#undef Bs3TrapRmV86SetGate +#undef Bs3TrapSetDpl +#undef Bs3TrapSetHandler +#undef Bs3TrapSetHandlerEx +#undef Bs3TrapSetJmp +#undef Bs3TrapSetJmpAndRestore +#undef Bs3TrapUnsetJmp +#undef Bs3UInt32Div +#undef Bs3UInt64Div +#undef Bs3UtilSetFullGdtr +#undef Bs3UtilSetFullIdtr +#ifndef BS3_CMN_ONLY +# undef Bs3CpuDetect +# undef Bs3SwitchTo32BitAndCallC +# undef Bs3TestDoModes +# undef Bs3TestDoModesByMax +# undef Bs3TestDoModesByOne +# undef Bs3TrapInit +#endif /* !BS3_CMN_ONLY */ diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3kit-mangling-code.h b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3kit-mangling-code.h new file mode 100644 index 00000000..d7e65518 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3kit-mangling-code.h @@ -0,0 +1,42 @@ +/* $Id: bs3kit-mangling-code.h $ */ +/** @file + * BS3Kit - Symbol mangling, code. + */ + +/* + * Copyright (C) 2007-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + + +/* + * Do function mangling. This can be redone at compile time (templates). + */ +#undef BS3_CMN_MANGLER +#undef BS3_MODE_MANGLER +#if ARCH_BITS != 16 || !defined(BS3_USE_ALT_16BIT_TEXT_SEG) +# define BS3_CMN_MANGLER(a_Function) BS3_CMN_NM(a_Function) +# define BS3_MODE_MANGLER(a_Function) TMPL_NM(a_Function) +#else +# define BS3_CMN_MANGLER(a_Function) BS3_CMN_FAR_NM(a_Function) +# define BS3_MODE_MANGLER(a_Function) TMPL_FAR_NM(a_Function) +#endif +#include "bs3kit-mangling-code-undef.h" +#include "bs3kit-mangling-code-define.h" + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3kit-mangling-data.h b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3kit-mangling-data.h new file mode 100644 index 00000000..c5f706ff --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3kit-mangling-data.h @@ -0,0 +1,285 @@ +/* $Id: bs3kit-mangling-data.h $ */ +/** @file + * BS3Kit - Symbol mangling. + */ + +/* + * Copyright (C) 2007-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + + +/* + * First part is only applied once. It concerns itself with data symbols. + */ + +#ifndef BS3KIT_INCLUDED_bs3kit_mangling_data_h +#define BS3KIT_INCLUDED_bs3kit_mangling_data_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#if 0 /* the object converter deals with this now */ +#if ARCH_BITS == 64 + +# define Bs3Gdt BS3_DATA_NM(Bs3Gdt) +# define Bs3Gdt_Ldt BS3_DATA_NM(Bs3Gdt_Ldt) +# define Bs3Gdte_Tss16 BS3_DATA_NM(Bs3Gdte_Tss16) +# define Bs3Gdte_Tss16DoubleFault BS3_DATA_NM(Bs3Gdte_Tss16DoubleFault) +# define Bs3Gdte_Tss16Spare0 BS3_DATA_NM(Bs3Gdte_Tss16Spare0) +# define Bs3Gdte_Tss16Spare1 BS3_DATA_NM(Bs3Gdte_Tss16Spare1) +# define Bs3Gdte_Tss32 BS3_DATA_NM(Bs3Gdte_Tss32) +# define Bs3Gdte_Tss32DoubleFault BS3_DATA_NM(Bs3Gdte_Tss32DoubleFault) +# define Bs3Gdte_Tss32Spare0 BS3_DATA_NM(Bs3Gdte_Tss32Spare0) +# define Bs3Gdte_Tss32Spare1 BS3_DATA_NM(Bs3Gdte_Tss32Spare1) +# define Bs3Gdte_Tss32IobpIntRedirBm BS3_DATA_NM(Bs3Gdte_Tss32IobpIntRedirBm) +# define Bs3Gdte_Tss32IntRedirBm BS3_DATA_NM(Bs3Gdte_Tss32IntRedirBm) +# define Bs3Gdte_Tss64 BS3_DATA_NM(Bs3Gdte_Tss64) +# define Bs3Gdte_Tss64Spare0 BS3_DATA_NM(Bs3Gdte_Tss64Spare0) +# define Bs3Gdte_Tss64Spare1 BS3_DATA_NM(Bs3Gdte_Tss64Spare1) +# define Bs3Gdte_Tss64Iobp BS3_DATA_NM(Bs3Gdte_Tss64Iobp) +# define Bs3Gdte_RMTEXT16_CS BS3_DATA_NM(Bs3Gdte_RMTEXT16_CS) +# define Bs3Gdte_X0TEXT16_CS BS3_DATA_NM(Bs3Gdte_X0TEXT16_CS) +# define Bs3Gdte_X1TEXT16_CS BS3_DATA_NM(Bs3Gdte_X1TEXT16_CS) +# define Bs3Gdte_R0_MMIO16 BS3_DATA_NM(Bs3Gdte_R0_MMIO16) + +# define Bs3Gdte_R0_First BS3_DATA_NM(Bs3Gdte_R0_First) +# define Bs3Gdte_R0_CS16 BS3_DATA_NM(Bs3Gdte_R0_CS16) +# define Bs3Gdte_R0_DS16 BS3_DATA_NM(Bs3Gdte_R0_DS16) +# define Bs3Gdte_R0_SS16 BS3_DATA_NM(Bs3Gdte_R0_SS16) +# define Bs3Gdte_R0_CS32 BS3_DATA_NM(Bs3Gdte_R0_CS32) +# define Bs3Gdte_R0_DS32 BS3_DATA_NM(Bs3Gdte_R0_DS32) +# define Bs3Gdte_R0_SS32 BS3_DATA_NM(Bs3Gdte_R0_SS32) +# define Bs3Gdte_R0_CS64 BS3_DATA_NM(Bs3Gdte_R0_CS64) +# define Bs3Gdte_R0_DS64 BS3_DATA_NM(Bs3Gdte_R0_DS64) +# define Bs3Gdte_R0_CS16_EO BS3_DATA_NM(Bs3Gdte_R0_CS16_EO) +# define Bs3Gdte_R0_CS16_CNF BS3_DATA_NM(Bs3Gdte_R0_CS16_CNF) +# define Bs3Gdte_R0_CS16_CND_EO BS3_DATA_NM(Bs3Gdte_R0_CS16_CND_EO) +# define Bs3Gdte_R0_CS32_EO BS3_DATA_NM(Bs3Gdte_R0_CS32_EO) +# define Bs3Gdte_R0_CS32_CNF BS3_DATA_NM(Bs3Gdte_R0_CS32_CNF) +# define Bs3Gdte_R0_CS32_CNF_EO BS3_DATA_NM(Bs3Gdte_R0_CS32_CNF_EO) +# define Bs3Gdte_R0_CS64_EO BS3_DATA_NM(Bs3Gdte_R0_CS64_EO) +# define Bs3Gdte_R0_CS64_CNF BS3_DATA_NM(Bs3Gdte_R0_CS64_CNF) +# define Bs3Gdte_R0_CS64_CNF_EO BS3_DATA_NM(Bs3Gdte_R0_CS64_CNF_EO) + +# define Bs3Gdte_R1_First BS3_DATA_NM(Bs3Gdte_R1_First) +# define Bs3Gdte_R1_CS16 BS3_DATA_NM(Bs3Gdte_R1_CS16) +# define Bs3Gdte_R1_DS16 BS3_DATA_NM(Bs3Gdte_R1_DS16) +# define Bs3Gdte_R1_SS16 BS3_DATA_NM(Bs3Gdte_R1_SS16) +# define Bs3Gdte_R1_CS32 BS3_DATA_NM(Bs3Gdte_R1_CS32) +# define Bs3Gdte_R1_DS32 BS3_DATA_NM(Bs3Gdte_R1_DS32) +# define Bs3Gdte_R1_SS32 BS3_DATA_NM(Bs3Gdte_R1_SS32) +# define Bs3Gdte_R1_CS64 BS3_DATA_NM(Bs3Gdte_R1_CS64) +# define Bs3Gdte_R1_DS64 BS3_DATA_NM(Bs3Gdte_R1_DS64) +# define Bs3Gdte_R1_CS16_EO BS3_DATA_NM(Bs3Gdte_R1_CS16_EO) +# define Bs3Gdte_R1_CS16_CNF BS3_DATA_NM(Bs3Gdte_R1_CS16_CNF) +# define Bs3Gdte_R1_CS16_CND_EO BS3_DATA_NM(Bs3Gdte_R1_CS16_CND_EO) +# define Bs3Gdte_R1_CS32_EO BS3_DATA_NM(Bs3Gdte_R1_CS32_EO) +# define Bs3Gdte_R1_CS32_CNF BS3_DATA_NM(Bs3Gdte_R1_CS32_CNF) +# define Bs3Gdte_R1_CS32_CNF_EO BS3_DATA_NM(Bs3Gdte_R1_CS32_CNF_EO) +# define Bs3Gdte_R1_CS64_EO BS3_DATA_NM(Bs3Gdte_R1_CS64_EO) +# define Bs3Gdte_R1_CS64_CNF BS3_DATA_NM(Bs3Gdte_R1_CS64_CNF) +# define Bs3Gdte_R1_CS64_CNF_EO BS3_DATA_NM(Bs3Gdte_R1_CS64_CNF_EO) + +# define Bs3Gdte_R2_First BS3_DATA_NM(Bs3Gdte_R2_First) +# define Bs3Gdte_R2_CS16 BS3_DATA_NM(Bs3Gdte_R2_CS16) +# define Bs3Gdte_R2_DS16 BS3_DATA_NM(Bs3Gdte_R2_DS16) +# define Bs3Gdte_R2_SS16 BS3_DATA_NM(Bs3Gdte_R2_SS16) +# define Bs3Gdte_R2_CS32 BS3_DATA_NM(Bs3Gdte_R2_CS32) +# define Bs3Gdte_R2_DS32 BS3_DATA_NM(Bs3Gdte_R2_DS32) +# define Bs3Gdte_R2_SS32 BS3_DATA_NM(Bs3Gdte_R2_SS32) +# define Bs3Gdte_R2_CS64 BS3_DATA_NM(Bs3Gdte_R2_CS64) +# define Bs3Gdte_R2_DS64 BS3_DATA_NM(Bs3Gdte_R2_DS64) +# define Bs3Gdte_R2_CS16_EO BS3_DATA_NM(Bs3Gdte_R2_CS16_EO) +# define Bs3Gdte_R2_CS16_CNF BS3_DATA_NM(Bs3Gdte_R2_CS16_CNF) +# define Bs3Gdte_R2_CS16_CND_EO BS3_DATA_NM(Bs3Gdte_R2_CS16_CND_EO) +# define Bs3Gdte_R2_CS32_EO BS3_DATA_NM(Bs3Gdte_R2_CS32_EO) +# define Bs3Gdte_R2_CS32_CNF BS3_DATA_NM(Bs3Gdte_R2_CS32_CNF) +# define Bs3Gdte_R2_CS32_CNF_EO BS3_DATA_NM(Bs3Gdte_R2_CS32_CNF_EO) +# define Bs3Gdte_R2_CS64_EO BS3_DATA_NM(Bs3Gdte_R2_CS64_EO) +# define Bs3Gdte_R2_CS64_CNF BS3_DATA_NM(Bs3Gdte_R2_CS64_CNF) +# define Bs3Gdte_R2_CS64_CNF_EO BS3_DATA_NM(Bs3Gdte_R2_CS64_CNF_EO) + +# define Bs3Gdte_R3_First BS3_DATA_NM(Bs3Gdte_R3_First) +# define Bs3Gdte_R3_CS16 BS3_DATA_NM(Bs3Gdte_R3_CS16) +# define Bs3Gdte_R3_DS16 BS3_DATA_NM(Bs3Gdte_R3_DS16) +# define Bs3Gdte_R3_SS16 BS3_DATA_NM(Bs3Gdte_R3_SS16) +# define Bs3Gdte_R3_CS32 BS3_DATA_NM(Bs3Gdte_R3_CS32) +# define Bs3Gdte_R3_DS32 BS3_DATA_NM(Bs3Gdte_R3_DS32) +# define Bs3Gdte_R3_SS32 BS3_DATA_NM(Bs3Gdte_R3_SS32) +# define Bs3Gdte_R3_CS64 BS3_DATA_NM(Bs3Gdte_R3_CS64) +# define Bs3Gdte_R3_DS64 BS3_DATA_NM(Bs3Gdte_R3_DS64) +# define Bs3Gdte_R3_CS16_EO BS3_DATA_NM(Bs3Gdte_R3_CS16_EO) +# define Bs3Gdte_R3_CS16_CNF BS3_DATA_NM(Bs3Gdte_R3_CS16_CNF) +# define Bs3Gdte_R3_CS16_CND_EO BS3_DATA_NM(Bs3Gdte_R3_CS16_CND_EO) +# define Bs3Gdte_R3_CS32_EO BS3_DATA_NM(Bs3Gdte_R3_CS32_EO) +# define Bs3Gdte_R3_CS32_CNF BS3_DATA_NM(Bs3Gdte_R3_CS32_CNF) +# define Bs3Gdte_R3_CS32_CNF_EO BS3_DATA_NM(Bs3Gdte_R3_CS32_CNF_EO) +# define Bs3Gdte_R3_CS64_EO BS3_DATA_NM(Bs3Gdte_R3_CS64_EO) +# define Bs3Gdte_R3_CS64_CNF BS3_DATA_NM(Bs3Gdte_R3_CS64_CNF) +# define Bs3Gdte_R3_CS64_CNF_EO BS3_DATA_NM(Bs3Gdte_R3_CS64_CNF_EO) + +# define Bs3GdteSpare00 BS3_DATA_NM(Bs3GdteSpare00) +# define Bs3GdteSpare01 BS3_DATA_NM(Bs3GdteSpare01) +# define Bs3GdteSpare02 BS3_DATA_NM(Bs3GdteSpare02) +# define Bs3GdteSpare03 BS3_DATA_NM(Bs3GdteSpare03) +# define Bs3GdteSpare04 BS3_DATA_NM(Bs3GdteSpare04) +# define Bs3GdteSpare05 BS3_DATA_NM(Bs3GdteSpare05) +# define Bs3GdteSpare06 BS3_DATA_NM(Bs3GdteSpare06) +# define Bs3GdteSpare07 BS3_DATA_NM(Bs3GdteSpare07) +# define Bs3GdteSpare08 BS3_DATA_NM(Bs3GdteSpare08) +# define Bs3GdteSpare09 BS3_DATA_NM(Bs3GdteSpare09) +# define Bs3GdteSpare0a BS3_DATA_NM(Bs3GdteSpare0a) +# define Bs3GdteSpare0b BS3_DATA_NM(Bs3GdteSpare0b) +# define Bs3GdteSpare0c BS3_DATA_NM(Bs3GdteSpare0c) +# define Bs3GdteSpare0d BS3_DATA_NM(Bs3GdteSpare0d) +# define Bs3GdteSpare0e BS3_DATA_NM(Bs3GdteSpare0e) +# define Bs3GdteSpare0f BS3_DATA_NM(Bs3GdteSpare0f) +# define Bs3GdteSpare10 BS3_DATA_NM(Bs3GdteSpare10) +# define Bs3GdteSpare11 BS3_DATA_NM(Bs3GdteSpare11) +# define Bs3GdteSpare12 BS3_DATA_NM(Bs3GdteSpare12) +# define Bs3GdteSpare13 BS3_DATA_NM(Bs3GdteSpare13) +# define Bs3GdteSpare14 BS3_DATA_NM(Bs3GdteSpare14) +# define Bs3GdteSpare15 BS3_DATA_NM(Bs3GdteSpare15) +# define Bs3GdteSpare16 BS3_DATA_NM(Bs3GdteSpare16) +# define Bs3GdteSpare17 BS3_DATA_NM(Bs3GdteSpare17) +# define Bs3GdteSpare18 BS3_DATA_NM(Bs3GdteSpare18) +# define Bs3GdteSpare19 BS3_DATA_NM(Bs3GdteSpare19) +# define Bs3GdteSpare1a BS3_DATA_NM(Bs3GdteSpare1a) +# define Bs3GdteSpare1b BS3_DATA_NM(Bs3GdteSpare1b) +# define Bs3GdteSpare1c BS3_DATA_NM(Bs3GdteSpare1c) +# define Bs3GdteSpare1d BS3_DATA_NM(Bs3GdteSpare1d) +# define Bs3GdteSpare1e BS3_DATA_NM(Bs3GdteSpare1e) +# define Bs3GdteSpare1f BS3_DATA_NM(Bs3GdteSpare1f) + +# define Bs3GdteTiled BS3_DATA_NM(Bs3GdteTiled) +# define Bs3GdteFreePart1 BS3_DATA_NM(Bs3GdteFreePart1) +# define Bs3Gdte_CODE16 BS3_DATA_NM(Bs3Gdte_CODE16) +# define Bs3GdteFreePart2 BS3_DATA_NM(Bs3GdteFreePart2) +# define Bs3Gdte_SYSTEM16 BS3_DATA_NM(Bs3Gdte_SYSTEM16) +# define Bs3GdteFreePart3 BS3_DATA_NM(Bs3GdteFreePart3) +# define Bs3Gdte_DATA16 BS3_DATA_NM(Bs3Gdte_DATA16) + +# define Bs3GdteFreePart4 BS3_DATA_NM(Bs3GdteFreePart4) +# define Bs3GdtePreTestPage08 BS3_DATA_NM(Bs3GdtePreTestPage08) +# define Bs3GdtePreTestPage07 BS3_DATA_NM(Bs3GdtePreTestPage07) +# define Bs3GdtePreTestPage06 BS3_DATA_NM(Bs3GdtePreTestPage06) +# define Bs3GdtePreTestPage05 BS3_DATA_NM(Bs3GdtePreTestPage05) +# define Bs3GdtePreTestPage04 BS3_DATA_NM(Bs3GdtePreTestPage04) +# define Bs3GdtePreTestPage03 BS3_DATA_NM(Bs3GdtePreTestPage03) +# define Bs3GdtePreTestPage02 BS3_DATA_NM(Bs3GdtePreTestPage02) +# define Bs3GdtePreTestPage01 BS3_DATA_NM(Bs3GdtePreTestPage01) +# define Bs3GdteTestPage BS3_DATA_NM(Bs3GdteTestPage) +# define Bs3GdteTestPage00 BS3_DATA_NM(Bs3GdteTestPage00) +# define Bs3GdteTestPage01 BS3_DATA_NM(Bs3GdteTestPage01) +# define Bs3GdteTestPage02 BS3_DATA_NM(Bs3GdteTestPage02) +# define Bs3GdteTestPage03 BS3_DATA_NM(Bs3GdteTestPage03) +# define Bs3GdteTestPage04 BS3_DATA_NM(Bs3GdteTestPage04) +# define Bs3GdteTestPage05 BS3_DATA_NM(Bs3GdteTestPage05) +# define Bs3GdteTestPage06 BS3_DATA_NM(Bs3GdteTestPage06) +# define Bs3GdteTestPage07 BS3_DATA_NM(Bs3GdteTestPage07) + +# define Bs3GdtEnd BS3_DATA_NM(Bs3GdtEnd) + +# define Bs3Tss16 BS3_DATA_NM(Bs3Tss16) +# define Bs3Tss16DoubleFault BS3_DATA_NM(Bs3Tss16DoubleFault) +# define Bs3Tss16Spare0 BS3_DATA_NM(Bs3Tss16Spare0) +# define Bs3Tss16Spare1 BS3_DATA_NM(Bs3Tss16Spare1) +# define Bs3Tss32 BS3_DATA_NM(Bs3Tss32) +# define Bs3Tss32DoubleFault BS3_DATA_NM(Bs3Tss32DoubleFault) +# define Bs3Tss32Spare0 BS3_DATA_NM(Bs3Tss32Spare0) +# define Bs3Tss32Spare1 BS3_DATA_NM(Bs3Tss32Spare1) +# define Bs3Tss64 BS3_DATA_NM(Bs3Tss64) +# define Bs3Tss64Spare0 BS3_DATA_NM(Bs3Tss64Spare0) +# define Bs3Tss64Spare1 BS3_DATA_NM(Bs3Tss64Spare1) +# define Bs3Tss64WithIopb BS3_DATA_NM(Bs3Tss64WithIopb) +# define Bs3Tss32WithIopb BS3_DATA_NM(Bs3Tss32WithIopb) +# define Bs3SharedIntRedirBm BS3_DATA_NM(Bs3SharedIntRedirBm) +# define Bs3SharedIobp BS3_DATA_NM(Bs3SharedIobp) +# define Bs3SharedIobpEnd BS3_DATA_NM(Bs3SharedIobpEnd) +# define Bs3Idt16 BS3_DATA_NM(Bs3Idt16) +# define Bs3Idt32 BS3_DATA_NM(Bs3Idt32) +# define Bs3Idt64 BS3_DATA_NM(Bs3Idt64) +# define Bs3Lidt_Idt16 BS3_DATA_NM(Bs3Lidt_Idt16) +# define Bs3Lidt_Idt32 BS3_DATA_NM(Bs3Lidt_Idt32) +# define Bs3Lidt_Idt64 BS3_DATA_NM(Bs3Lidt_Idt64) +# define Bs3Lidt_Ivt BS3_DATA_NM(Bs3Lidt_Ivt) +# define Bs3Lgdt_Gdt BS3_DATA_NM(Bs3Lgdt_Gdt) +# define Bs3Ldt BS3_DATA_NM(Bs3Ldt) +# define Bs3LdtEnd BS3_DATA_NM(Bs3LdtEnd) + +# define Bs3Text16_StartOfSegment BS3_DATA_NM(Bs3Text16_StartOfSegment) +# define Bs3Text16_EndOfSegment BS3_DATA_NM(Bs3Text16_EndOfSegment) +# define Bs3Text16_Size BS3_DATA_NM(Bs3Text16_Size) + +# define Bs3System16_StartOfSegment BS3_DATA_NM(Bs3System16_StartOfSegment) +# define Bs3System16_EndOfSegment BS3_DATA_NM(Bs3System16_EndOfSegment) + +# define Bs3Data16_StartOfSegment BS3_DATA_NM(Bs3Data16_StartOfSegment) +# define Bs3Data16_EndOfSegment BS3_DATA_NM(Bs3Data16_EndOfSegment) + +# define Bs3RmText16_StartOfSegment BS3_DATA_NM(Bs3RmText16_StartOfSegment) +# define Bs3RmText16_EndOfSegment BS3_DATA_NM(Bs3RmText16_EndOfSegment) +# define Bs3RmText16_Size BS3_DATA_NM(Bs3RmText16_Size) +# define Bs3RmText16_FlatAddr BS3_DATA_NM(Bs3RmText16_FlatAddr) + +# define Bs3X0Text16_StartOfSegment BS3_DATA_NM(Bs3X0Text16_StartOfSegment) +# define Bs3X0Text16_EndOfSegment BS3_DATA_NM(Bs3X0Text16_EndOfSegment) +# define Bs3X0Text16_Size BS3_DATA_NM(Bs3X0Text16_Size) +# define Bs3X0Text16_FlatAddr BS3_DATA_NM(Bs3X0Text16_FlatAddr) + +# define Bs3X1Text16_StartOfSegment BS3_DATA_NM(Bs3X1Text16_StartOfSegment) +# define Bs3X1Text16_EndOfSegment BS3_DATA_NM(Bs3X1Text16_EndOfSegment) +# define Bs3X1Text16_Size BS3_DATA_NM(Bs3X1Text16_Size) +# define Bs3X1Text16_FlatAddr BS3_DATA_NM(Bs3X1Text16_FlatAddr) + +# define Bs3Text32_StartOfSegment BS3_DATA_NM(Bs3Text32_StartOfSegment) +# define Bs3Text32_EndOfSegment BS3_DATA_NM(Bs3Text32_EndOfSegment) + +# define Bs3Data32_StartOfSegment BS3_DATA_NM(Bs3Data32_StartOfSegment) +# define Bs3Data32_EndOfSegment BS3_DATA_NM(Bs3Data32_EndOfSegment) + +# define Bs3Text64_StartOfSegment BS3_DATA_NM(Bs3Text64_StartOfSegment) +# define Bs3Text64_EndOfSegment BS3_DATA_NM(Bs3Text64_EndOfSegment) + +# define Bs3Data64_StartOfSegment BS3_DATA_NM(Bs3Data64_StartOfSegment) +# define Bs3Data64_EndOfSegment BS3_DATA_NM(Bs3Data64_EndOfSegment) + +# define Bs3Data16Thru64Text32And64_TotalSize BS3_DATA_NM(Bs3Data16Thru64Text32And64_TotalSize) +# define Bs3TotalImageSize BS3_DATA_NM(Bs3TotalImageSize) + +# define g_achBs3HexDigits BS3_DATA_NM(g_achBs3HexDigits) +# define g_achBs3HexDigitsUpper BS3_DATA_NM(g_achBs3HexDigitsUpper) +# define g_bBs3CurrentMode BS3_DATA_NM(g_bBs3CurrentMode) +# define g_uBs3TrapEipHint BS3_DATA_NM(g_uBs3TrapEipHint) +# define g_aBs3RmIvtOriginal BS3_DATA_NM(g_aBs3RmIvtOriginal) + +# define g_usBs3TestStep BS3_DATA_NM(g_usBs3TestStep) +# define g_usBs3TestStep BS3_DATA_NM(g_usBs3TestStep) +# define g_Bs3Trap16GenericEntriesFlatAddr BS3_DATA_NM(g_Bs3Trap16GenericEntriesFlatAddr) +# define g_Bs3Trap32GenericEntriesFlatAddr BS3_DATA_NM(g_Bs3Trap32GenericEntriesFlatAddr) +# define g_Bs3Trap64GenericEntriesFlatAddr BS3_DATA_NM(g_Bs3Trap64GenericEntriesFlatAddr) + +# define g_uBs3CpuDetected BS3_DATA_NM(g_uBs3CpuDetected) + +#endif /* ARCH_BITS == 64 */ +#endif /* not needed */ + +#endif /* !BS3KIT_INCLUDED_bs3kit_mangling_data_h */ + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3kit-template-footer.h b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3kit-template-footer.h new file mode 100644 index 00000000..043d6009 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3kit-template-footer.h @@ -0,0 +1,83 @@ +/* $Id: bs3kit-template-footer.h $ */ +/** @file + * BS3Kit footer for multi-mode code templates. + */ + +/* + * Copyright (C) 2007-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + + +/* + * Undefine macros defined by the header. + * This is a subset of what bs3kit-template-footer.mac does. + */ +#undef TMPL_RM +#undef TMPL_PE16 +#undef TMPL_PE16_32 +#undef TMPL_PE16_V86 +#undef TMPL_PE32 +#undef TMPL_PE32_16 +#undef TMPL_PEV86 +#undef TMPL_PP16 +#undef TMPL_PP16_32 +#undef TMPL_PP16_V86 +#undef TMPL_PP32 +#undef TMPL_PP32_16 +#undef TMPL_PPV86 +#undef TMPL_PAE16 +#undef TMPL_PAE16_32 +#undef TMPL_PAE16_V86 +#undef TMPL_PAE32 +#undef TMPL_PAE32_16 +#undef TMPL_PAEV86 +#undef TMPL_LM16 +#undef TMPL_LM32 +#undef TMPL_LM64 + +#undef TMPL_CMN_PE +#undef TMPL_SYS_PE16 +#undef TMPL_SYS_PE32 +#undef TMPL_CMN_PP +#undef TMPL_SYS_PP16 +#undef TMPL_SYS_PP32 +#undef TMPL_CMN_PAE +#undef TMPL_SYS_PAE16 +#undef TMPL_SYS_PAE32 +#undef TMPL_CMN_LM +#undef TMPL_CMN_V86 +#undef TMPL_CMN_R86 +#undef TMPL_CMN_PAGING +#undef TMPL_CMN_WEIRD +#undef TMPL_CMN_WEIRD_V86 + +#undef TMPL_CMN_R86 + +#undef TMPL_NM +#undef TMPL_FAR_NM +#undef TMPL_MODE +#undef TMPL_MODE_STR +#undef TMPL_MODE_LNAME +#undef TMPL_MODE_UNAME +#undef TMPL_16BIT +#undef TMPL_32BIT +#undef TMPL_64BIT +#undef TMPL_BITS + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3kit-template-footer.mac b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3kit-template-footer.mac new file mode 100644 index 00000000..b80f7d2c --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3kit-template-footer.mac @@ -0,0 +1,132 @@ +; $Id: bs3kit-template-footer.mac $ +;; @file +; BS3Kit footer for multi-mode code templates. +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + + +; +; Undefine macros defined by the header. +; +; Note! The following is useful for verifying that all macros are included here: +; +; for i in `grep "%define" bootsector2-template-header.mac \ +; | sed -e 's/^ *%define *//' -e 's/^\([^() ]*\).*$/\1/' \ +; | sort -u` +; do +; if ! grep -wF "%undef $i" bootsector2-template-footer.mac; then +; echo $i +; fi +; done +; +%undef TMPL_RM +%undef TMPL_PE16 +%undef TMPL_PE16_32 +%undef TMPL_PE16_V86 +%undef TMPL_PE32 +%undef TMPL_PE32_16 +%undef TMPL_PEV86 +%undef TMPL_PP16 +%undef TMPL_PP16_32 +%undef TMPL_PP16_V86 +%undef TMPL_PP32 +%undef TMPL_PP32_16 +%undef TMPL_PPV86 +%undef TMPL_PAE16 +%undef TMPL_PAE16_32 +%undef TMPL_PAE16_V86 +%undef TMPL_PAE32 +%undef TMPL_PAE32_16 +%undef TMPL_PAEV86 +%undef TMPL_LM16 +%undef TMPL_LM32 +%undef TMPL_LM64 + +%undef TMPL_CMN_PE +%undef TMPL_SYS_PE16 +%undef TMPL_SYS_PE32 +%undef TMPL_CMN_PP +%undef TMPL_SYS_PP16 +%undef TMPL_SYS_PP32 +%undef TMPL_CMN_PAE +%undef TMPL_SYS_PAE16 +%undef TMPL_SYS_PAE32 +%undef TMPL_CMN_LM +%undef TMPL_CMN_V86 +%undef TMPL_CMN_R86 +%undef TMPL_CMN_PAGING +%undef TMPL_CMN_WEIRD +%undef TMPL_CMN_WEIRD_V86 + +%undef TMPL_CMN_R86 + +%undef TMPL_NM +%undef TMPL_NM_U +%undef TMPL_FAR_NM +%undef BS3_CMN_NM +%undef TMPL_UNDESCORE +%undef TMPL_MODE_UNAME +%undef TMPL_MODE_LNAME +%undef TMPL_MODE_STR +%undef TMPL_16BIT +%undef TMPL_32BIT +%undef TMPL_64BIT +%undef TMPL_BITS +%undef TMPL_PTR_DEF +%undef TMPL_HAVE_BIOS +%undef TMPL_BEGINCODE + +%undef xCB +%undef xDEF +%undef xRES +%undef xPRE +%undef xSP +%undef xBP +%undef xAX +%undef xBX +%undef xCX +%undef xDX +%undef xDI +%undef xSI +%undef xWrtRIP + +%undef sCB +%undef sDEF +%undef sRES +%undef sPRE +%undef sSP +%undef sBP +%undef sAX +%undef sBX +%undef sCX +%undef sDX +%undef sDI +%undef sSI + +%unmacro TONLY16 1+ +%unmacro TONLY32 1+ +%unmacro TONLY64 1+ +%unmacro TNOT16 1+ +%unmacro TNOT32 1+ +%unmacro TNOT64 1+ + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3kit-template-header.h b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3kit-template-header.h new file mode 100644 index 00000000..ee1b7cf7 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3kit-template-header.h @@ -0,0 +1,522 @@ +/* $Id: bs3kit-template-header.h $ */ +/** @file + * BS3Kit header for multi-mode code templates. + */ + +/* + * Copyright (C) 2007-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + +#include "bs3kit.h" + +/** @defgroup grp_bs3kit_tmpl Multi-Mode Code Templates + * @ingroup grp_bs3kit + * + * Multi-mode code templates avoid duplicating code for each of the CPU modes. + * Instead the code is compiled multiple times, either via multiple inclusions + * into a source files with different mode selectors defined or by multiple + * compiler invocations. + * + * In C/C++ code we're restricted to the compiler target bit count, whereas in + * assembly we can do everything in assembler run (with some 64-bit + * restrictions, that is). + * + * Before \#defining the next mode selector and including + * bs3kit-template-header.h again, include bs3kit-template-footer.h to undefine + * all the previous mode selectors and the macros defined by the header. + * + * @{ + */ + +#ifdef DOXYGEN_RUNNING +/** @name Template mode selectors. + * + * Exactly one of these are defined by the file including the + * bs3kit-template-header.h header file. When building the code libraries, the + * kBuild target defines this. + * + * @{ */ +# define TMPL_RM /**< real mode. */ + +# define TMPL_PE16 /**< 16-bit protected mode kernel+tss, running 16-bit code, unpaged. */ +# define TMPL_PE16_32 /**< 16-bit protected mode kernel+tss, running 32-bit code, unpaged. */ +# define TMPL_PE16_V86 /**< 16-bit protected mode kernel+tss, running virtual 8086 mode code, unpaged. */ +# define TMPL_PE32 /**< 32-bit protected mode kernel+tss, running 32-bit code, unpaged. */ +# define TMPL_PE32_16 /**< 32-bit protected mode kernel+tss, running 16-bit code, unpaged. */ +# define TMPL_PEV86 /**< 32-bit protected mode kernel+tss, running virtual 8086 mode code, unpaged. */ + +# define TMPL_PP16 /**< 16-bit protected mode kernel+tss, running 16-bit code, paged. */ +# define TMPL_PP16_32 /**< 16-bit protected mode kernel+tss, running 32-bit code, paged. */ +# define TMPL_PP16_V86 /**< 16-bit protected mode kernel+tss, running virtual 8086 mode code, paged. */ +# define TMPL_PP32 /**< 32-bit protected mode kernel+tss, running 32-bit code, paged. */ +# define TMPL_PP32_16 /**< 32-bit protected mode kernel+tss, running 16-bit code, paged. */ +# define TMPL_PPV86 /**< 32-bit protected mode kernel+tss, running virtual 8086 mode code, paged. */ + +# define TMPL_PAE16 /**< 16-bit protected mode kernel+tss, running 16-bit code, PAE paging. */ +# define TMPL_PAE16_32 /**< 16-bit protected mode kernel+tss, running 32-bit code, PAE paging. */ +# define TMPL_PAE16_V86 /**< 16-bit protected mode kernel+tss, running virtual 8086 mode code, PAE paging. */ +# define TMPL_PAE32 /**< 32-bit protected mode kernel+tss, running 32-bit code, PAE paging. */ +# define TMPL_PAE32_16 /**< 32-bit protected mode kernel+tss, running 16-bit code, PAE paging. */ +# define TMPL_PAEV86 /**< 32-bit protected mode kernel+tss, running virtual 8086 mode code, PAE paging. */ + +# define TMPL_LM16 /**< 16-bit long mode (paged), kernel+tss always 64-bit. */ +# define TMPL_LM32 /**< 32-bit long mode (paged), kernel+tss always 64-bit. */ +# define TMPL_LM64 /**< 64-bit long mode (paged), kernel+tss always 64-bit. */ +/** @} */ + +/** @name Derived Indicators + * @{ */ +# define TMPL_CMN_PE /**< TMPL_PE16 | TMPL_PE16_32 | TMPL_PE16_V86 | TMPL_PE32 | TMPL_PE32_16 | TMPL_PEV86 */ +# define TMPL_SYS_PE16 /**< TMPL_PE16 | TMPL_PE16_32 | TMPL_PE16_V86 */ +# define TMPL_SYS_PE32 /**< TMPL_PE32 | TMPL_PE32_16 | TMPL_PEV86 */ +# define TMPL_CMN_PP /**< TMPL_PP16 | TMPL_PP16_32 | TMPL_PP16_V86 | TMPL_PP32 | TMPL_PP32_16 | TMPL_PPV86 */ +# define TMPL_SYS_PP16 /**< TMPL_PP16 | TMPL_PP16_32 | TMPL_PP16_V86 */ +# define TMPL_SYS_PP32 /**< TMPL_PP32 | TMPL_PP32_16 | TMPL_PPV86 */ +# define TMPL_CMN_PAE /**< TMPL_PAE16 | TMPL_PAE16_32 | TMPL_PAE16_V86 | TMPL_PAE32 | TMPL_PAE32_16 | TMPL_PAEV86 */ +# define TMPL_SYS_PAE16 /**< TMPL_PAE16 | TMPL_PAE16_32 | TMPL_PAE16_V86 */ +# define TMPL_SYS_PAE32 /**< TMPL_PAE32 | TMPL_PAE32_16 | TMPL_PAEV86 */ +# define TMPL_CMN_LM /**< TMPL_LM16 | TMPL_LM32 | TMPL_LM64 */ +# define TMPL_CMN_V86 /**< TMPL_PEV86 | TMPL_PE16_V86 | TMPL_PPV86 | TMPL_PP16_V86 | TMPL_PAEV86 | TMPL_PAE16_V86 */ +# define TMPL_CMN_R86 /**< TMPL_CMN_V86 | TMPL_RM */ +# define TMPL_CMN_PAGING /**< TMPL_CMN_PP | TMPL_CMN_PAE | TMPL_CMN_LM */ +# define TMPL_CMN_WEIRD /**< TMPL_PE16_32 | TMPL_PE32_16 | TMPL_PP16_32 | TMPL_PP32_16 | TMPL_PAE16_32 | TMPL_PAE32_16 | TMPL_CMN_WEIRD_V86 */ +# define TMPL_CMN_WEIRD_V86 /**< TMPL_PE16_V86 | TMPL_PP16_V86 | TMPL_PAE16_V86 */ +/** @} */ + +/** @def TMPL_NM + * Name mangling macro for the current mode. + * + * Example: TMPL_NM(PrintChr) + * + * @param Name The function or variable name to mangle. + * @sa #TMPL_FAR_NM, #BS3_CMN_NM, #BS3_CMN_FAR_NM + */ +# define TMPL_NM(Name) RT_CONCAT(Name,_mode) + +/** @def TMPL_FAR_NM + * Name mangling macro for the current mode into a far function name. + * + * In 32-bit and 64-bit code this does not differ from #TMPL_NM. + * + * Example: TMPL_FAR_NM(PrintChr) + * + * @param Name The function or variable name to mangle. + * @sa #TMPL_NM, #BS3_CMN_FAR_NM, #BS3_CMN_NM + */ +# define TMPL_FAR_NM(Name) RT_CONCAT3(Name,_mode,_far) + +/** @def TMPL_MODE_STR + * Short mode description. */ +# define TMPL_MODE_STR + +/** @def TMPL_HAVE_BIOS + * Indicates that we have direct access to the BIOS (only in real mode). */ +# define TMPL_HAVE_BIOS + + +/** @name For ASM compatability + * @{ */ +/** @def TMPL_16BIT + * For ASM compatibility - please use ARCH_BITS == 16. */ +# define TMPL_16BIT +/** @def TMPL_32BIT + * For ASM compatibility - please use ARCH_BITS == 32. */ +# define TMPL_32BIT +/** @def TMPL_64BIT + * For ASM compatibility - please use ARCH_BITS == 64. */ +# define TMPL_64BIT + +/** @def TMPL_BITS + * For ASM compatibility - please use ARCH_BITS instead. */ +# define TMPL_BITS ARCH_BITS +/** @} */ + +#else /* !DOXYGEN_RUNNING */ + +//#undef BS3_CMN_NM +//#undef BS3_CMN_FAR_NM + + +/* + * Convert TMPL_XXX to TMPL_MODE. + */ +#ifndef TMPL_MODE +# ifdef TMPL_RM +# define TMPL_MODE BS3_MODE_RM +# elif defined(TMPL_PE16) +# define TMPL_MODE BS3_MODE_PE16 +# elif defined(TMPL_PE16_32) +# define TMPL_MODE BS3_MODE_PE16_32 +# elif defined(TMPL_PE16_V86) +# define TMPL_MODE BS3_MODE_PE16_V86 +# elif defined(TMPL_PE32) +# define TMPL_MODE BS3_MODE_PE32 +# elif defined(TMPL_PE32_16) +# define TMPL_MODE BS3_MODE_PE32_16 +# elif defined(TMPL_PEV86) +# define TMPL_MODE BS3_MODE_PEV86 +# elif defined(TMPL_PP16) +# define TMPL_MODE BS3_MODE_PP16 +# elif defined(TMPL_PP16_32) +# define TMPL_MODE BS3_MODE_PP16_32 +# elif defined(TMPL_PP16_V86) +# define TMPL_MODE BS3_MODE_PP16_V86 +# elif defined(TMPL_PP32) +# define TMPL_MODE BS3_MODE_PP32 +# elif defined(TMPL_PP32_16) +# define TMPL_MODE BS3_MODE_PP32_16 +# elif defined(TMPL_PPV86) +# define TMPL_MODE BS3_MODE_PPV86 +# elif defined(TMPL_PAE16) +# define TMPL_MODE BS3_MODE_PAE16 +# elif defined(TMPL_PAE16_32) +# define TMPL_MODE BS3_MODE_PAE16_32 +# elif defined(TMPL_PAE16_V86) +# define TMPL_MODE BS3_MODE_PAE16_V86 +# elif defined(TMPL_PAE32) +# define TMPL_MODE BS3_MODE_PAE32 +# elif defined(TMPL_PAE32_16) +# define TMPL_MODE BS3_MODE_PAE32_16 +# elif defined(TMPL_PAEV86) +# define TMPL_MODE BS3_MODE_PAEV86 +# elif defined(TMPL_LM16) +# define TMPL_MODE BS3_MODE_LM16 +# elif defined(TMPL_LM32) +# define TMPL_MODE BS3_MODE_LM32 +# elif defined(TMPL_LM64) +# define TMPL_MODE BS3_MODE_LM64 +# else +# error "Unable to to figure out the template mode." +# endif +#endif + + +/* + * Check the code bitness and set derived defines. + */ +#if (TMPL_MODE & BS3_MODE_CODE_MASK) == BS3_MODE_CODE_16 +# if ARCH_BITS != 16 +# error "BS3_MODE_CODE_16 requires ARCH_BITS to be 16." +# endif +# define TMPL_16BIT +# define TMPL_BITS 16 +# define TMPL_UNDERSCORE _ +//# define BS3_CMN_NM(Name) RT_CONCAT(Name,_c16) +//# define BS3_CMN_FAR_NM(Name) RT_CONCAT(Name,_f16) + + +#elif (TMPL_MODE & BS3_MODE_CODE_MASK) == BS3_MODE_CODE_32 +# if ARCH_BITS != 32 +# error "BS3_MODE_CODE_32 requires ARCH_BITS to be 32." +# endif +# define TMPL_32BIT +# define TMPL_BITS 32 +# define TMPL_UNDERSCORE _ +//# define BS3_CMN_NM(Name) RT_CONCAT(Name,_c32) +//# define BS3_CMN_FAR_NM(a_Name) RT_CONCAT(Name,_c32) + +#elif (TMPL_MODE & BS3_MODE_CODE_MASK) == BS3_MODE_CODE_V86 +# if ARCH_BITS != 16 +# error "BS3_MODE_CODE_V86 requires ARCH_BITS to be 16." +# endif +# define TMPL_16BIT +# define TMPL_BITS 16 +# define TMPL_UNDERSCORE _ +//# define BS3_CMN_NM(Name) RT_CONCAT(Name,_c16) +//# define BS3_CMN_FAR_NM(Name) RT_CONCAT(Name,_f16) +# define TMPL_CMN_R86 +# define TMPL_CMN_V86 + +#elif (TMPL_MODE & BS3_MODE_CODE_MASK) == BS3_MODE_CODE_64 +# if ARCH_BITS != 64 +# error "BS3_MODE_CODE_64 requires ARCH_BITS to be 64." +# endif +# define TMPL_64BIT +# define TMPL_BITS 64 +# define TMPL_UNDERSCORE +//# define BS3_CMN_NM(Name) RT_CONCAT(Name,_c64) +//# define BS3_CMN_FAR_NM(a_Name) RT_CONCAT(Name,_c64) + +#else +# error "Invalid TMPL_MODE value!" +#endif + + +/* + * Check the system specific mask and set derived values. + */ +#if (TMPL_MODE & BS3_MODE_SYS_MASK) == BS3_MODE_SYS_RM +# define TMPL_HAVE_BIOS +# define TMPL_CMN_R86 + +#elif (TMPL_MODE & BS3_MODE_SYS_MASK) == BS3_MODE_SYS_PE16 +# define TMPL_SYS_PE16 +# define TMPL_CMN_PE + +#elif (TMPL_MODE & BS3_MODE_SYS_MASK) == BS3_MODE_SYS_PE32 +# define TMPL_SYS_PE32 +# define TMPL_CMN_PE + +#elif (TMPL_MODE & BS3_MODE_SYS_MASK) == BS3_MODE_SYS_PP16 +# define TMPL_SYS_PP16 +# define TMPL_CMN_PP +# define TMPL_CMN_PAGING + +#elif (TMPL_MODE & BS3_MODE_SYS_MASK) == BS3_MODE_SYS_PP32 +# define TMPL_SYS_PP32 +# define TMPL_CMN_PP +# define TMPL_CMN_PAGING + +#elif (TMPL_MODE & BS3_MODE_SYS_MASK) == BS3_MODE_SYS_PAE16 +# define TMPL_SYS_PAE16 +# define TMPL_CMN_PAE +# define TMPL_CMN_PAGING + +#elif (TMPL_MODE & BS3_MODE_SYS_MASK) == BS3_MODE_SYS_PAE32 +# define TMPL_SYS_PAE32 +# define TMPL_CMN_PAE +# define TMPL_CMN_PAGING + +#elif (TMPL_MODE & BS3_MODE_SYS_MASK) == BS3_MODE_SYS_LM +# define TMPL_SYS_LM +# define TMPL_CMN_LM +# define TMPL_CMN_PAGING + +#else +# error "Invalid TMPL_MODE value!" +#endif + + +/* + * Mode specific stuff. + */ +#if TMPL_MODE == BS3_MODE_RM +# define TMPL_RM 1 +# define TMPL_MODE_STR "real mode" +# define TMPL_NM(Name) RT_CONCAT(Name,_rm) +# define TMPL_MODE_LNAME rm +# define TMPL_MODE_UNAME RM + + +#elif TMPL_MODE == BS3_MODE_PE16 +# define TMPL_PE16 1 +# define TMPL_MODE_STR "16-bit prot, 16-bit" +# define TMPL_NM(Name) RT_CONCAT(Name,_pe16) +# define TMPL_MODE_LNAME pe16 +# define TMPL_MODE_UNAME PE16 + +#elif TMPL_MODE == BS3_MODE_PE16_32 +# define TMPL_PE16_32 1 +# define TMPL_MODE_STR "16-bit prot, 32-bit" +# define TMPL_NM(Name) RT_CONCAT(Name,_pe16_32) +# define TMPL_MODE_LNAME pe16_32 +# define TMPL_MODE_UNAME PE16_32 +# define TMPL_CMN_WEIRD + +#elif TMPL_MODE == BS3_MODE_PE16_V86 +# define TMPL_PE16_V86 1 +# define TMPL_MODE_STR "16-bit prot, v8086" +# define TMPL_NM(Name) RT_CONCAT(Name,_pe16_v86) +# define TMPL_MODE_LNAME pe16_v86 +# define TMPL_MODE_UNAME PE16_v86 +# define TMPL_CMN_WEIRD +# define TMPL_CMN_WEIRD_V86 + + +#elif TMPL_MODE == BS3_MODE_PE32 +# define TMPL_PE32 1 +# define TMPL_MODE_STR "32-bit prot, 32-bit" +# define TMPL_NM(Name) RT_CONCAT(Name,_pe32) +# define TMPL_MODE_LNAME pe32 +# define TMPL_MODE_UNAME PE32 + +#elif TMPL_MODE == BS3_MODE_PE32_16 +# define TMPL_PE32_16 1 +# define TMPL_MODE_STR "32-bit prot, 16-bit" +# define TMPL_NM(Name) RT_CONCAT(Name,_pe32_16) +# define TMPL_MODE_LNAME pe32_16 +# define TMPL_MODE_UNAME PE32_16 +# define TMPL_CMN_WEIRD + +#elif TMPL_MODE == BS3_MODE_PEV86 +# define TMPL_PEV86 1 +# define TMPL_MODE_STR "32-bit prot, v8086" +# define TMPL_NM(Name) RT_CONCAT(Name,_pev86) +# define TMPL_MODE_LNAME pev86 +# define TMPL_MODE_UNAME PEV86 + + +#elif TMPL_MODE == BS3_MODE_PP16 +# define TMPL_PP16 1 +# define TMPL_MODE_STR "16-bit paged, 16-bit" +# define TMPL_NM(Name) RT_CONCAT(Name,_pp16) +# define TMPL_MODE_LNAME pp16 +# define TMPL_MODE_UNAME PP16 + +#elif TMPL_MODE == BS3_MODE_PP16_32 +# define TMPL_PP16_32 1 +# define TMPL_MODE_STR "16-bit paged, 32-bit" +# define TMPL_NM(Name) RT_CONCAT(Name,_pp16_32) +# define TMPL_MODE_LNAME pp16_32 +# define TMPL_MODE_UNAME PP16_32 +# define TMPL_CMN_WEIRD + +#elif TMPL_MODE == BS3_MODE_PP16_V86 +# define TMPL_PP16_V86 1 +# define TMPL_MODE_STR "16-bit paged, v8086" +# define TMPL_NM(Name) RT_CONCAT(Name,_pp16_v86) +# define TMPL_MODE_LNAME pp16_v86 +# define TMPL_MODE_UNAME PP16_v86 +# define TMPL_CMN_WEIRD +# define TMPL_CMN_WEIRD_V86 + + +#elif TMPL_MODE == BS3_MODE_PP32 +# define TMPL_PP32 1 +# define TMPL_MODE_STR "32-bit paged, 32-bit" +# define TMPL_NM(Name) RT_CONCAT(Name,_pp32) +# define TMPL_MODE_LNAME pp32 +# define TMPL_MODE_UNAME PP32 + +#elif TMPL_MODE == BS3_MODE_PP32_16 +# define TMPL_PP32_16 1 +# define TMPL_MODE_STR "32-bit paged, 16-bit" +# define TMPL_NM(Name) RT_CONCAT(Name,_pp32_16) +# define TMPL_MODE_LNAME pp32_16 +# define TMPL_MODE_UNAME PP32_16 +# define TMPL_CMN_WEIRD + +#elif TMPL_MODE == BS3_MODE_PPV86 +# define TMPL_PPV86 1 +# define TMPL_MODE_STR "32-bit paged, v8086" +# define TMPL_NM(Name) RT_CONCAT(Name,_ppv86) +# define TMPL_MODE_LNAME ppv86 +# define TMPL_MODE_UNAME PPV86 + + +#elif TMPL_MODE == BS3_MODE_PAE16 +# define TMPL_PAE16 1 +# define TMPL_MODE_STR "16-bit pae, 16-bit" +# define TMPL_NM(Name) RT_CONCAT(Name,_pae16) +# define TMPL_MODE_LNAME pae16 +# define TMPL_MODE_UNAME PAE16 + +#elif TMPL_MODE == BS3_MODE_PAE16_32 +# define TMPL_PAE16_32 1 +# define TMPL_MODE_STR "16-bit pae, 32-bit" +# define TMPL_NM(Name) RT_CONCAT(Name,_pae16_32) +# define TMPL_MODE_LNAME pae16_32 +# define TMPL_MODE_UNAME PAE16_32 +# define TMPL_CMN_WEIRD + +#elif TMPL_MODE == BS3_MODE_PAE16_V86 +# define TMPL_PAE16_V86 1 +# define TMPL_MODE_STR "16-bit pae, v8086" +# define TMPL_NM(Name) RT_CONCAT(Name,_pae16_v86) +# define TMPL_MODE_LNAME pae16_v86 +# define TMPL_MODE_UNAME PAE16_v86 +# define TMPL_CMN_WEIRD +# define TMPL_CMN_WEIRD_V86 + + +#elif TMPL_MODE == BS3_MODE_PAE32 +# define TMPL_PAE32 1 +# define TMPL_MODE_STR "32-bit pae, 32-bit" +# define TMPL_NM(Name) RT_CONCAT(Name,_pae32) +# define TMPL_MODE_LNAME pae32 +# define TMPL_MODE_UNAME PAE32 + +#elif TMPL_MODE == BS3_MODE_PAE32_16 +# define TMPL_PAE32_16 1 +# define TMPL_MODE_STR "32-bit pae, 32-bit" +# define TMPL_NM(Name) RT_CONCAT(Name,_pae32_16) +# define TMPL_MODE_LNAME pae32_16 +# define TMPL_MODE_UNAME PAE32_16 +# define TMPL_CMN_WEIRD + +#elif TMPL_MODE == BS3_MODE_PAEV86 +# define TMPL_PAEV86 1 +# define TMPL_MODE_STR "32-bit pae, v8086 pae" +# define TMPL_NM(Name) RT_CONCAT(Name,_paev86) +# define TMPL_MODE_LNAME paev86 +# define TMPL_MODE_UNAME PAEV86 + + +#elif TMPL_MODE == BS3_MODE_LM16 +# define TMPL_LM16 1 +# define TMPL_MODE_STR "long, 16-bit" +# define TMPL_NM(Name) RT_CONCAT(Name,_lm16) +# define TMPL_MODE_LNAME lm16 +# define TMPL_MODE_UNAME LM16 + +#elif TMPL_MODE == BS3_MODE_LM32 +# define TMPL_LM32 1 +# define TMPL_MODE_STR "long, 32-bit" +# define TMPL_NM(Name) RT_CONCAT(Name,_lm32) +# define TMPL_MODE_LNAME lm32 +# define TMPL_MODE_UNAME LM32 + +#elif TMPL_MODE == BS3_MODE_LM64 +# define TMPL_LM64 1 +# define TMPL_MODE_STR "long, 64-bit" +# define TMPL_NM(Name) RT_CONCAT(Name,_lm64) +# define TMPL_MODE_LNAME lm64 +# define TMPL_MODE_UNAME LM64 + +#else +# error "Invalid TMPL_MODE value!!" +#endif + + +#if TMPL_MODE & (BS3_MODE_CODE_16 | BS3_MODE_CODE_V86) +# define TMPL_FAR_NM(Name) RT_CONCAT3(TMPL_NM(Name),_f,ar) /* _far and far may be #defined already. */ +#else +# define TMPL_FAR_NM(Name) TMPL_NM(Name) +#endif + + +/** @def BS3_MODE_DEF + * Macro for defining a mode specific function. + * + * This makes 16-bit mode functions far, while 32-bit and 64-bit are near. + * You need to update the make file to generate near->far wrappers in most + * cases. + * + * @param a_RetType The return type. + * @param a_Name The function basename. + * @param a_Params The parameter list (in parentheses). + * + * @sa BS3_MODE_PROTO + */ +#if ARCH_BITS == 16 +# define BS3_MODE_DEF(a_RetType, a_Name, a_Params) BS3_DECL_FAR(a_RetType) TMPL_FAR_NM(a_Name) a_Params +#else +# define BS3_MODE_DEF(a_RetType, a_Name, a_Params) BS3_DECL_NEAR(a_RetType) TMPL_NM(a_Name) a_Params +#endif + + + +#ifndef TMPL_MODE_STR +# error "internal error" +#endif + +#endif /* !DOXYGEN_RUNNING */ +/** @} */ + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3kit-template-header.mac b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3kit-template-header.mac new file mode 100644 index 00000000..0b705e78 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3kit-template-header.mac @@ -0,0 +1,522 @@ +; $Id: bs3kit-template-header.mac $ +;; @file +; BS3Kit header for multi-mode code templates. +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + +%include "bs3kit.mac" + +; +; Check and expand the mode defines. +; One of the following must be defined: +; - TMPL_RM - real mode. +; - TMPL_PE16 - 16-bit protected mode, unpaged. +; - TMPL_PE32 - 32-bit protected mode, unpaged. +; - TMPL_PEV86 - virtual 8086 mode under protected mode, unpaged. +; - TMPL_PP16 - 16-bit protected mode, paged. +; - TMPL_PP32 - 32-bit protected mode, paged. +; - TMPL_PPV86 - virtual 8086 mode under protected mode, paged. +; - TMPL_PAE16 - 16-bit protected mode with PAE (paged). +; - TMPL_PAE32 - 16-bit protected mode with PAE (paged). +; - TMPL_PAEV86- virtual 8086 mode under protected mode with PAE (paged). +; - TMPL_LM16 - 16-bit long mode (paged). +; - TMPL_LM32 - 32-bit long mode (paged). +; - TMPL_LM64 - 64-bit long mode (paged). +; +; Derived indicators: +; - TMPL_CMN_PE = TMPL_PE16 | TMPL_PE32 | TMPL_PEV86 +; - TMPL_CMN_PP = TMPL_PP16 | TMPL_PP32 | TMPL_PPV86 +; - TMPL_CMN_PAE = TMPL_PAE16 | TMPL_PAE32 | TMPL_PAEV86 +; - TMPL_CMN_LM = TMPL_LM16 | TMPL_LM32 | TMPL_LM64 +; - TMPL_CMN_V86 = TMPL_PEV86 | TMPL_PPV86 | TMPL_PAEV86 +; - TMPL_CMN_R86 = TMPL_CMN_V86 | TMPL_RM +; - TMPL_CMN_PAGING = TMPL_CMN_PP | TMPL_CMN_PAE | TMPL_CMN_LM +; + + +; +; Convert TMPL_XXX to TMPL_MODE. +; +%ifndef TMPL_MODE + %ifdef TMPL_RM + %define TMPL_MODE BS3_MODE_RM + %elifdef TMPL_PE16 + %define TMPL_MODE BS3_MODE_PE16 + %elifdef TMPL_PE16_32 + %define TMPL_MODE BS3_MODE_PE16_32 + %elifdef TMPL_PE16_V86 + %define TMPL_MODE BS3_MODE_PE16_V86 + %elifdef TMPL_PE32 + %define TMPL_MODE BS3_MODE_PE32 + %elifdef TMPL_PE32_16 + %define TMPL_MODE BS3_MODE_PE32_16 + %elifdef TMPL_PEV86 + %define TMPL_MODE BS3_MODE_PEV86 + %elifdef TMPL_PP16 + %define TMPL_MODE BS3_MODE_PP16 + %elifdef TMPL_PP16_32 + %define TMPL_MODE BS3_MODE_PP16_32 + %elifdef TMPL_PP16_V86 + %define TMPL_MODE BS3_MODE_PP16_V86 + %elifdef TMPL_PP32 + %define TMPL_MODE BS3_MODE_PP32 + %elifdef TMPL_PP32_16 + %define TMPL_MODE BS3_MODE_PP32_16 + %elifdef TMPL_PPV86 + %define TMPL_MODE BS3_MODE_PPV86 + %elifdef TMPL_PAE16 + %define TMPL_MODE BS3_MODE_PAE16 + %elifdef TMPL_PAE16_32 + %define TMPL_MODE BS3_MODE_PAE16_32 + %elifdef TMPL_PAE16_V86 + %define TMPL_MODE BS3_MODE_PAE16_V86 + %elifdef TMPL_PAE32 + %define TMPL_MODE BS3_MODE_PAE32 + %elifdef TMPL_PAE32_16 + %define TMPL_MODE BS3_MODE_PAE32_16 + %elifdef TMPL_PAEV86 + %define TMPL_MODE BS3_MODE_PAEV86 + %elifdef TMPL_LM16 + %define TMPL_MODE BS3_MODE_LM16 + %elifdef TMPL_LM32 + %define TMPL_MODE BS3_MODE_LM32 + %elifdef TMPL_LM64 + %define TMPL_MODE BS3_MODE_LM64 + %else + %error "Unable to to figure out the template mode." + %endif +%endif + +; +; Check the code bitness and set TMPL_XXBITS, TMPL_BITS, BS3_CMN_NM +; +%if (TMPL_MODE & BS3_MODE_CODE_MASK) == BS3_MODE_CODE_16 + %define TMPL_16BIT + %define TMPL_BITS 16 + %define TMPL_PTR_DEF dw + %define TMPL_UNDERSCORE _ + %define BS3_CMN_NM(Name) _ %+ Name %+ _c16 + +%elif (TMPL_MODE & BS3_MODE_CODE_MASK) == BS3_MODE_CODE_32 + %define TMPL_32BIT + %define TMPL_BITS 32 + %define TMPL_PTR_DEF dd + %define TMPL_UNDERSCORE _ + %define BS3_CMN_NM(Name) _ %+ Name %+ _c32 + +%elif (TMPL_MODE & BS3_MODE_CODE_MASK) == BS3_MODE_CODE_V86 + %define TMPL_16BIT + %define TMPL_BITS 16 + %define TMPL_UNDERSCORE _ + %define BS3_CMN_NM(Name) _ %+ Name %+ _c16 + %define TMPL_CMN_R86 + %define TMPL_CMN_V86 + +%elif (TMPL_MODE & BS3_MODE_CODE_MASK) == BS3_MODE_CODE_64 + %define TMPL_64BIT + %define TMPL_BITS 64 + %define TMPL_PTR_DEF dq + %define TMPL_UNDERSCORE _ + %define BS3_CMN_NM(Name) _ %+ Name %+ _c64 + +%else + %error "Invalid TMPL_MODE value!" +%endif + +; +; Check the system specific mask and set derived values. +; +%if (TMPL_MODE & BS3_MODE_SYS_MASK) == BS3_MODE_SYS_RM + %define TMPL_HAVE_BIOS + %define TMPL_CMN_R86 + +%elif (TMPL_MODE & BS3_MODE_SYS_MASK) == BS3_MODE_SYS_PE16 + %define TMPL_SYS_PE16 + %define TMPL_CMN_PE + +%elif (TMPL_MODE & BS3_MODE_SYS_MASK) == BS3_MODE_SYS_PE32 + %define TMPL_SYS_PE32 + %define TMPL_CMN_PE + +%elif (TMPL_MODE & BS3_MODE_SYS_MASK) == BS3_MODE_SYS_PP16 + %define TMPL_SYS_PP16 + %define TMPL_CMN_PP + %define TMPL_CMN_PAGING + +%elif (TMPL_MODE & BS3_MODE_SYS_MASK) == BS3_MODE_SYS_PP32 + %define TMPL_SYS_PP32 + %define TMPL_CMN_PP + %define TMPL_CMN_PAGING + +%elif (TMPL_MODE & BS3_MODE_SYS_MASK) == BS3_MODE_SYS_PAE16 + %define TMPL_SYS_PAE16 + %define TMPL_CMN_PAE + %define TMPL_CMN_PAGING + +%elif (TMPL_MODE & BS3_MODE_SYS_MASK) == BS3_MODE_SYS_PAE32 + %define TMPL_SYS_PAE32 + %define TMPL_CMN_PAE + %define TMPL_CMN_PAGING + +%elif (TMPL_MODE & BS3_MODE_SYS_MASK) == BS3_MODE_SYS_LM + %define TMPL_SYS_LM + %define TMPL_CMN_LM + %define TMPL_CMN_PAGING + +%else + %error "Invalid TMPL_MODE value!" +%endif + + +; +; Mode specific stuff. +; +%if TMPL_MODE == BS3_MODE_RM + %define TMPL_RM + %define TMPL_MODE_STR "real mode" + %define TMPL_NM(Name) _ %+ Name %+ _rm + %define TMPL_MODE_LNAME rm + %define TMPL_MODE_UNAME RM + + +%elif TMPL_MODE == BS3_MODE_PE16 + %define TMPL_PE16 + %define TMPL_MODE_STR "16-bit prot, 16-bit" + %define TMPL_NM(Name) _ %+ Name %+ _pe16 + %define TMPL_MODE_LNAME pe16 + %define TMPL_MODE_UNAME PE16 + +%elif TMPL_MODE == BS3_MODE_PE16_32 + %define TMPL_PE16_32 + %define TMPL_MODE_STR "16-bit prot, 32-bit" + %define TMPL_NM(Name) _ %+ Name %+ _pe16_32 + %define TMPL_MODE_LNAME pe16_32 + %define TMPL_MODE_UNAME PE16_32 + %define TMPL_CMN_WEIRD + +%elif TMPL_MODE == BS3_MODE_PE16_V86 + %define TMPL_PE16_V86 + %define TMPL_MODE_STR "16-bit prot, v8086" + %define TMPL_NM(Name) _ %+ Name %+ _pe16_v86 + %define TMPL_MODE_LNAME pe16_v86 + %define TMPL_MODE_UNAME PE16_v86 + %define TMPL_CMN_WEIRD + %define TMPL_CMN_WEIRD_V86 + + +%elif TMPL_MODE == BS3_MODE_PE32 + %define TMPL_PE32 + %define TMPL_MODE_STR "32-bit prot, 32-bit" + %define TMPL_NM(Name) _ %+ Name %+ _pe32 + %define TMPL_MODE_LNAME pe32 + %define TMPL_MODE_UNAME PE32 + +%elif TMPL_MODE == BS3_MODE_PE32_16 + %define TMPL_PE32_16 + %define TMPL_MODE_STR "32-bit prot, 16-bit" + %define TMPL_NM(Name) _ %+ Name %+ _pe32_16 + %define TMPL_MODE_LNAME pe32_16 + %define TMPL_MODE_UNAME PE32_16 + %define TMPL_CMN_WEIRD + +%elif TMPL_MODE == BS3_MODE_PEV86 + %define TMPL_PEV86 + %define TMPL_MODE_STR "32-bit prot, v8086" + %define TMPL_NM(Name) _ %+ Name %+ _pev86 + %define TMPL_MODE_LNAME pev86 + %define TMPL_MODE_UNAME PEV86 + + +%elif TMPL_MODE == BS3_MODE_PP16 + %define TMPL_PP16 + %define TMPL_MODE_STR "16-bit paged, 16-bit" + %define TMPL_NM(Name) _ %+ Name %+ _pp16 + %define TMPL_MODE_LNAME pp16 + %define TMPL_MODE_UNAME PP16 + +%elif TMPL_MODE == BS3_MODE_PP16_32 + %define TMPL_PP16_32 + %define TMPL_MODE_STR "16-bit paged, 32-bit" + %define TMPL_NM(Name) _ %+ Name %+ _pp16_32 + %define TMPL_MODE_LNAME pp16_32 + %define TMPL_MODE_UNAME PP16_32 + %define TMPL_CMN_WEIRD + +%elif TMPL_MODE == BS3_MODE_PP16_V86 + %define TMPL_PP16_V86 + %define TMPL_MODE_STR "16-bit paged, v8086" + %define TMPL_NM(Name) _ %+ Name %+ _pp16_v86 + %define TMPL_MODE_LNAME pp16_v86 + %define TMPL_MODE_UNAME PP16_v86 + %define TMPL_CMN_WEIRD + %define TMPL_CMN_WEIRD_V86 + + +%elif TMPL_MODE == BS3_MODE_PP32 + %define TMPL_PP32 + %define TMPL_MODE_STR "32-bit paged, 32-bit" + %define TMPL_NM(Name) _ %+ Name %+ _pp32 + %define TMPL_MODE_LNAME pp32 + %define TMPL_MODE_UNAME PP32 + +%elif TMPL_MODE == BS3_MODE_PP32_16 + %define TMPL_PP32_16 + %define TMPL_MODE_STR "32-bit paged, 16-bit" + %define TMPL_NM(Name) _ %+ Name %+ _pp32_16 + %define TMPL_MODE_LNAME pp32_16 + %define TMPL_MODE_UNAME PP32_16 + %define TMPL_CMN_WEIRD + +%elif TMPL_MODE == BS3_MODE_PPV86 + %define TMPL_PPV86 + %define TMPL_MODE_STR "32-bit paged, v8086" + %define TMPL_NM(Name) _ %+ Name %+ _ppv86 + %define TMPL_MODE_LNAME ppv86 + %define TMPL_MODE_UNAME PPV86 + + +%elif TMPL_MODE == BS3_MODE_PAE16 + %define TMPL_PAE16 + %define TMPL_MODE_STR "16-bit pae, 16-bit" + %define TMPL_NM(Name) _ %+ Name %+ _pae16 + %define TMPL_MODE_LNAME pae16 + %define TMPL_MODE_UNAME PAE16 + +%elif TMPL_MODE == BS3_MODE_PAE16_32 + %define TMPL_PAE16_32 + %define TMPL_MODE_STR "16-bit pae, 32-bit" + %define TMPL_NM(Name) _ %+ Name %+ _pae16_32 + %define TMPL_MODE_LNAME pae16_32 + %define TMPL_MODE_UNAME PAE16_32 + %define TMPL_CMN_WEIRD + +%elif TMPL_MODE == BS3_MODE_PAE16_V86 + %define TMPL_PAE16_V86 + %define TMPL_MODE_STR "16-bit pae, v8086" + %define TMPL_NM(Name) _ %+ Name %+ _pae16_v86 + %define TMPL_MODE_LNAME pae16_v86 + %define TMPL_MODE_UNAME PAE16_v86 + %define TMPL_CMN_WEIRD + %define TMPL_CMN_WEIRD_V86 + + +%elif TMPL_MODE == BS3_MODE_PAE32 + %define TMPL_PAE32 + %define TMPL_MODE_STR "32-bit pae, 32-bit" + %define TMPL_NM(Name) _ %+ Name %+ _pae32 + %define TMPL_MODE_LNAME pae32 + %define TMPL_MODE_UNAME PAE32 + +%elif TMPL_MODE == BS3_MODE_PAE32_16 + %define TMPL_PAE32_16 + %define TMPL_MODE_STR "32-bit pae, 16-bit" + %define TMPL_NM(Name) _ %+ Name %+ _pae32_16 + %define TMPL_MODE_LNAME pae32_16 + %define TMPL_MODE_UNAME PAE32_16 + %define TMPL_CMN_WEIRD + +%elif TMPL_MODE == BS3_MODE_PAEV86 + %define TMPL_PAEV86 + %define TMPL_MODE_STR "32-bit pae, v8086 pae" + %define TMPL_NM(Name) _ %+ Name %+ _paev86 + %define TMPL_MODE_LNAME paev86 + %define TMPL_MODE_UNAME PAEV86 + + +%elif TMPL_MODE == BS3_MODE_LM16 + %define TMPL_LM16 + %define TMPL_MODE_STR "long, 16-bit" + %define TMPL_NM(Name) _ %+ Name %+ _lm16 + %define TMPL_MODE_LNAME lm16 + %define TMPL_MODE_UNAME LM16 + +%elif TMPL_MODE == BS3_MODE_LM32 + %define TMPL_LM32 + %define TMPL_MODE_STR "long, 32-bit" + %define TMPL_NM(Name) _ %+ Name %+ _lm32 + %define TMPL_MODE_LNAME lm32 + %define TMPL_MODE_UNAME LM32 + +%elif TMPL_MODE == BS3_MODE_LM64 + %define TMPL_LM64 + %define TMPL_MODE_STR "long, 64-bit" + %define TMPL_NM(Name) _ %+ Name %+ _lm64 + %define TMPL_MODE_LNAME lm64 + %define TMPL_MODE_UNAME LM64 + +%else + %error "Invalid TMPL_MODE value!!" +%endif + +%ifnidn TMPL_UNDERSCORE,_; RT_CONCAT3 doesn't work with TMPL_UNDERSCORE being empty. duh. + %ifidn RT_CONCAT(TestName_,TMPL_MODE_LNAME),TMPL_NM(TestName) + %else + %error internal error: RT_CONCAT(TestName_,TMPL_MODE_LNAME) vs TMPL_NM(TestName) + %endif +%else + %ifidn RT_CONCAT3(TMPL_UNDERSCORE,TestName_,TMPL_MODE_LNAME),TMPL_NM(TestName) + %else + %error internal error: RT_CONCAT3(TMPL_UNDERSCORE,TestName_,TMPL_MODE_LNAME) vs TMPL_NM(TestName) + %endif +%endif + +; TMPL_NM version with uppercased suffix and no underscore separating them. +%define TMPL_NM_U(Name) TMPL_UNDERSCORE %+ Name %+ TMPL_MODE_UNAME + +; TMPL_FAR_NM +%if TMPL_MODE & (BS3_MODE_CODE_16 | BS3_MODE_CODE_V86) + %define TMPL_FAR_NM(Name) TMPL_NM(Name) %+ _far +%else + %define TMPL_FAR_NM(Name) TMPL_NM(Name) +%endif + + +;; @def TMPL_WRT_FLAT +; WRT flat when not in 16-bit modes. +; +%ifdef TMPL_16BIT + %define TMPL_WRT_FLAT +%else + %define TMPL_WRT_FLAT wrt FLAT +%endif + +;; @def TMPL_WRT_DATA16_OR_FLAT +; WRT DATA16 in 16-bit mode, WRT FLAT in 32- and 64-bit modes. +; This is important when accessing global variables. +; +%ifdef TMPL_16BIT + %define TMPL_WRT_DATA16_OR_FLAT wrt BS3KIT_GRPNM_DATA16 +%else + %define TMPL_WRT_DATA16_OR_FLAT wrt FLAT +%endif + +;; @def TMPL_DATA16_WRT +; WRT DATA16 in 16-bit mode, WRT FLAT in 32- and 64-bit modes. +; This is important when accessing global variables. +; +%if TMPL_BITS == 16 + %define TMPL_DATA16_WRT(a_Var) a_Var wrt BS3KIT_GRPNM_DATA16 +%elif TMPL_BITS == 32 + %define TMPL_DATA16_WRT(a_Var) a_Var wrt FLAT +%elif TMPL_BITS == 64 + %define TMPL_DATA16_WRT(a_Var) rel a_Var wrt FLAT +%else + %error TMPL_BITS +%endif + +;; @def TMPL_WRT_SYSTEM16_OR_FLAT +; WRT BS3SYSTEM16 in 16-bit mode, WRT FLAT in 32- and 64-bit modes. +; This is important when accessing global variables in the BS3SYSTEM16 segment. +%ifdef TMPL_16BIT + %define TMPL_WRT_SYSTEM16_OR_FLAT wrt BS3SYSTEM16 +%else + %define TMPL_WRT_SYSTEM16_OR_FLAT wrt FLAT +%endif + +;; @def TONLY16 +; Version of BONLY16 that follows the code template. +; Like BONLY16 this normally goes in column 1. +%if TMPL_BITS == 16 + %macro TONLY16 1+ + %1 + %endmacro +%else + %macro TONLY16 1+ + %endmacro +%endif + +;; @def TONLY32 +; Version of BONLY32 that follows the code template. +; Like BONLY32 this normally goes in column 1. +%if TMPL_BITS == 32 + %macro TONLY32 1+ + %1 + %endmacro +%else + %macro TONLY32 1+ + %endmacro +%endif + +;; @def TONLY64 +; Version of BONLY64 that follows the code template. +; Like BONLY64 this normally goes in column 1. +%if TMPL_BITS == 64 + %macro TONLY64 1+ + %1 + %endmacro +%else + %macro TONLY64 1+ + %endmacro +%endif + +;; @def TNOT16 +; Version of BNOT16 that follows the code template. +; Like BNOT16 this normally goes in column 1. +%if TMPL_BITS == 16 + %macro TNOT16 1+ + %endmacro +%else + %macro TNOT16 1+ + %1 + %endmacro +%endif + +;; @def TNOT32 +; Version of BNOT32 that follows the code template. +; Like BNOT32 this normally goes in column 1. +%if TMPL_BITS == 32 + %macro TNOT32 1+ + %endmacro +%else + %macro TNOT32 1+ + %1 + %endmacro +%endif + +;; @def TNOT64 +; Version of BNOT64 that follows the code template. +; Like BNOT64 this normally goes in column 1. +%if TMPL_BITS == 64 + %macro TNOT64 1+ + %endmacro +%else + %macro TNOT64 1+ + %1 + %endmacro +%endif + + +; +; Default code segment (changes BITS too). +; +%ifdef TMPL_64BIT + %define TMPL_BEGIN_TEXT BS3_BEGIN_TEXT64 +%elifdef TMPL_32BIT + %define TMPL_BEGIN_TEXT BS3_BEGIN_TEXT32 +%elifdef TMPL_16BIT + %define TMPL_BEGIN_TEXT BS3_BEGIN_TEXT16 +%else + %error "Missing TMPL_xxBIT!" +%endif +TMPL_BEGIN_TEXT + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3kit.h b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3kit.h new file mode 100644 index 00000000..5cbbcf17 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3kit.h @@ -0,0 +1,3957 @@ +/* $Id: bs3kit.h $ */ +/** @file + * BS3Kit - structures, symbols, macros and stuff. + */ + +/* + * Copyright (C) 2007-2019 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL) only, as it comes in the "COPYING.CDDL" file of the + * VirtualBox OSE distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + */ + +#ifndef BS3KIT_INCLUDED_bs3kit_h +#define BS3KIT_INCLUDED_bs3kit_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#ifndef DOXYGEN_RUNNING +# undef IN_RING0 +# define IN_RING0 +#endif + +#define RT_NO_STRICT /* Don't drag in IPRT assertion code in inline code we may use (asm.h). */ +#include <iprt/cdefs.h> +#include <iprt/types.h> + +#ifndef DOXYGEN_RUNNING +# undef IN_RING0 +#endif + +/* + * Make asm.h and friend compatible with our 64-bit assembly config (ASM_CALL64_MSC). + */ +#if defined(__GNUC__) && ARCH_BITS == 64 +# undef DECLASM +# ifdef __cplusplus +# define DECLASM(type) extern "C" type BS3_CALL +# else +# define DECLASM(type) type BS3_CALL +# endif +#endif + + +/* + * Work around ms_abi trouble in the gcc camp (gcc bugzilla #50818). + * ASSUMES all va_lists are in functions with + */ +#if defined(__GNUC__) && ARCH_BITS == 64 +# undef va_list +# undef va_start +# undef va_end +# undef va_copy +# define va_list __builtin_ms_va_list +# define va_start(a_Va, a_Arg) __builtin_ms_va_start(a_Va, a_Arg) +# define va_end(a_Va) __builtin_ms_va_end(a_Va) +# define va_copy(a_DstVa, a_SrcVa) __builtin_ms_va_copy(a_DstVa, a_SrcVa) +#endif + + +/** @def BS3_USE_ALT_16BIT_TEXT_SEG + * @ingroup grp_bs3kit + * Combines the BS3_USE_RM_TEXT_SEG, BS3_USE_X0_TEXT_SEG, and + * BS3_USE_X1_TEXT_SEG indicators into a single one. + */ +#if defined(BS3_USE_RM_TEXT_SEG) || defined(BS3_USE_X0_TEXT_SEG) || defined(BS3_USE_X1_TEXT_SEG) || defined(DOXYGEN_RUNNING) +# define BS3_USE_ALT_16BIT_TEXT_SEG +#else +# undef BS3_USE_ALT_16BIT_TEXT_SEG +#endif + +/** @def BS3_USE_X0_TEXT_SEG + * @ingroup grp_bs3kit + * Emit 16-bit code to the BS3X0TEXT16 segment - ignored for 32-bit and 64-bit. + * + * Calling directly into the BS3X0TEXT16 segment is only possible in real-mode + * and v8086 mode. In protected mode the real far pointer have to be converted + * to a protected mode pointer that uses BS3_SEL_X0TEXT16_CS, Bs3TestDoModes and + * associates does this automatically. + */ +#ifdef DOXYGEN_RUNNING +# define BS3_USE_X0_TEXT_SEG +#endif + +/** @def BS3_USE_X1_TEXT_SEG + * @ingroup grp_bs3kit + * Emit 16-bit code to the BS3X1TEXT16 segment - ignored for 32-bit and 64-bit. + * + * Calling directly into the BS3X1TEXT16 segment is only possible in real-mode + * and v8086 mode. In protected mode the real far pointer have to be converted + * to a protected mode pointer that uses BS3_SEL_X1TEXT16_CS, Bs3TestDoModes and + * associates does this automatically. + */ +#ifdef DOXYGEN_RUNNING +# define BS3_USE_X1_TEXT_SEG +#endif + +/** @def BS3_USE_RM_TEXT_SEG + * @ingroup grp_bs3kit + * Emit 16-bit code to the BS3RMTEXT16 segment - ignored for 32-bit and 64-bit. + * + * This segment is normally used for real-mode only code, though + * BS3_SEL_RMTEXT16_CS can be used to call it from protected mode. Unlike the + * BS3X0TEXT16 and BS3X1TEXT16 segments which are empty by default, this segment + * is used by common BS3Kit code. + */ +#ifdef DOXYGEN_RUNNING +# define BS3_USE_X0_TEXT_SEG +#endif + +/** @def BS3_MODEL_FAR_CODE + * @ingroup grp_bs3kit + * Default compiler model indicates far code. + */ +#ifdef DOXYGEN_RUNNING +# define BS3_MODEL_FAR_CODE +#elif !defined(BS3_MODEL_FAR_CODE) && (defined(__LARGE__) || defined(__MEDIUM__) || defined(__HUGE__)) && ARCH_BITS == 16 +# define BS3_MODEL_FAR_CODE +#endif + + +/* + * We normally don't want the noreturn / aborts attributes as they mess up stack traces. + * + * Note! pragma aux <fnname> aborts can only be used with functions + * implemented in C and functions that does not have parameters. + */ +#define BS3_KIT_WITH_NO_RETURN +#ifndef BS3_KIT_WITH_NO_RETURN +# undef DECL_NO_RETURN +# define DECL_NO_RETURN(type) type +#endif + + +/* + * We may want to reuse some IPRT code in the common name space, so we + * redefine the RT_MANGLER to work like BS3_CMN_NM. (We cannot use + * BS3_CMN_NM yet, as we need to include IPRT headers with function + * declarations before we can define it. Thus the duplciate effort.) + */ +#if ARCH_BITS == 16 +# undef RTCALL +# if defined(BS3_USE_ALT_16BIT_TEXT_SEG) +# define RTCALL __cdecl __far +# define RT_MANGLER(a_Name) RT_CONCAT(a_Name,_f16) +# else +# define RTCALL __cdecl __near +# define RT_MANGLER(a_Name) RT_CONCAT(a_Name,_c16) +# endif +#else +# define RT_MANGLER(a_Name) RT_CONCAT3(a_Name,_c,ARCH_BITS) +#endif +#include <iprt/mangling.h> +#include <iprt/x86.h> +#include <iprt/err.h> + +/* + * Include data symbol mangling (function mangling/mapping must be done + * after the protypes). + */ +#include "bs3kit-mangling-data.h" + + + +RT_C_DECLS_BEGIN + +/** @defgroup grp_bs3kit BS3Kit - Boot Sector Kit \#3 + * + * The BS3Kit is a framework for bare metal floppy/usb image tests, + * see the @ref pg_bs3kit "doc page" for more. + * + * @{ */ + +/** @name Execution modes. + * @{ */ +#define BS3_MODE_INVALID UINT8_C(0x00) +#define BS3_MODE_RM UINT8_C(0x01) /**< real mode. */ +#define BS3_MODE_PE16 UINT8_C(0x11) /**< 16-bit protected mode kernel+tss, running 16-bit code, unpaged. */ +#define BS3_MODE_PE16_32 UINT8_C(0x12) /**< 16-bit protected mode kernel+tss, running 32-bit code, unpaged. */ +#define BS3_MODE_PE16_V86 UINT8_C(0x18) /**< 16-bit protected mode kernel+tss, running virtual 8086 mode code, unpaged. */ +#define BS3_MODE_PE32 UINT8_C(0x22) /**< 32-bit protected mode kernel+tss, running 32-bit code, unpaged. */ +#define BS3_MODE_PE32_16 UINT8_C(0x21) /**< 32-bit protected mode kernel+tss, running 16-bit code, unpaged. */ +#define BS3_MODE_PEV86 UINT8_C(0x28) /**< 32-bit protected mode kernel+tss, running virtual 8086 mode code, unpaged. */ +#define BS3_MODE_PP16 UINT8_C(0x31) /**< 16-bit protected mode kernel+tss, running 16-bit code, paged. */ +#define BS3_MODE_PP16_32 UINT8_C(0x32) /**< 16-bit protected mode kernel+tss, running 32-bit code, paged. */ +#define BS3_MODE_PP16_V86 UINT8_C(0x38) /**< 16-bit protected mode kernel+tss, running virtual 8086 mode code, paged. */ +#define BS3_MODE_PP32 UINT8_C(0x42) /**< 32-bit protected mode kernel+tss, running 32-bit code, paged. */ +#define BS3_MODE_PP32_16 UINT8_C(0x41) /**< 32-bit protected mode kernel+tss, running 16-bit code, paged. */ +#define BS3_MODE_PPV86 UINT8_C(0x48) /**< 32-bit protected mode kernel+tss, running virtual 8086 mode code, paged. */ +#define BS3_MODE_PAE16 UINT8_C(0x51) /**< 16-bit protected mode kernel+tss, running 16-bit code, PAE paging. */ +#define BS3_MODE_PAE16_32 UINT8_C(0x52) /**< 16-bit protected mode kernel+tss, running 32-bit code, PAE paging. */ +#define BS3_MODE_PAE16_V86 UINT8_C(0x58) /**< 16-bit protected mode kernel+tss, running virtual 8086 mode, PAE paging. */ +#define BS3_MODE_PAE32 UINT8_C(0x62) /**< 32-bit protected mode kernel+tss, running 32-bit code, PAE paging. */ +#define BS3_MODE_PAE32_16 UINT8_C(0x61) /**< 32-bit protected mode kernel+tss, running 16-bit code, PAE paging. */ +#define BS3_MODE_PAEV86 UINT8_C(0x68) /**< 32-bit protected mode kernel+tss, running virtual 8086 mode, PAE paging. */ +#define BS3_MODE_LM16 UINT8_C(0x71) /**< 16-bit long mode (paged), kernel+tss always 64-bit. */ +#define BS3_MODE_LM32 UINT8_C(0x72) /**< 32-bit long mode (paged), kernel+tss always 64-bit. */ +#define BS3_MODE_LM64 UINT8_C(0x74) /**< 64-bit long mode (paged), kernel+tss always 64-bit. */ + +#define BS3_MODE_CODE_MASK UINT8_C(0x0f) /**< Running code mask. */ +#define BS3_MODE_CODE_16 UINT8_C(0x01) /**< Running 16-bit code. */ +#define BS3_MODE_CODE_32 UINT8_C(0x02) /**< Running 32-bit code. */ +#define BS3_MODE_CODE_64 UINT8_C(0x04) /**< Running 64-bit code. */ +#define BS3_MODE_CODE_V86 UINT8_C(0x08) /**< Running 16-bit virtual 8086 code. */ + +#define BS3_MODE_SYS_MASK UINT8_C(0xf0) /**< kernel+tss mask. */ +#define BS3_MODE_SYS_RM UINT8_C(0x00) /**< Real mode kernel+tss. */ +#define BS3_MODE_SYS_PE16 UINT8_C(0x10) /**< 16-bit protected mode kernel+tss. */ +#define BS3_MODE_SYS_PE32 UINT8_C(0x20) /**< 32-bit protected mode kernel+tss. */ +#define BS3_MODE_SYS_PP16 UINT8_C(0x30) /**< 16-bit paged protected mode kernel+tss. */ +#define BS3_MODE_SYS_PP32 UINT8_C(0x40) /**< 32-bit paged protected mode kernel+tss. */ +#define BS3_MODE_SYS_PAE16 UINT8_C(0x50) /**< 16-bit PAE paged protected mode kernel+tss. */ +#define BS3_MODE_SYS_PAE32 UINT8_C(0x60) /**< 32-bit PAE paged protected mode kernel+tss. */ +#define BS3_MODE_SYS_LM UINT8_C(0x70) /**< 64-bit (paged) long mode protected mode kernel+tss. */ + +/** Whether the mode has paging enabled. */ +#define BS3_MODE_IS_PAGED(a_fMode) ((a_fMode) >= BS3_MODE_PP16) +/** Whether the mode has legacy paging enabled (legacy as opposed to PAE or + * long mode). */ +#define BS3_MODE_IS_LEGACY_PAGING(a_fMode) ((a_fMode) >= BS3_MODE_PP16 && (a_fMode) < BS3_MODE_PAE16) + +/** Whether the mode is running v8086 code. */ +#define BS3_MODE_IS_V86(a_fMode) (((a_fMode) & BS3_MODE_CODE_MASK) == BS3_MODE_CODE_V86) +/** Whether the we're executing in real mode or v8086 mode. */ +#define BS3_MODE_IS_RM_OR_V86(a_fMode) ((a_fMode) == BS3_MODE_RM || BS3_MODE_IS_V86(a_fMode)) +/** Whether the mode is running 16-bit code, except v8086. */ +#define BS3_MODE_IS_16BIT_CODE_NO_V86(a_fMode) (((a_fMode) & BS3_MODE_CODE_MASK) == BS3_MODE_CODE_16) +/** Whether the mode is running 16-bit code (includes v8086). */ +#define BS3_MODE_IS_16BIT_CODE(a_fMode) (BS3_MODE_IS_16BIT_CODE_NO_V86(a_fMode) || BS3_MODE_IS_V86(a_fMode)) +/** Whether the mode is running 32-bit code. */ +#define BS3_MODE_IS_32BIT_CODE(a_fMode) (((a_fMode) & BS3_MODE_CODE_MASK) == BS3_MODE_CODE_32) +/** Whether the mode is running 64-bit code. */ +#define BS3_MODE_IS_64BIT_CODE(a_fMode) (((a_fMode) & BS3_MODE_CODE_MASK) == BS3_MODE_CODE_64) + +/** Whether the system is in real mode. */ +#define BS3_MODE_IS_RM_SYS(a_fMode) (((a_fMode) & BS3_MODE_SYS_MASK) == BS3_MODE_SYS_RM) +/** Whether the system is some 16-bit mode that isn't real mode. */ +#define BS3_MODE_IS_16BIT_SYS_NO_RM(a_fMode) ( ((a_fMode) & BS3_MODE_SYS_MASK) == BS3_MODE_SYS_PE16 \ + || ((a_fMode) & BS3_MODE_SYS_MASK) == BS3_MODE_SYS_PP16 \ + || ((a_fMode) & BS3_MODE_SYS_MASK) == BS3_MODE_SYS_PAE16) +/** Whether the system is some 16-bit mode (includes real mode). */ +#define BS3_MODE_IS_16BIT_SYS(a_fMode) (BS3_MODE_IS_16BIT_SYS_NO_RM(a_fMode) || BS3_MODE_IS_RM_SYS(a_fMode)) +/** Whether the system is some 32-bit mode. */ +#define BS3_MODE_IS_32BIT_SYS(a_fMode) ( ((a_fMode) & BS3_MODE_SYS_MASK) == BS3_MODE_SYS_PE32 \ + || ((a_fMode) & BS3_MODE_SYS_MASK) == BS3_MODE_SYS_PP32 \ + || ((a_fMode) & BS3_MODE_SYS_MASK) == BS3_MODE_SYS_PAE32) +/** Whether the system is long mode. */ +#define BS3_MODE_IS_64BIT_SYS(a_fMode) (((a_fMode) & BS3_MODE_SYS_MASK) == BS3_MODE_SYS_LM) + +/** Whether the system is in protected mode (with or without paging). + * @note Long mode is not included. */ +#define BS3_MODE_IS_PM_SYS(a_fMode) ((a_fMode) >= BS3_MODE_SYS_PE16 && (a_fMode) < BS3_MODE_SYS_LM) + +/** @todo testcase: How would long-mode handle a 16-bit TSS loaded prior to the switch? (mainly stack switching wise) Hopefully, it will tripple fault, right? */ +/** @} */ + + +/** @name BS3_ADDR_XXX - Static Memory Allocation + * @{ */ +/** The flat load address for the code after the bootsector. */ +#define BS3_ADDR_LOAD 0x10000 +/** Where we save the boot registers during init. + * Located right before the code. */ +#define BS3_ADDR_REG_SAVE (BS3_ADDR_LOAD - sizeof(BS3REGCTX) - 8) +/** Where the stack starts (initial RSP value). + * Located 16 bytes (assumed by boot sector) before the saved registers. + * SS.BASE=0. The size is a little short of 32KB */ +#define BS3_ADDR_STACK (BS3_ADDR_REG_SAVE - 16) +/** The ring-0 stack (8KB) for ring transitions. */ +#define BS3_ADDR_STACK_R0 0x06000 +/** The ring-1 stack (8KB) for ring transitions. */ +#define BS3_ADDR_STACK_R1 0x04000 +/** The ring-2 stack (8KB) for ring transitions. */ +#define BS3_ADDR_STACK_R2 0x02000 +/** IST1 ring-0 stack for long mode (4KB), used for double faults elsewhere. */ +#define BS3_ADDR_STACK_R0_IST1 0x09000 +/** IST2 ring-0 stack for long mode (3KB), used for spare 0 stack elsewhere. */ +#define BS3_ADDR_STACK_R0_IST2 0x08000 +/** IST3 ring-0 stack for long mode (1KB). */ +#define BS3_ADDR_STACK_R0_IST3 0x07400 +/** IST4 ring-0 stack for long mode (1KB), used for spare 1 stack elsewhere. */ +#define BS3_ADDR_STACK_R0_IST4 0x07000 +/** IST5 ring-0 stack for long mode (1KB). */ +#define BS3_ADDR_STACK_R0_IST5 0x06c00 +/** IST6 ring-0 stack for long mode (1KB). */ +#define BS3_ADDR_STACK_R0_IST6 0x06800 +/** IST7 ring-0 stack for long mode (1KB). */ +#define BS3_ADDR_STACK_R0_IST7 0x06400 + +/** The base address of the BS3TEXT16 segment (same as BS3_LOAD_ADDR). + * @sa BS3_SEL_TEXT16 */ +#define BS3_ADDR_BS3TEXT16 0x10000 +/** The base address of the BS3SYSTEM16 segment. + * @sa BS3_SEL_SYSTEM16 */ +#define BS3_ADDR_BS3SYSTEM16 0x20000 +/** The base address of the BS3DATA16/BS3KIT_GRPNM_DATA16 segment. + * @sa BS3_SEL_DATA16 */ +#define BS3_ADDR_BS3DATA16 0x29000 +/** @} */ + +/** @name BS3_SEL_XXX - GDT selector assignments. + * + * The real mode segment numbers for BS16TEXT, BS16DATA and BS16SYSTEM are + * present in the GDT, this allows the 16-bit C/C++ and assembly code to + * continue using the real mode segment values in ring-0 protected mode. + * + * The three segments have fixed locations: + * | segment | flat address | real mode segment | + * | ----------- | ------------ | ----------------- | + * | BS3TEXT16 | 0x00010000 | 1000h | + * | BS3SYSTEM16 | 0x00020000 | 2000h | + * | BS3DATA16 | 0x00029000 | 2900h | + * + * This means that we've got a lot of GDT space to play around with. + * + * @{ */ +#define BS3_SEL_LDT 0x0010 /**< The LDT selector for Bs3Ldt. */ +#define BS3_SEL_TSS16 0x0020 /**< The 16-bit TSS selector. */ +#define BS3_SEL_TSS16_DF 0x0028 /**< The 16-bit TSS selector for double faults. */ +#define BS3_SEL_TSS16_SPARE0 0x0030 /**< The 16-bit TSS selector for testing. */ +#define BS3_SEL_TSS16_SPARE1 0x0038 /**< The 16-bit TSS selector for testing. */ +#define BS3_SEL_TSS32 0x0040 /**< The 32-bit TSS selector. */ +#define BS3_SEL_TSS32_DF 0x0048 /**< The 32-bit TSS selector for double faults. */ +#define BS3_SEL_TSS32_SPARE0 0x0050 /**< The 32-bit TSS selector for testing. */ +#define BS3_SEL_TSS32_SPARE1 0x0058 /**< The 32-bit TSS selector for testing. */ +#define BS3_SEL_TSS32_IOBP_IRB 0x0060 /**< The 32-bit TSS selector with I/O permission and interrupt redirection bitmaps. */ +#define BS3_SEL_TSS32_IRB 0x0068 /**< The 32-bit TSS selector with only interrupt redirection bitmap (IOPB stripped by limit). */ +#define BS3_SEL_TSS64 0x0070 /**< The 64-bit TSS selector. */ +#define BS3_SEL_TSS64_SPARE0 0x0080 /**< The 64-bit TSS selector. */ +#define BS3_SEL_TSS64_SPARE1 0x0090 /**< The 64-bit TSS selector. */ +#define BS3_SEL_TSS64_IOBP 0x00a0 /**< The 64-bit TSS selector. */ + +#define BS3_SEL_RMTEXT16_CS 0x00e0 /**< Conforming code selector for accessing the BS3RMTEXT16 segment. Runtime config. */ +#define BS3_SEL_X0TEXT16_CS 0x00e8 /**< Conforming code selector for accessing the BS3X0TEXT16 segment. Runtime config. */ +#define BS3_SEL_X1TEXT16_CS 0x00f0 /**< Conforming code selector for accessing the BS3X1TEXT16 segment. Runtime config. */ +#define BS3_SEL_VMMDEV_MMIO16 0x00f8 /**< Selector for accessing the VMMDev MMIO segment at 0100000h from 16-bit code. */ + +/** Checks if @a uSel is in the BS3_SEL_RX_XXX range. */ +#define BS3_SEL_IS_IN_RING_RANGE(uSel) ( (unsigned)(uSel - BS3_SEL_R0_FIRST) < (unsigned)(4 << BS3_SEL_RING_SHIFT) ) +#define BS3_SEL_RING_SHIFT 8 /**< For the formula: BS3_SEL_R0_XXX + ((cs & 3) << BS3_SEL_RING_SHIFT) */ +#define BS3_SEL_RING_SUB_MASK 0x00f8 /**< Mask for getting the sub-selector. For use with BS3_SEL_R*_FIRST. */ + +/** Checks if @a uSel is in the BS3_SEL_R0_XXX range. */ +#define BS3_SEL_IS_IN_R0_RANGE(uSel) ( (unsigned)(uSel - BS3_SEL_R0_FIRST) < (unsigned)(1 << BS3_SEL_RING_SHIFT) ) +#define BS3_SEL_R0_FIRST 0x0100 /**< The first selector in the ring-0 block. */ +#define BS3_SEL_R0_CS16 0x0100 /**< ring-0: 16-bit code selector, base 0x10000. */ +#define BS3_SEL_R0_DS16 0x0108 /**< ring-0: 16-bit data selector, base 0x23000. */ +#define BS3_SEL_R0_SS16 0x0110 /**< ring-0: 16-bit stack selector, base 0x00000. */ +#define BS3_SEL_R0_CS32 0x0118 /**< ring-0: 32-bit flat code selector. */ +#define BS3_SEL_R0_DS32 0x0120 /**< ring-0: 32-bit flat data selector. */ +#define BS3_SEL_R0_SS32 0x0128 /**< ring-0: 32-bit flat stack selector. */ +#define BS3_SEL_R0_CS64 0x0130 /**< ring-0: 64-bit flat code selector. */ +#define BS3_SEL_R0_DS64 0x0138 /**< ring-0: 64-bit flat data & stack selector. */ +#define BS3_SEL_R0_CS16_EO 0x0140 /**< ring-0: 16-bit execute-only code selector, not accessed, 0xfffe limit, CS16 base. */ +#define BS3_SEL_R0_CS16_CNF 0x0148 /**< ring-0: 16-bit conforming code selector, not accessed, 0xfffe limit, CS16 base. */ +#define BS3_SEL_R0_CS16_CNF_EO 0x0150 /**< ring-0: 16-bit execute-only conforming code selector, not accessed, 0xfffe limit, CS16 base. */ +#define BS3_SEL_R0_CS32_EO 0x0158 /**< ring-0: 32-bit execute-only code selector, not accessed, flat. */ +#define BS3_SEL_R0_CS32_CNF 0x0160 /**< ring-0: 32-bit conforming code selector, not accessed, flat. */ +#define BS3_SEL_R0_CS32_CNF_EO 0x0168 /**< ring-0: 32-bit execute-only conforming code selector, not accessed, flat. */ +#define BS3_SEL_R0_CS64_EO 0x0170 /**< ring-0: 64-bit execute-only code selector, not accessed, flat. */ +#define BS3_SEL_R0_CS64_CNF 0x0178 /**< ring-0: 64-bit conforming code selector, not accessed, flat. */ +#define BS3_SEL_R0_CS64_CNF_EO 0x0180 /**< ring-0: 64-bit execute-only conforming code selector, not accessed, flat. */ + +#define BS3_SEL_R1_FIRST 0x0200 /**< The first selector in the ring-1 block. */ +#define BS3_SEL_R1_CS16 0x0200 /**< ring-1: 16-bit code selector, base 0x10000. */ +#define BS3_SEL_R1_DS16 0x0208 /**< ring-1: 16-bit data selector, base 0x23000. */ +#define BS3_SEL_R1_SS16 0x0210 /**< ring-1: 16-bit stack selector, base 0x00000. */ +#define BS3_SEL_R1_CS32 0x0218 /**< ring-1: 32-bit flat code selector. */ +#define BS3_SEL_R1_DS32 0x0220 /**< ring-1: 32-bit flat data selector. */ +#define BS3_SEL_R1_SS32 0x0228 /**< ring-1: 32-bit flat stack selector. */ +#define BS3_SEL_R1_CS64 0x0230 /**< ring-1: 64-bit flat code selector. */ +#define BS3_SEL_R1_DS64 0x0238 /**< ring-1: 64-bit flat data & stack selector. */ +#define BS3_SEL_R1_CS16_EO 0x0240 /**< ring-1: 16-bit execute-only code selector, not accessed, 0xfffe limit, CS16 base. */ +#define BS3_SEL_R1_CS16_CNF 0x0248 /**< ring-1: 16-bit conforming code selector, not accessed, 0xfffe limit, CS16 base. */ +#define BS3_SEL_R1_CS16_CNF_EO 0x0250 /**< ring-1: 16-bit execute-only conforming code selector, not accessed, 0xfffe limit, CS16 base. */ +#define BS3_SEL_R1_CS32_EO 0x0258 /**< ring-1: 32-bit execute-only code selector, not accessed, flat. */ +#define BS3_SEL_R1_CS32_CNF 0x0260 /**< ring-1: 32-bit conforming code selector, not accessed, flat. */ +#define BS3_SEL_R1_CS32_CNF_EO 0x0268 /**< ring-1: 32-bit execute-only conforming code selector, not accessed, flat. */ +#define BS3_SEL_R1_CS64_EO 0x0270 /**< ring-1: 64-bit execute-only code selector, not accessed, flat. */ +#define BS3_SEL_R1_CS64_CNF 0x0278 /**< ring-1: 64-bit conforming code selector, not accessed, flat. */ +#define BS3_SEL_R1_CS64_CNF_EO 0x0280 /**< ring-1: 64-bit execute-only conforming code selector, not accessed, flat. */ + +#define BS3_SEL_R2_FIRST 0x0300 /**< The first selector in the ring-2 block. */ +#define BS3_SEL_R2_CS16 0x0300 /**< ring-2: 16-bit code selector, base 0x10000. */ +#define BS3_SEL_R2_DS16 0x0308 /**< ring-2: 16-bit data selector, base 0x23000. */ +#define BS3_SEL_R2_SS16 0x0310 /**< ring-2: 16-bit stack selector, base 0x00000. */ +#define BS3_SEL_R2_CS32 0x0318 /**< ring-2: 32-bit flat code selector. */ +#define BS3_SEL_R2_DS32 0x0320 /**< ring-2: 32-bit flat data selector. */ +#define BS3_SEL_R2_SS32 0x0328 /**< ring-2: 32-bit flat stack selector. */ +#define BS3_SEL_R2_CS64 0x0330 /**< ring-2: 64-bit flat code selector. */ +#define BS3_SEL_R2_DS64 0x0338 /**< ring-2: 64-bit flat data & stack selector. */ +#define BS3_SEL_R2_CS16_EO 0x0340 /**< ring-2: 16-bit execute-only code selector, not accessed, 0xfffe limit, CS16 base. */ +#define BS3_SEL_R2_CS16_CNF 0x0348 /**< ring-2: 16-bit conforming code selector, not accessed, 0xfffe limit, CS16 base. */ +#define BS3_SEL_R2_CS16_CNF_EO 0x0350 /**< ring-2: 16-bit execute-only conforming code selector, not accessed, 0xfffe limit, CS16 base. */ +#define BS3_SEL_R2_CS32_EO 0x0358 /**< ring-2: 32-bit execute-only code selector, not accessed, flat. */ +#define BS3_SEL_R2_CS32_CNF 0x0360 /**< ring-2: 32-bit conforming code selector, not accessed, flat. */ +#define BS3_SEL_R2_CS32_CNF_EO 0x0368 /**< ring-2: 32-bit execute-only conforming code selector, not accessed, flat. */ +#define BS3_SEL_R2_CS64_EO 0x0370 /**< ring-2: 64-bit execute-only code selector, not accessed, flat. */ +#define BS3_SEL_R2_CS64_CNF 0x0378 /**< ring-2: 64-bit conforming code selector, not accessed, flat. */ +#define BS3_SEL_R2_CS64_CNF_EO 0x0380 /**< ring-2: 64-bit execute-only conforming code selector, not accessed, flat. */ + +#define BS3_SEL_R3_FIRST 0x0400 /**< The first selector in the ring-3 block. */ +#define BS3_SEL_R3_CS16 0x0400 /**< ring-3: 16-bit code selector, base 0x10000. */ +#define BS3_SEL_R3_DS16 0x0408 /**< ring-3: 16-bit data selector, base 0x23000. */ +#define BS3_SEL_R3_SS16 0x0410 /**< ring-3: 16-bit stack selector, base 0x00000. */ +#define BS3_SEL_R3_CS32 0x0418 /**< ring-3: 32-bit flat code selector. */ +#define BS3_SEL_R3_DS32 0x0420 /**< ring-3: 32-bit flat data selector. */ +#define BS3_SEL_R3_SS32 0x0428 /**< ring-3: 32-bit flat stack selector. */ +#define BS3_SEL_R3_CS64 0x0430 /**< ring-3: 64-bit flat code selector. */ +#define BS3_SEL_R3_DS64 0x0438 /**< ring-3: 64-bit flat data & stack selector. */ +#define BS3_SEL_R3_CS16_EO 0x0440 /**< ring-3: 16-bit execute-only code selector, not accessed, 0xfffe limit, CS16 base. */ +#define BS3_SEL_R3_CS16_CNF 0x0448 /**< ring-3: 16-bit conforming code selector, not accessed, 0xfffe limit, CS16 base. */ +#define BS3_SEL_R3_CS16_CNF_EO 0x0450 /**< ring-3: 16-bit execute-only conforming code selector, not accessed, 0xfffe limit, CS16 base. */ +#define BS3_SEL_R3_CS32_EO 0x0458 /**< ring-3: 32-bit execute-only code selector, not accessed, flat. */ +#define BS3_SEL_R3_CS32_CNF 0x0460 /**< ring-3: 32-bit conforming code selector, not accessed, flat. */ +#define BS3_SEL_R3_CS32_CNF_EO 0x0468 /**< ring-3: 32-bit execute-only conforming code selector, not accessed, flat. */ +#define BS3_SEL_R3_CS64_EO 0x0470 /**< ring-3: 64-bit execute-only code selector, not accessed, flat. */ +#define BS3_SEL_R3_CS64_CNF 0x0478 /**< ring-3: 64-bit conforming code selector, not accessed, flat. */ +#define BS3_SEL_R3_CS64_CNF_EO 0x0480 /**< ring-3: 64-bit execute-only conforming code selector, not accessed, flat. */ + +#define BS3_SEL_R3_LAST 0x04f8 /**< ring-3: Last of the BS3_SEL_RX_XXX range. */ + +#define BS3_SEL_SPARE_FIRST 0x0500 /**< The first selector in the spare block */ +#define BS3_SEL_SPARE_00 0x0500 /**< Spare selector number 00h. */ +#define BS3_SEL_SPARE_01 0x0508 /**< Spare selector number 01h. */ +#define BS3_SEL_SPARE_02 0x0510 /**< Spare selector number 02h. */ +#define BS3_SEL_SPARE_03 0x0518 /**< Spare selector number 03h. */ +#define BS3_SEL_SPARE_04 0x0520 /**< Spare selector number 04h. */ +#define BS3_SEL_SPARE_05 0x0528 /**< Spare selector number 05h. */ +#define BS3_SEL_SPARE_06 0x0530 /**< Spare selector number 06h. */ +#define BS3_SEL_SPARE_07 0x0538 /**< Spare selector number 07h. */ +#define BS3_SEL_SPARE_08 0x0540 /**< Spare selector number 08h. */ +#define BS3_SEL_SPARE_09 0x0548 /**< Spare selector number 09h. */ +#define BS3_SEL_SPARE_0a 0x0550 /**< Spare selector number 0ah. */ +#define BS3_SEL_SPARE_0b 0x0558 /**< Spare selector number 0bh. */ +#define BS3_SEL_SPARE_0c 0x0560 /**< Spare selector number 0ch. */ +#define BS3_SEL_SPARE_0d 0x0568 /**< Spare selector number 0dh. */ +#define BS3_SEL_SPARE_0e 0x0570 /**< Spare selector number 0eh. */ +#define BS3_SEL_SPARE_0f 0x0578 /**< Spare selector number 0fh. */ +#define BS3_SEL_SPARE_10 0x0580 /**< Spare selector number 10h. */ +#define BS3_SEL_SPARE_11 0x0588 /**< Spare selector number 11h. */ +#define BS3_SEL_SPARE_12 0x0590 /**< Spare selector number 12h. */ +#define BS3_SEL_SPARE_13 0x0598 /**< Spare selector number 13h. */ +#define BS3_SEL_SPARE_14 0x05a0 /**< Spare selector number 14h. */ +#define BS3_SEL_SPARE_15 0x05a8 /**< Spare selector number 15h. */ +#define BS3_SEL_SPARE_16 0x05b0 /**< Spare selector number 16h. */ +#define BS3_SEL_SPARE_17 0x05b8 /**< Spare selector number 17h. */ +#define BS3_SEL_SPARE_18 0x05c0 /**< Spare selector number 18h. */ +#define BS3_SEL_SPARE_19 0x05c8 /**< Spare selector number 19h. */ +#define BS3_SEL_SPARE_1a 0x05d0 /**< Spare selector number 1ah. */ +#define BS3_SEL_SPARE_1b 0x05d8 /**< Spare selector number 1bh. */ +#define BS3_SEL_SPARE_1c 0x05e0 /**< Spare selector number 1ch. */ +#define BS3_SEL_SPARE_1d 0x05e8 /**< Spare selector number 1dh. */ +#define BS3_SEL_SPARE_1e 0x05f0 /**< Spare selector number 1eh. */ +#define BS3_SEL_SPARE_1f 0x05f8 /**< Spare selector number 1fh. */ + +#define BS3_SEL_TILED 0x0600 /**< 16-bit data tiling: First - base=0x00000000, limit=64KB, DPL=3. */ +#define BS3_SEL_TILED_LAST 0x0df8 /**< 16-bit data tiling: Last - base=0x00ff0000, limit=64KB, DPL=3. */ +#define BS3_SEL_TILED_AREA_SIZE 0x001000000 /**< 16-bit data tiling: Size of addressable area, in bytes. (16 MB) */ + +#define BS3_SEL_FREE_PART1 0x0e00 /**< Free selector space - part \#1. */ +#define BS3_SEL_FREE_PART1_LAST 0x0ff8 /**< Free selector space - part \#1, last entry. */ + +#define BS3_SEL_TEXT16 0x1000 /**< The BS3TEXT16 selector. */ + +#define BS3_SEL_FREE_PART2 0x1008 /**< Free selector space - part \#2. */ +#define BS3_SEL_FREE_PART2_LAST 0x17f8 /**< Free selector space - part \#2, last entry. */ + +#define BS3_SEL_TILED_R0 0x1800 /**< 16-bit data/stack tiling: First - base=0x00000000, limit=64KB, DPL=0. */ +#define BS3_SEL_TILED_R0_LAST 0x1ff8 /**< 16-bit data/stack tiling: Last - base=0x00ff0000, limit=64KB, DPL=0. */ + +#define BS3_SEL_SYSTEM16 0x2000 /**< The BS3SYSTEM16 selector. */ + +#define BS3_SEL_FREE_PART3 0x2008 /**< Free selector space - part \#3. */ +#define BS3_SEL_FREE_PART3_LAST 0x28f8 /**< Free selector space - part \#3, last entry. */ + +#define BS3_SEL_DATA16 0x2900 /**< The BS3DATA16/BS3KIT_GRPNM_DATA16 selector. */ + +#define BS3_SEL_FREE_PART4 0x2908 /**< Free selector space - part \#4. */ +#define BS3_SEL_FREE_PART4_LAST 0x2f98 /**< Free selector space - part \#4, last entry. */ + +#define BS3_SEL_PRE_TEST_PAGE_08 0x2fa0 /**< Selector located 8 selectors before the test page. */ +#define BS3_SEL_PRE_TEST_PAGE_07 0x2fa8 /**< Selector located 7 selectors before the test page. */ +#define BS3_SEL_PRE_TEST_PAGE_06 0x2fb0 /**< Selector located 6 selectors before the test page. */ +#define BS3_SEL_PRE_TEST_PAGE_05 0x2fb8 /**< Selector located 5 selectors before the test page. */ +#define BS3_SEL_PRE_TEST_PAGE_04 0x2fc0 /**< Selector located 4 selectors before the test page. */ +#define BS3_SEL_PRE_TEST_PAGE_03 0x2fc8 /**< Selector located 3 selectors before the test page. */ +#define BS3_SEL_PRE_TEST_PAGE_02 0x2fd0 /**< Selector located 2 selectors before the test page. */ +#define BS3_SEL_PRE_TEST_PAGE_01 0x2fd8 /**< Selector located 1 selector before the test page. */ +#define BS3_SEL_TEST_PAGE 0x2fe0 /**< Start of the test page intended for playing around with paging and GDT. */ +#define BS3_SEL_TEST_PAGE_00 0x2fe0 /**< Test page selector number 00h (convenience). */ +#define BS3_SEL_TEST_PAGE_01 0x2fe8 /**< Test page selector number 01h (convenience). */ +#define BS3_SEL_TEST_PAGE_02 0x2ff0 /**< Test page selector number 02h (convenience). */ +#define BS3_SEL_TEST_PAGE_03 0x2ff8 /**< Test page selector number 03h (convenience). */ +#define BS3_SEL_TEST_PAGE_04 0x3000 /**< Test page selector number 04h (convenience). */ +#define BS3_SEL_TEST_PAGE_05 0x3008 /**< Test page selector number 05h (convenience). */ +#define BS3_SEL_TEST_PAGE_06 0x3010 /**< Test page selector number 06h (convenience). */ +#define BS3_SEL_TEST_PAGE_07 0x3018 /**< Test page selector number 07h (convenience). */ +#define BS3_SEL_TEST_PAGE_LAST 0x3fd0 /**< The last selector in the spare page. */ + +#define BS3_SEL_GDT_LIMIT 0x3fd8 /**< The GDT limit. */ +/** @} */ + + +/** @def BS3_FAR + * For indicating far pointers in 16-bit code. + * Does nothing in 32-bit and 64-bit code. */ +/** @def BS3_NEAR + * For indicating near pointers in 16-bit code. + * Does nothing in 32-bit and 64-bit code. */ +/** @def BS3_FAR_CODE + * For indicating far 16-bit functions. + * Does nothing in 32-bit and 64-bit code. */ +/** @def BS3_NEAR_CODE + * For indicating near 16-bit functions. + * Does nothing in 32-bit and 64-bit code. */ +/** @def BS3_FAR_DATA + * For indicating far 16-bit external data, i.e. in a segment other than DATA16. + * Does nothing in 32-bit and 64-bit code. */ +#ifdef M_I86 +# define BS3_FAR __far +# define BS3_NEAR __near +# define BS3_FAR_CODE __far +# define BS3_NEAR_CODE __near +# define BS3_FAR_DATA __far +#else +# define BS3_FAR +# define BS3_NEAR +# define BS3_FAR_CODE +# define BS3_NEAR_CODE +# define BS3_FAR_DATA +#endif + +#if ARCH_BITS == 16 || defined(DOXYGEN_RUNNING) +/** @def BS3_FP_SEG + * Get the selector (segment) part of a far pointer. + * + * @returns selector. + * @param a_pv Far pointer. + */ +# define BS3_FP_SEG(a_pv) ((uint16_t)(__segment)(void BS3_FAR *)(a_pv)) +/** @def BS3_FP_OFF + * Get the segment offset part of a far pointer. + * + * For sake of convenience, this works like a uintptr_t cast in 32-bit and + * 64-bit code. + * + * @returns offset. + * @param a_pv Far pointer. + */ +# define BS3_FP_OFF(a_pv) ((uint16_t)(void __near *)(a_pv)) +/** @def BS3_FP_MAKE + * Create a far pointer. + * + * @returns Far pointer. + * @param a_uSeg The selector/segment. + * @param a_off The offset into the segment. + */ +# define BS3_FP_MAKE(a_uSeg, a_off) (((__segment)(a_uSeg)) :> ((void __near *)(a_off))) +#else +# define BS3_FP_OFF(a_pv) ((uintptr_t)(a_pv)) +#endif + +/** @def BS3_MAKE_PROT_R0PTR_FROM_FLAT + * Creates a protected mode pointer from a flat address. + * + * For sake of convenience, this macro also works in 32-bit and 64-bit mode, + * only there it doesn't return a far pointer but a flat point. + * + * @returns far void pointer if 16-bit code, near/flat void pointer in 32-bit + * and 64-bit. + * @param a_uFlat Flat address in the first 16MB. */ +#if ARCH_BITS == 16 +# define BS3_MAKE_PROT_R0PTR_FROM_FLAT(a_uFlat) \ + BS3_FP_MAKE(((uint16_t)(a_uFlat >> 16) << 3) + BS3_SEL_TILED, (uint16_t)(a_uFlat)) +#else +# define BS3_MAKE_PROT_R0PTR_FROM_FLAT(a_uFlat) ((void *)(uintptr_t)(a_uFlat)) +#endif + +/** @def BS3_MAKE_PROT_R0PTR_FROM_REAL + * Creates a protected mode pointer from a far real mode address. + * + * For sake of convenience, this macro also works in 32-bit and 64-bit mode, + * only there it doesn't return a far pointer but a flat point. + * + * @returns far void pointer if 16-bit code, near/flat void pointer in 32-bit + * and 64-bit. + * @param a_uSeg The selector/segment. + * @param a_off The offset into the segment. + */ +#if ARCH_BITS == 16 +# define BS3_MAKE_PROT_R0PTR_FROM_REAL(a_uSeg, a_off) BS3_MAKE_PROT_R0PTR_FROM_FLAT(((uint32_t)(a_uSeg) << 4) + (uint16_t)(a_off)) +#else +# define BS3_MAKE_PROT_R0PTR_FROM_REAL(a_uSeg, a_off) ( (void *)(uintptr_t)(((uint32_t)(a_uSeg) << 4) + (uint16_t)(a_off)) ) +#endif + + +/** @def BS3_CALL + * The calling convension used by BS3 functions. */ +#if ARCH_BITS != 64 +# define BS3_CALL __cdecl +#elif !defined(_MSC_VER) +# define BS3_CALL __attribute__((__ms_abi__)) +#else +# define BS3_CALL +#endif + +/** @def IN_BS3KIT + * Indicates that we're in the same link job as the BS3Kit code. */ +#ifdef DOXYGEN_RUNNING +# define IN_BS3KIT +#endif + +/** @def BS3_DECL + * Declares a BS3Kit function with default far/near. + * + * Until we outgrow BS3TEXT16, we use all near functions in 16-bit. + * + * @param a_Type The return type. */ +#if ARCH_BITS != 16 || !defined(BS3_USE_ALT_16BIT_TEXT_SEG) +# define BS3_DECL(a_Type) BS3_DECL_NEAR(a_Type) +#else +# define BS3_DECL(a_Type) BS3_DECL_FAR(a_Type) +#endif + +/** @def BS3_DECL_NEAR + * Declares a BS3Kit function, always near everywhere. + * + * Until we outgrow BS3TEXT16, we use all near functions in 16-bit. + * + * @param a_Type The return type. */ +#ifdef IN_BS3KIT +# define BS3_DECL_NEAR(a_Type) DECLEXPORT(a_Type) BS3_NEAR_CODE BS3_CALL +#else +# define BS3_DECL_NEAR(a_Type) DECLIMPORT(a_Type) BS3_NEAR_CODE BS3_CALL +#endif + +/** @def BS3_DECL_FAR + * Declares a BS3Kit function, far 16-bit, otherwise near. + * + * Until we outgrow BS3TEXT16, we use all near functions in 16-bit. + * + * @param a_Type The return type. */ +#ifdef IN_BS3KIT +# define BS3_DECL_FAR(a_Type) DECLEXPORT(a_Type) BS3_FAR_CODE BS3_CALL +#else +# define BS3_DECL_FAR(a_Type) DECLIMPORT(a_Type) BS3_FAR_CODE BS3_CALL +#endif + +/** @def BS3_DECL_CALLBACK + * Declares a BS3Kit callback function (typically static). + * + * @param a_Type The return type. */ +#ifdef IN_BS3KIT +# define BS3_DECL_CALLBACK(a_Type) a_Type BS3_FAR_CODE BS3_CALL +#else +# define BS3_DECL_CALLBACK(a_Type) a_Type BS3_FAR_CODE BS3_CALL +#endif + +/** @def BS3_DECL_NEAR_CALLBACK + * Declares a near BS3Kit callback function (typically static). + * + * 16-bit users must be in CGROUP16! + * + * @param a_Type The return type. */ +#ifdef IN_BS3KIT +# define BS3_DECL_NEAR_CALLBACK(a_Type) a_Type BS3_NEAR_CODE BS3_CALL +#else +# define BS3_DECL_NEAR_CALLBACK(a_Type) a_Type BS3_NEAR_CODE BS3_CALL +#endif + +/** + * Constructs a common name. + * + * Example: BS3_CMN_NM(Bs3Shutdown) + * + * @param a_Name The name of the function or global variable. + */ +#define BS3_CMN_NM(a_Name) RT_CONCAT3(a_Name,_c,ARCH_BITS) + +/** + * Constructs a common function name, far in 16-bit code. + * + * Example: BS3_CMN_FAR_NM(Bs3Shutdown) + * + * @param a_Name The name of the function. + */ +#if ARCH_BITS == 16 +# define BS3_CMN_FAR_NM(a_Name) RT_CONCAT(a_Name,_f16) +#else +# define BS3_CMN_FAR_NM(a_Name) RT_CONCAT3(a_Name,_c,ARCH_BITS) +#endif + +/** + * Constructs a common function name, far or near as defined by the source. + * + * Which to use in 16-bit mode is defined by BS3_USE_ALT_16BIT_TEXT_SEG. In + * 32-bit and 64-bit mode there are no far symbols, only near ones. + * + * Example: BS3_CMN_FN_NM(Bs3Shutdown) + * + * @param a_Name The name of the function. + */ +#if ARCH_BITS != 16 || !defined(BS3_USE_ALT_16BIT_TEXT_SEG) +# define BS3_CMN_FN_NM(a_Name) BS3_CMN_NM(a_Name) +#else +# define BS3_CMN_FN_NM(a_Name) BS3_CMN_FAR_NM(a_Name) +#endif + + +/** + * Constructs a data name. + * + * This glosses over the underscore prefix usage of our 16-bit, 32-bit and + * 64-bit compilers. + * + * Example: @code{.c} + * \#define Bs3Gdt BS3_DATA_NM(Bs3Gdt) + * extern X86DESC BS3_FAR_DATA Bs3Gdt + * @endcode + * + * @param a_Name The name of the global variable. + * @remarks Mainly used in bs3kit-mangling.h, internal headers and templates. + */ +//converter does this now//#if ARCH_BITS == 64 +//converter does this now//# define BS3_DATA_NM(a_Name) RT_CONCAT(_,a_Name) +//converter does this now//#else +# define BS3_DATA_NM(a_Name) a_Name +//converter does this now//#endif + +/** + * Template for creating a pointer union type. + * @param a_BaseName The base type name. + * @param a_Modifiers The type modifier. + */ +#define BS3_PTR_UNION_TEMPLATE(a_BaseName, a_Modifiers) \ + typedef union a_BaseName \ + { \ + /** Pointer into the void. */ \ + a_Modifiers void BS3_FAR *pv; \ + /** As a signed integer. */ \ + intptr_t i; \ + /** As an unsigned integer. */ \ + uintptr_t u; \ + /** Pointer to char value. */ \ + a_Modifiers char BS3_FAR *pch; \ + /** Pointer to char value. */ \ + a_Modifiers unsigned char BS3_FAR *puch; \ + /** Pointer to a int value. */ \ + a_Modifiers int BS3_FAR *pi; \ + /** Pointer to a unsigned int value. */ \ + a_Modifiers unsigned int BS3_FAR *pu; \ + /** Pointer to a long value. */ \ + a_Modifiers long BS3_FAR *pl; \ + /** Pointer to a long value. */ \ + a_Modifiers unsigned long BS3_FAR *pul; \ + /** Pointer to a memory size value. */ \ + a_Modifiers size_t BS3_FAR *pcb; \ + /** Pointer to a byte value. */ \ + a_Modifiers uint8_t BS3_FAR *pb; \ + /** Pointer to a 8-bit unsigned value. */ \ + a_Modifiers uint8_t BS3_FAR *pu8; \ + /** Pointer to a 16-bit unsigned value. */ \ + a_Modifiers uint16_t BS3_FAR *pu16; \ + /** Pointer to a 32-bit unsigned value. */ \ + a_Modifiers uint32_t BS3_FAR *pu32; \ + /** Pointer to a 64-bit unsigned value. */ \ + a_Modifiers uint64_t BS3_FAR *pu64; \ + /** Pointer to a UTF-16 character. */ \ + a_Modifiers RTUTF16 BS3_FAR *pwc; \ + /** Pointer to a UUID character. */ \ + a_Modifiers RTUUID BS3_FAR *pUuid; \ + } a_BaseName; \ + /** Pointer to a pointer union. */ \ + typedef a_BaseName *RT_CONCAT(P,a_BaseName) +BS3_PTR_UNION_TEMPLATE(BS3PTRUNION, RT_NOTHING); +BS3_PTR_UNION_TEMPLATE(BS3CPTRUNION, const); +BS3_PTR_UNION_TEMPLATE(BS3VPTRUNION, volatile); +BS3_PTR_UNION_TEMPLATE(BS3CVPTRUNION, const volatile); + +/** Generic far function type. */ +typedef BS3_DECL_FAR(void) FNBS3FAR(void); +/** Generic far function pointer type. */ +typedef FNBS3FAR *FPFNBS3FAR; + +/** Generic near function type. */ +typedef BS3_DECL_NEAR(void) FNBS3NEAR(void); +/** Generic near function pointer type. */ +typedef FNBS3NEAR *PFNBS3NEAR; + +/** Generic far 16:16 function pointer type for address conversion functions. */ +#if ARCH_BITS == 16 +typedef FPFNBS3FAR PFNBS3FARADDRCONV; +#else +typedef uint32_t PFNBS3FARADDRCONV; +#endif + +/** The system call vector. */ +#define BS3_TRAP_SYSCALL UINT8_C(0x20) + +/** @name System call numbers (ax). + * Paramenters are generally passed in registers specific to each system call, + * however cx:xSI is used for passing a pointer parameter. + * @{ */ +/** Print char (cl). */ +#define BS3_SYSCALL_PRINT_CHR UINT16_C(0x0001) +/** Print string (pointer in cx:xSI, length in dx). */ +#define BS3_SYSCALL_PRINT_STR UINT16_C(0x0002) +/** Switch to ring-0. */ +#define BS3_SYSCALL_TO_RING0 UINT16_C(0x0003) +/** Switch to ring-1. */ +#define BS3_SYSCALL_TO_RING1 UINT16_C(0x0004) +/** Switch to ring-2. */ +#define BS3_SYSCALL_TO_RING2 UINT16_C(0x0005) +/** Switch to ring-3. */ +#define BS3_SYSCALL_TO_RING3 UINT16_C(0x0006) +/** Restore context (pointer in cx:xSI, flags in dx). */ +#define BS3_SYSCALL_RESTORE_CTX UINT16_C(0x0007) +/** Set DRx register (value in ESI, register number in dl). */ +#define BS3_SYSCALL_SET_DRX UINT16_C(0x0008) +/** Get DRx register (register number in dl, value returned in ax:dx). */ +#define BS3_SYSCALL_GET_DRX UINT16_C(0x0009) +/** Set CRx register (value in ESI, register number in dl). */ +#define BS3_SYSCALL_SET_CRX UINT16_C(0x000a) +/** Get CRx register (register number in dl, value returned in ax:dx). */ +#define BS3_SYSCALL_GET_CRX UINT16_C(0x000b) +/** Set the task register (value in ESI). */ +#define BS3_SYSCALL_SET_TR UINT16_C(0x000c) +/** Get the task register (value returned in ax). */ +#define BS3_SYSCALL_GET_TR UINT16_C(0x000d) +/** Set the LDT register (value in ESI). */ +#define BS3_SYSCALL_SET_LDTR UINT16_C(0x000e) +/** Get the LDT register (value returned in ax). */ +#define BS3_SYSCALL_GET_LDTR UINT16_C(0x000f) +/** The last system call value. */ +#define BS3_SYSCALL_LAST BS3_SYSCALL_GET_LDTR +/** @} */ + + + +/** @defgroup grp_bs3kit_system System Structures + * @{ */ +/** The GDT, indexed by BS3_SEL_XXX shifted by 3. */ +extern X86DESC BS3_FAR_DATA Bs3Gdt[(BS3_SEL_GDT_LIMIT + 1) / 8]; + +extern X86DESC64 BS3_FAR_DATA Bs3Gdt_Ldt; /**< @see BS3_SEL_LDT */ +extern X86DESC BS3_FAR_DATA Bs3Gdte_Tss16; /**< @see BS3_SEL_TSS16 */ +extern X86DESC BS3_FAR_DATA Bs3Gdte_Tss16DoubleFault; /**< @see BS3_SEL_TSS16_DF */ +extern X86DESC BS3_FAR_DATA Bs3Gdte_Tss16Spare0; /**< @see BS3_SEL_TSS16_SPARE0 */ +extern X86DESC BS3_FAR_DATA Bs3Gdte_Tss16Spare1; /**< @see BS3_SEL_TSS16_SPARE1 */ +extern X86DESC BS3_FAR_DATA Bs3Gdte_Tss32; /**< @see BS3_SEL_TSS32 */ +extern X86DESC BS3_FAR_DATA Bs3Gdte_Tss32DoubleFault; /**< @see BS3_SEL_TSS32_DF */ +extern X86DESC BS3_FAR_DATA Bs3Gdte_Tss32Spare0; /**< @see BS3_SEL_TSS32_SPARE0 */ +extern X86DESC BS3_FAR_DATA Bs3Gdte_Tss32Spare1; /**< @see BS3_SEL_TSS32_SPARE1 */ +extern X86DESC BS3_FAR_DATA Bs3Gdte_Tss32IobpIntRedirBm; /**< @see BS3_SEL_TSS32_IOBP_IRB */ +extern X86DESC BS3_FAR_DATA Bs3Gdte_Tss32IntRedirBm; /**< @see BS3_SEL_TSS32_IRB */ +extern X86DESC BS3_FAR_DATA Bs3Gdte_Tss64; /**< @see BS3_SEL_TSS64 */ +extern X86DESC BS3_FAR_DATA Bs3Gdte_Tss64Spare0; /**< @see BS3_SEL_TSS64_SPARE0 */ +extern X86DESC BS3_FAR_DATA Bs3Gdte_Tss64Spare1; /**< @see BS3_SEL_TSS64_SPARE1 */ +extern X86DESC BS3_FAR_DATA Bs3Gdte_Tss64Iobp; /**< @see BS3_SEL_TSS64_IOBP */ +extern X86DESC BS3_FAR_DATA Bs3Gdte_RMTEXT16_CS; /**< @see BS3_SEL_RMTEXT16_CS */ +extern X86DESC BS3_FAR_DATA Bs3Gdte_X0TEXT16_CS; /**< @see BS3_SEL_X0TEXT16_CS */ +extern X86DESC BS3_FAR_DATA Bs3Gdte_X1TEXT16_CS; /**< @see BS3_SEL_X1TEXT16_CS */ +extern X86DESC BS3_FAR_DATA Bs3Gdte_R0_MMIO16; /**< @see BS3_SEL_VMMDEV_MMIO16 */ + +extern X86DESC BS3_FAR_DATA Bs3Gdte_R0_First; /**< @see BS3_SEL_R0_FIRST */ +extern X86DESC BS3_FAR_DATA Bs3Gdte_R0_CS16; /**< @see BS3_SEL_R0_CS16 */ +extern X86DESC BS3_FAR_DATA Bs3Gdte_R0_DS16; /**< @see BS3_SEL_R0_DS16 */ +extern X86DESC BS3_FAR_DATA Bs3Gdte_R0_SS16; /**< @see BS3_SEL_R0_SS16 */ +extern X86DESC BS3_FAR_DATA Bs3Gdte_R0_CS32; /**< @see BS3_SEL_R0_CS32 */ +extern X86DESC BS3_FAR_DATA Bs3Gdte_R0_DS32; /**< @see BS3_SEL_R0_DS32 */ +extern X86DESC BS3_FAR_DATA Bs3Gdte_R0_SS32; /**< @see BS3_SEL_R0_SS32 */ +extern X86DESC BS3_FAR_DATA Bs3Gdte_R0_CS64; /**< @see BS3_SEL_R0_CS64 */ +extern X86DESC BS3_FAR_DATA Bs3Gdte_R0_DS64; /**< @see BS3_SEL_R0_DS64 */ +extern X86DESC BS3_FAR_DATA Bs3Gdte_R0_CS16_EO; /**< @see BS3_SEL_R0_CS16_EO */ +extern X86DESC BS3_FAR_DATA Bs3Gdte_R0_CS16_CNF; /**< @see BS3_SEL_R0_CS16_CNF */ +extern X86DESC BS3_FAR_DATA Bs3Gdte_R0_CS16_CND_EO; /**< @see BS3_SEL_R0_CS16_CNF_EO */ +extern X86DESC BS3_FAR_DATA Bs3Gdte_R0_CS32_EO; /**< @see BS3_SEL_R0_CS32_EO */ +extern X86DESC BS3_FAR_DATA Bs3Gdte_R0_CS32_CNF; /**< @see BS3_SEL_R0_CS32_CNF */ +extern X86DESC BS3_FAR_DATA Bs3Gdte_R0_CS32_CNF_EO; /**< @see BS3_SEL_R0_CS32_CNF_EO */ +extern X86DESC BS3_FAR_DATA Bs3Gdte_R0_CS64_EO; /**< @see BS3_SEL_R0_CS64_EO */ +extern X86DESC BS3_FAR_DATA Bs3Gdte_R0_CS64_CNF; /**< @see BS3_SEL_R0_CS64_CNF */ +extern X86DESC BS3_FAR_DATA Bs3Gdte_R0_CS64_CNF_EO; /**< @see BS3_SEL_R0_CS64_CNF_EO */ + +extern X86DESC BS3_FAR_DATA Bs3Gdte_R1_First; /**< @see BS3_SEL_R1_FIRST */ +extern X86DESC BS3_FAR_DATA Bs3Gdte_R1_CS16; /**< @see BS3_SEL_R1_CS16 */ +extern X86DESC BS3_FAR_DATA Bs3Gdte_R1_DS16; /**< @see BS3_SEL_R1_DS16 */ +extern X86DESC BS3_FAR_DATA Bs3Gdte_R1_SS16; /**< @see BS3_SEL_R1_SS16 */ +extern X86DESC BS3_FAR_DATA Bs3Gdte_R1_CS32; /**< @see BS3_SEL_R1_CS32 */ +extern X86DESC BS3_FAR_DATA Bs3Gdte_R1_DS32; /**< @see BS3_SEL_R1_DS32 */ +extern X86DESC BS3_FAR_DATA Bs3Gdte_R1_SS32; /**< @see BS3_SEL_R1_SS32 */ +extern X86DESC BS3_FAR_DATA Bs3Gdte_R1_CS64; /**< @see BS3_SEL_R1_CS64 */ +extern X86DESC BS3_FAR_DATA Bs3Gdte_R1_DS64; /**< @see BS3_SEL_R1_DS64 */ +extern X86DESC BS3_FAR_DATA Bs3Gdte_R1_CS16_EO; /**< @see BS3_SEL_R1_CS16_EO */ +extern X86DESC BS3_FAR_DATA Bs3Gdte_R1_CS16_CNF; /**< @see BS3_SEL_R1_CS16_CNF */ +extern X86DESC BS3_FAR_DATA Bs3Gdte_R1_CS16_CND_EO; /**< @see BS3_SEL_R1_CS16_CNF_EO */ +extern X86DESC BS3_FAR_DATA Bs3Gdte_R1_CS32_EO; /**< @see BS3_SEL_R1_CS32_EO */ +extern X86DESC BS3_FAR_DATA Bs3Gdte_R1_CS32_CNF; /**< @see BS3_SEL_R1_CS32_CNF */ +extern X86DESC BS3_FAR_DATA Bs3Gdte_R1_CS32_CNF_EO; /**< @see BS3_SEL_R1_CS32_CNF_EO */ +extern X86DESC BS3_FAR_DATA Bs3Gdte_R1_CS64_EO; /**< @see BS3_SEL_R1_CS64_EO */ +extern X86DESC BS3_FAR_DATA Bs3Gdte_R1_CS64_CNF; /**< @see BS3_SEL_R1_CS64_CNF */ +extern X86DESC BS3_FAR_DATA Bs3Gdte_R1_CS64_CNF_EO; /**< @see BS3_SEL_R1_CS64_CNF_EO */ + +extern X86DESC BS3_FAR_DATA Bs3Gdte_R2_First; /**< @see BS3_SEL_R2_FIRST */ +extern X86DESC BS3_FAR_DATA Bs3Gdte_R2_CS16; /**< @see BS3_SEL_R2_CS16 */ +extern X86DESC BS3_FAR_DATA Bs3Gdte_R2_DS16; /**< @see BS3_SEL_R2_DS16 */ +extern X86DESC BS3_FAR_DATA Bs3Gdte_R2_SS16; /**< @see BS3_SEL_R2_SS16 */ +extern X86DESC BS3_FAR_DATA Bs3Gdte_R2_CS32; /**< @see BS3_SEL_R2_CS32 */ +extern X86DESC BS3_FAR_DATA Bs3Gdte_R2_DS32; /**< @see BS3_SEL_R2_DS32 */ +extern X86DESC BS3_FAR_DATA Bs3Gdte_R2_SS32; /**< @see BS3_SEL_R2_SS32 */ +extern X86DESC BS3_FAR_DATA Bs3Gdte_R2_CS64; /**< @see BS3_SEL_R2_CS64 */ +extern X86DESC BS3_FAR_DATA Bs3Gdte_R2_DS64; /**< @see BS3_SEL_R2_DS64 */ +extern X86DESC BS3_FAR_DATA Bs3Gdte_R2_CS16_EO; /**< @see BS3_SEL_R2_CS16_EO */ +extern X86DESC BS3_FAR_DATA Bs3Gdte_R2_CS16_CNF; /**< @see BS3_SEL_R2_CS16_CNF */ +extern X86DESC BS3_FAR_DATA Bs3Gdte_R2_CS16_CND_EO; /**< @see BS3_SEL_R2_CS16_CNF_EO */ +extern X86DESC BS3_FAR_DATA Bs3Gdte_R2_CS32_EO; /**< @see BS3_SEL_R2_CS32_EO */ +extern X86DESC BS3_FAR_DATA Bs3Gdte_R2_CS32_CNF; /**< @see BS3_SEL_R2_CS32_CNF */ +extern X86DESC BS3_FAR_DATA Bs3Gdte_R2_CS32_CNF_EO; /**< @see BS3_SEL_R2_CS32_CNF_EO */ +extern X86DESC BS3_FAR_DATA Bs3Gdte_R2_CS64_EO; /**< @see BS3_SEL_R2_CS64_EO */ +extern X86DESC BS3_FAR_DATA Bs3Gdte_R2_CS64_CNF; /**< @see BS3_SEL_R2_CS64_CNF */ +extern X86DESC BS3_FAR_DATA Bs3Gdte_R2_CS64_CNF_EO; /**< @see BS3_SEL_R2_CS64_CNF_EO */ + +extern X86DESC BS3_FAR_DATA Bs3Gdte_R3_First; /**< @see BS3_SEL_R3_FIRST */ +extern X86DESC BS3_FAR_DATA Bs3Gdte_R3_CS16; /**< @see BS3_SEL_R3_CS16 */ +extern X86DESC BS3_FAR_DATA Bs3Gdte_R3_DS16; /**< @see BS3_SEL_R3_DS16 */ +extern X86DESC BS3_FAR_DATA Bs3Gdte_R3_SS16; /**< @see BS3_SEL_R3_SS16 */ +extern X86DESC BS3_FAR_DATA Bs3Gdte_R3_CS32; /**< @see BS3_SEL_R3_CS32 */ +extern X86DESC BS3_FAR_DATA Bs3Gdte_R3_DS32; /**< @see BS3_SEL_R3_DS32 */ +extern X86DESC BS3_FAR_DATA Bs3Gdte_R3_SS32; /**< @see BS3_SEL_R3_SS32 */ +extern X86DESC BS3_FAR_DATA Bs3Gdte_R3_CS64; /**< @see BS3_SEL_R3_CS64 */ +extern X86DESC BS3_FAR_DATA Bs3Gdte_R3_DS64; /**< @see BS3_SEL_R3_DS64 */ +extern X86DESC BS3_FAR_DATA Bs3Gdte_R3_CS16_EO; /**< @see BS3_SEL_R3_CS16_EO */ +extern X86DESC BS3_FAR_DATA Bs3Gdte_R3_CS16_CNF; /**< @see BS3_SEL_R3_CS16_CNF */ +extern X86DESC BS3_FAR_DATA Bs3Gdte_R3_CS16_CND_EO; /**< @see BS3_SEL_R3_CS16_CNF_EO */ +extern X86DESC BS3_FAR_DATA Bs3Gdte_R3_CS32_EO; /**< @see BS3_SEL_R3_CS32_EO */ +extern X86DESC BS3_FAR_DATA Bs3Gdte_R3_CS32_CNF; /**< @see BS3_SEL_R3_CS32_CNF */ +extern X86DESC BS3_FAR_DATA Bs3Gdte_R3_CS32_CNF_EO; /**< @see BS3_SEL_R3_CS32_CNF_EO */ +extern X86DESC BS3_FAR_DATA Bs3Gdte_R3_CS64_EO; /**< @see BS3_SEL_R3_CS64_EO */ +extern X86DESC BS3_FAR_DATA Bs3Gdte_R3_CS64_CNF; /**< @see BS3_SEL_R3_CS64_CNF */ +extern X86DESC BS3_FAR_DATA Bs3Gdte_R3_CS64_CNF_EO; /**< @see BS3_SEL_R3_CS64_CNF_EO */ + +extern X86DESC BS3_FAR_DATA Bs3GdteSpare00; /**< GDT entry for playing with in testcases. @see BS3_SEL_SPARE_00 */ +extern X86DESC BS3_FAR_DATA Bs3GdteSpare01; /**< GDT entry for playing with in testcases. @see BS3_SEL_SPARE_01 */ +extern X86DESC BS3_FAR_DATA Bs3GdteSpare02; /**< GDT entry for playing with in testcases. @see BS3_SEL_SPARE_02 */ +extern X86DESC BS3_FAR_DATA Bs3GdteSpare03; /**< GDT entry for playing with in testcases. @see BS3_SEL_SPARE_03 */ +extern X86DESC BS3_FAR_DATA Bs3GdteSpare04; /**< GDT entry for playing with in testcases. @see BS3_SEL_SPARE_04 */ +extern X86DESC BS3_FAR_DATA Bs3GdteSpare05; /**< GDT entry for playing with in testcases. @see BS3_SEL_SPARE_05 */ +extern X86DESC BS3_FAR_DATA Bs3GdteSpare06; /**< GDT entry for playing with in testcases. @see BS3_SEL_SPARE_06 */ +extern X86DESC BS3_FAR_DATA Bs3GdteSpare07; /**< GDT entry for playing with in testcases. @see BS3_SEL_SPARE_07 */ +extern X86DESC BS3_FAR_DATA Bs3GdteSpare08; /**< GDT entry for playing with in testcases. @see BS3_SEL_SPARE_08 */ +extern X86DESC BS3_FAR_DATA Bs3GdteSpare09; /**< GDT entry for playing with in testcases. @see BS3_SEL_SPARE_09 */ +extern X86DESC BS3_FAR_DATA Bs3GdteSpare0a; /**< GDT entry for playing with in testcases. @see BS3_SEL_SPARE_0a */ +extern X86DESC BS3_FAR_DATA Bs3GdteSpare0b; /**< GDT entry for playing with in testcases. @see BS3_SEL_SPARE_0b */ +extern X86DESC BS3_FAR_DATA Bs3GdteSpare0c; /**< GDT entry for playing with in testcases. @see BS3_SEL_SPARE_0c */ +extern X86DESC BS3_FAR_DATA Bs3GdteSpare0d; /**< GDT entry for playing with in testcases. @see BS3_SEL_SPARE_0d */ +extern X86DESC BS3_FAR_DATA Bs3GdteSpare0e; /**< GDT entry for playing with in testcases. @see BS3_SEL_SPARE_0e */ +extern X86DESC BS3_FAR_DATA Bs3GdteSpare0f; /**< GDT entry for playing with in testcases. @see BS3_SEL_SPARE_0f */ +extern X86DESC BS3_FAR_DATA Bs3GdteSpare10; /**< GDT entry for playing with in testcases. @see BS3_SEL_SPARE_10 */ +extern X86DESC BS3_FAR_DATA Bs3GdteSpare11; /**< GDT entry for playing with in testcases. @see BS3_SEL_SPARE_11 */ +extern X86DESC BS3_FAR_DATA Bs3GdteSpare12; /**< GDT entry for playing with in testcases. @see BS3_SEL_SPARE_12 */ +extern X86DESC BS3_FAR_DATA Bs3GdteSpare13; /**< GDT entry for playing with in testcases. @see BS3_SEL_SPARE_13 */ +extern X86DESC BS3_FAR_DATA Bs3GdteSpare14; /**< GDT entry for playing with in testcases. @see BS3_SEL_SPARE_14 */ +extern X86DESC BS3_FAR_DATA Bs3GdteSpare15; /**< GDT entry for playing with in testcases. @see BS3_SEL_SPARE_15 */ +extern X86DESC BS3_FAR_DATA Bs3GdteSpare16; /**< GDT entry for playing with in testcases. @see BS3_SEL_SPARE_16 */ +extern X86DESC BS3_FAR_DATA Bs3GdteSpare17; /**< GDT entry for playing with in testcases. @see BS3_SEL_SPARE_17 */ +extern X86DESC BS3_FAR_DATA Bs3GdteSpare18; /**< GDT entry for playing with in testcases. @see BS3_SEL_SPARE_18 */ +extern X86DESC BS3_FAR_DATA Bs3GdteSpare19; /**< GDT entry for playing with in testcases. @see BS3_SEL_SPARE_19 */ +extern X86DESC BS3_FAR_DATA Bs3GdteSpare1a; /**< GDT entry for playing with in testcases. @see BS3_SEL_SPARE_1a */ +extern X86DESC BS3_FAR_DATA Bs3GdteSpare1b; /**< GDT entry for playing with in testcases. @see BS3_SEL_SPARE_1b */ +extern X86DESC BS3_FAR_DATA Bs3GdteSpare1c; /**< GDT entry for playing with in testcases. @see BS3_SEL_SPARE_1c */ +extern X86DESC BS3_FAR_DATA Bs3GdteSpare1d; /**< GDT entry for playing with in testcases. @see BS3_SEL_SPARE_1d */ +extern X86DESC BS3_FAR_DATA Bs3GdteSpare1e; /**< GDT entry for playing with in testcases. @see BS3_SEL_SPARE_1e */ +extern X86DESC BS3_FAR_DATA Bs3GdteSpare1f; /**< GDT entry for playing with in testcases. @see BS3_SEL_SPARE_1f */ + +/** GDTs setting up the tiled 16-bit access to the first 16 MBs of memory. + * @see BS3_SEL_TILED, BS3_SEL_TILED_LAST, BS3_SEL_TILED_AREA_SIZE */ +extern X86DESC BS3_FAR_DATA Bs3GdteTiled[256]; +/** Free GDTes, part \#1. */ +extern X86DESC BS3_FAR_DATA Bs3GdteFreePart1[64]; +/** The BS3TEXT16/BS3CLASS16CODE GDT entry. @see BS3_SEL_TEXT16 */ +extern X86DESC BS3_FAR_DATA Bs3Gdte_CODE16; +/** Free GDTes, part \#2. */ +extern X86DESC BS3_FAR_DATA Bs3GdteFreePart2[511]; +/** The BS3SYSTEM16 GDT entry. */ +extern X86DESC BS3_FAR_DATA Bs3Gdte_SYSTEM16; +/** Free GDTes, part \#3. */ +extern X86DESC BS3_FAR_DATA Bs3GdteFreePart3[223]; +/** The BS3DATA16/BS3KIT_GRPNM_DATA16 GDT entry. */ +extern X86DESC BS3_FAR_DATA Bs3Gdte_DATA16; + +/** Free GDTes, part \#4. */ +extern X86DESC BS3_FAR_DATA Bs3GdteFreePart4[211]; + +extern X86DESC BS3_FAR_DATA Bs3GdtePreTestPage08; /**< GDT entry 8 selectors prior to the test page, testcase resource. @see BS3_SEL_PRE_TEST_PAGE_08 */ +extern X86DESC BS3_FAR_DATA Bs3GdtePreTestPage07; /**< GDT entry 7 selectors prior to the test page, testcase resource. @see BS3_SEL_PRE_TEST_PAGE_07 */ +extern X86DESC BS3_FAR_DATA Bs3GdtePreTestPage06; /**< GDT entry 6 selectors prior to the test page, testcase resource. @see BS3_SEL_PRE_TEST_PAGE_06 */ +extern X86DESC BS3_FAR_DATA Bs3GdtePreTestPage05; /**< GDT entry 5 selectors prior to the test page, testcase resource. @see BS3_SEL_PRE_TEST_PAGE_05 */ +extern X86DESC BS3_FAR_DATA Bs3GdtePreTestPage04; /**< GDT entry 4 selectors prior to the test page, testcase resource. @see BS3_SEL_PRE_TEST_PAGE_04 */ +extern X86DESC BS3_FAR_DATA Bs3GdtePreTestPage03; /**< GDT entry 3 selectors prior to the test page, testcase resource. @see BS3_SEL_PRE_TEST_PAGE_03 */ +extern X86DESC BS3_FAR_DATA Bs3GdtePreTestPage02; /**< GDT entry 2 selectors prior to the test page, testcase resource. @see BS3_SEL_PRE_TEST_PAGE_02 */ +extern X86DESC BS3_FAR_DATA Bs3GdtePreTestPage01; /**< GDT entry 1 selectors prior to the test page, testcase resource. @see BS3_SEL_PRE_TEST_PAGE_01 */ +/** Array of GDT entries starting on a page boundrary and filling (almost) the + * whole page. This is for playing with paging and GDT usage. + * @see BS3_SEL_TEST_PAGE */ +extern X86DESC BS3_FAR_DATA Bs3GdteTestPage[2043]; +extern X86DESC BS3_FAR_DATA Bs3GdteTestPage00; /**< GDT entry 0 on the test page (convenience). @see BS3_SEL_TEST_PAGE_00 */ +extern X86DESC BS3_FAR_DATA Bs3GdteTestPage01; /**< GDT entry 1 on the test page (convenience). @see BS3_SEL_TEST_PAGE_01 */ +extern X86DESC BS3_FAR_DATA Bs3GdteTestPage02; /**< GDT entry 2 on the test page (convenience). @see BS3_SEL_TEST_PAGE_02 */ +extern X86DESC BS3_FAR_DATA Bs3GdteTestPage03; /**< GDT entry 3 on the test page (convenience). @see BS3_SEL_TEST_PAGE_03 */ +extern X86DESC BS3_FAR_DATA Bs3GdteTestPage04; /**< GDT entry 4 on the test page (convenience). @see BS3_SEL_TEST_PAGE_04 */ +extern X86DESC BS3_FAR_DATA Bs3GdteTestPage05; /**< GDT entry 5 on the test page (convenience). @see BS3_SEL_TEST_PAGE_05 */ +extern X86DESC BS3_FAR_DATA Bs3GdteTestPage06; /**< GDT entry 6 on the test page (convenience). @see BS3_SEL_TEST_PAGE_06 */ +extern X86DESC BS3_FAR_DATA Bs3GdteTestPage07; /**< GDT entry 7 on the test page (convenience). @see BS3_SEL_TEST_PAGE_07 */ + +/** The end of the GDT (exclusive - contains eye-catcher string). */ +extern X86DESC BS3_FAR_DATA Bs3GdtEnd; + +/** The default 16-bit TSS. */ +extern X86TSS16 BS3_FAR_DATA Bs3Tss16; +extern X86TSS16 BS3_FAR_DATA Bs3Tss16DoubleFault; +extern X86TSS16 BS3_FAR_DATA Bs3Tss16Spare0; +extern X86TSS16 BS3_FAR_DATA Bs3Tss16Spare1; +/** The default 32-bit TSS. */ +extern X86TSS32 BS3_FAR_DATA Bs3Tss32; +extern X86TSS32 BS3_FAR_DATA Bs3Tss32DoubleFault; +extern X86TSS32 BS3_FAR_DATA Bs3Tss32Spare0; +extern X86TSS32 BS3_FAR_DATA Bs3Tss32Spare1; +/** The default 64-bit TSS. */ +extern X86TSS64 BS3_FAR_DATA Bs3Tss64; +extern X86TSS64 BS3_FAR_DATA Bs3Tss64Spare0; +extern X86TSS64 BS3_FAR_DATA Bs3Tss64Spare1; +extern X86TSS64 BS3_FAR_DATA Bs3Tss64WithIopb; +extern X86TSS32 BS3_FAR_DATA Bs3Tss32WithIopb; +/** Interrupt redirection bitmap used by Bs3Tss32WithIopb. */ +extern uint8_t BS3_FAR_DATA Bs3SharedIntRedirBm[32]; +/** I/O permission bitmap used by Bs3Tss32WithIopb and Bs3Tss64WithIopb. */ +extern uint8_t BS3_FAR_DATA Bs3SharedIobp[8192+2]; +/** End of the I/O permission bitmap (exclusive). */ +extern uint8_t BS3_FAR_DATA Bs3SharedIobpEnd; +/** 16-bit IDT. */ +extern X86DESC BS3_FAR_DATA Bs3Idt16[256]; +/** 32-bit IDT. */ +extern X86DESC BS3_FAR_DATA Bs3Idt32[256]; +/** 64-bit IDT. */ +extern X86DESC64 BS3_FAR_DATA Bs3Idt64[256]; +/** Structure for the LIDT instruction for loading the 16-bit IDT. */ +extern X86XDTR64 BS3_FAR_DATA Bs3Lidt_Idt16; +/** Structure for the LIDT instruction for loading the 32-bit IDT. */ +extern X86XDTR64 BS3_FAR_DATA Bs3Lidt_Idt32; +/** Structure for the LIDT instruction for loading the 64-bit IDT. */ +extern X86XDTR64 BS3_FAR_DATA Bs3Lidt_Idt64; +/** Structure for the LIDT instruction for loading the real mode interrupt + * vector table. */ +extern X86XDTR64 BS3_FAR_DATA Bs3Lidt_Ivt; +/** Structure for the LGDT instruction for loading the current GDT. */ +extern X86XDTR64 BS3_FAR_DATA Bs3Lgdt_Gdt; +/** Structure for the LGDT instruction for loading the default GDT. */ +extern X86XDTR64 BS3_FAR_DATA Bs3LgdtDef_Gdt; +/** The LDT (all entries are empty, fill in for testing). */ +extern X86DESC BS3_FAR_DATA Bs3Ldt[116]; +/** The end of the LDT (exclusive). */ +extern X86DESC BS3_FAR_DATA Bs3LdtEnd; + +/** @} */ + + +/** @name Segment start and end markers, sizes. + * @{ */ +/** Start of the BS3TEXT16 segment. */ +extern uint8_t BS3_FAR_DATA Bs3Text16_StartOfSegment; +/** End of the BS3TEXT16 segment. */ +extern uint8_t BS3_FAR_DATA Bs3Text16_EndOfSegment; +/** The size of the BS3TEXT16 segment. */ +extern uint16_t BS3_FAR_DATA Bs3Text16_Size; + +/** Start of the BS3SYSTEM16 segment. */ +extern uint8_t BS3_FAR_DATA Bs3System16_StartOfSegment; +/** End of the BS3SYSTEM16 segment. */ +extern uint8_t BS3_FAR_DATA Bs3System16_EndOfSegment; + +/** Start of the BS3DATA16/BS3KIT_GRPNM_DATA16 segment. */ +extern uint8_t BS3_FAR_DATA Bs3Data16_StartOfSegment; +/** End of the BS3DATA16/BS3KIT_GRPNM_DATA16 segment. */ +extern uint8_t BS3_FAR_DATA Bs3Data16_EndOfSegment; + +/** Start of the BS3RMTEXT16 segment. */ +extern uint8_t BS3_FAR_DATA Bs3RmText16_StartOfSegment; +/** End of the BS3RMTEXT16 segment. */ +extern uint8_t BS3_FAR_DATA Bs3RmText16_EndOfSegment; +/** The size of the BS3RMTEXT16 segment. */ +extern uint16_t BS3_FAR_DATA Bs3RmText16_Size; +/** The flat start address of the BS3X0TEXT16 segment. */ +extern uint32_t BS3_FAR_DATA Bs3RmText16_FlatAddr; + +/** Start of the BS3X0TEXT16 segment. */ +extern uint8_t BS3_FAR_DATA Bs3X0Text16_StartOfSegment; +/** End of the BS3X0TEXT16 segment. */ +extern uint8_t BS3_FAR_DATA Bs3X0Text16_EndOfSegment; +/** The size of the BS3X0TEXT16 segment. */ +extern uint16_t BS3_FAR_DATA Bs3X0Text16_Size; +/** The flat start address of the BS3X0TEXT16 segment. */ +extern uint32_t BS3_FAR_DATA Bs3X0Text16_FlatAddr; + +/** Start of the BS3X1TEXT16 segment. */ +extern uint8_t BS3_FAR_DATA Bs3X1Text16_StartOfSegment; +/** End of the BS3X1TEXT16 segment. */ +extern uint8_t BS3_FAR_DATA Bs3X1Text16_EndOfSegment; +/** The size of the BS3X1TEXT16 segment. */ +extern uint16_t BS3_FAR_DATA Bs3X1Text16_Size; +/** The flat start address of the BS3X1TEXT16 segment. */ +extern uint32_t BS3_FAR_DATA Bs3X1Text16_FlatAddr; + +/** Start of the BS3TEXT32 segment. */ +extern uint8_t BS3_FAR_DATA Bs3Text32_StartOfSegment; +/** Start of the BS3TEXT32 segment. */ +extern uint8_t BS3_FAR_DATA Bs3Text32_EndOfSegment; + +/** Start of the BS3DATA32 segment. */ +extern uint8_t BS3_FAR_DATA Bs3Data32_StartOfSegment; +/** Start of the BS3DATA32 segment. */ +extern uint8_t BS3_FAR_DATA Bs3Data32_EndOfSegment; + +/** Start of the BS3TEXT64 segment. */ +extern uint8_t BS3_FAR_DATA Bs3Text64_StartOfSegment; +/** Start of the BS3TEXT64 segment. */ +extern uint8_t BS3_FAR_DATA Bs3Text64_EndOfSegment; + +/** Start of the BS3DATA64 segment. */ +extern uint8_t BS3_FAR_DATA Bs3Data64_StartOfSegment; +/** Start of the BS3DATA64 segment. */ +extern uint8_t BS3_FAR_DATA Bs3Data64_EndOfSegment; + +/** The size of the Data16, Text32, Text64, Data32 and Data64 blob. */ +extern uint32_t BS3_FAR_DATA Bs3Data16Thru64Text32And64_TotalSize; +/** The total image size (from Text16 thu Data64). */ +extern uint32_t BS3_FAR_DATA Bs3TotalImageSize; +/** @} */ + + +/** Lower case hex digits. */ +extern char const g_achBs3HexDigits[16+1]; +/** Upper case hex digits. */ +extern char const g_achBs3HexDigitsUpper[16+1]; + + +/** The current mode (BS3_MODE_XXX) of CPU \#0. */ +extern uint8_t g_bBs3CurrentMode; + +/** Hint for 16-bit trap handlers regarding the high word of EIP. */ +extern uint32_t g_uBs3TrapEipHint; + +/** Set to disable special V8086 \#GP and \#UD handling in Bs3TrapDefaultHandler. + * This is useful for getting */ +extern bool volatile g_fBs3TrapNoV86Assist; + +/** Copy of the original real-mode interrupt vector table. */ +extern RTFAR16 g_aBs3RmIvtOriginal[256]; + + +#ifdef __WATCOMC__ +/** + * Executes the SMSW instruction and returns the value. + * + * @returns Machine status word. + */ +uint16_t Bs3AsmSmsw(void); +# pragma aux Bs3AsmSmsw = \ + ".286" \ + "smsw ax" \ + value [ax] modify exact [ax] nomemory; +#endif + + +/** @defgroup bs3kit_cross_ptr Cross Context Pointer Type + * + * The cross context pointer type is + * + * @{ */ + +/** + * Cross context pointer base type. + */ +typedef union BS3XPTR +{ + /** The flat pointer. */ + uint32_t uFlat; + /** 16-bit view. */ + struct + { + uint16_t uLow; + uint16_t uHigh; + } u; +#if ARCH_BITS == 16 + /** 16-bit near pointer. */ + void __near *pvNear; +#elif ARCH_BITS == 32 + /** 32-bit pointer. */ + void *pvRaw; +#endif +} BS3XPTR; +AssertCompileSize(BS3XPTR, 4); + + +/** @def BS3_XPTR_DEF_INTERNAL + * Internal worker. + * + * @param a_Scope RT_NOTHING if structure or global, static or extern + * otherwise. + * @param a_Type The type we're pointing to. + * @param a_Name The member or variable name. + * @internal + */ +#if ARCH_BITS == 16 +# define BS3_XPTR_DEF_INTERNAL(a_Scope, a_Type, a_Name) \ + a_Scope union \ + { \ + BS3XPTR XPtr; \ + a_Type __near *pNearTyped; \ + } a_Name +#elif ARCH_BITS == 32 +# define BS3_XPTR_DEF_INTERNAL(a_Scope, a_Type, a_Name) \ + a_Scope union \ + { \ + BS3XPTR XPtr; \ + a_Type *pTyped; \ + } a_Name +#elif ARCH_BITS == 64 +# define BS3_XPTR_DEF_INTERNAL(a_Scope, a_Type, a_Name) \ + a_Scope union \ + { \ + BS3XPTR XPtr; \ + } a_Name +#else +# error "ARCH_BITS" +#endif + +/** @def BS3_XPTR_MEMBER + * Defines a pointer member that can be shared by all CPU modes. + * + * @param a_Type The type we're pointing to. + * @param a_Name The member or variable name. + */ +#define BS3_XPTR_MEMBER(a_Type, a_Name) BS3_XPTR_DEF_INTERNAL(RT_NOTHING, a_Type, a_Name) + +/** @def BS3_XPTR_AUTO + * Defines a pointer static variable for working with an XPTR. + * + * This is typically used to convert flat pointers into context specific + * pointers. + * + * @param a_Type The type we're pointing to. + * @param a_Name The member or variable name. + */ +#define BS3_XPTR_AUTO(a_Type, a_Name) BS3_XPTR_DEF_INTERNAL(RT_NOTHING, a_Type, a_Name) + +/** @def BS3_XPTR_SET_FLAT + * Sets a cross context pointer. + * + * @param a_Type The type we're pointing to. + * @param a_Name The member or variable name. + * @param a_uFlatPtr The flat pointer value to assign. If the x-pointer is + * used in real mode, this must be less than 1MB. + * Otherwise the limit is 16MB (due to selector tiling). + */ +#define BS3_XPTR_SET_FLAT(a_Type, a_Name, a_uFlatPtr) \ + do { a_Name.XPtr.uFlat = (a_uFlatPtr); } while (0) + +/** @def BS3_XPTR_GET_FLAT + * Gets the flat address of a cross context pointer. + * + * @returns 32-bit flat pointer. + * @param a_Type The type we're pointing to. + * @param a_Name The member or variable name. + */ +#define BS3_XPTR_GET_FLAT(a_Type, a_Name) (a_Name.XPtr.uFlat) + +/** @def BS3_XPTR_GET_FLAT_LOW + * Gets the low 16 bits of the flat address. + * + * @returns Low 16 bits of the flat pointer. + * @param a_Type The type we're pointing to. + * @param a_Name The member or variable name. + */ +#define BS3_XPTR_GET_FLAT_LOW(a_Type, a_Name) (a_Name.XPtr.u.uLow) + + +#if ARCH_BITS == 16 + +/** + * Gets the current ring number. + * @returns Ring number. + */ +DECLINLINE(uint16_t) Bs3Sel16GetCurRing(void); +# pragma aux Bs3Sel16GetCurRing = \ + "mov ax, ss" \ + "and ax, 3" \ + value [ax] modify exact [ax] nomemory; + +/** + * Converts the high word of a flat pointer into a 16-bit selector. + * + * This makes use of the tiled area. It also handles real mode. + * + * @returns Segment selector value. + * @param uHigh The high part of flat pointer. + * @sa BS3_XPTR_GET, BS3_XPTR_SET + */ +DECLINLINE(__segment) Bs3Sel16HighFlatPtrToSelector(uint16_t uHigh) +{ + if (!BS3_MODE_IS_RM_OR_V86(g_bBs3CurrentMode)) + return (__segment)(((uHigh << 3) + BS3_SEL_TILED) | Bs3Sel16GetCurRing()); + return (__segment)(uHigh << 12); +} + +#endif /* ARCH_BITS == 16 */ + +/** @def BS3_XPTR_GET + * Gets the current context pointer value. + * + * @returns Usable pointer. + * @param a_Type The type we're pointing to. + * @param a_Name The member or variable name. + */ +#if ARCH_BITS == 16 +# define BS3_XPTR_GET(a_Type, a_Name) \ + ((a_Type BS3_FAR *)BS3_FP_MAKE(Bs3Sel16HighFlatPtrToSelector((a_Name).XPtr.u.uHigh), (a_Name).pNearTyped)) +#elif ARCH_BITS == 32 +# define BS3_XPTR_GET(a_Type, a_Name) ((a_Name).pTyped) +#elif ARCH_BITS == 64 +# define BS3_XPTR_GET(a_Type, a_Name) ((a_Type *)(uintptr_t)(a_Name).XPtr.uFlat) +#else +# error "ARCH_BITS" +#endif + +/** @def BS3_XPTR_SET + * Gets the current context pointer value. + * + * @returns Usable pointer. + * @param a_Type The type we're pointing to. + * @param a_Name The member or variable name. + * @param a_pValue The new pointer value, current context pointer. + */ +#if ARCH_BITS == 16 +# define BS3_XPTR_SET(a_Type, a_Name, a_pValue) \ + do { \ + a_Type BS3_FAR *pTypeCheck = (a_pValue); \ + if (BS3_MODE_IS_RM_OR_V86(g_bBs3CurrentMode)) \ + (a_Name).XPtr.uFlat = BS3_FP_OFF(pTypeCheck) + ((uint32_t)BS3_FP_SEG(pTypeCheck) << 4); \ + else \ + { \ + (a_Name).XPtr.u.uLow = BS3_FP_OFF(pTypeCheck); \ + (a_Name).XPtr.u.uHigh = ((BS3_FP_SEG(pTypeCheck) & UINT16_C(0xfff8)) - BS3_SEL_TILED) >> 3; \ + } \ + } while (0) +#elif ARCH_BITS == 32 +# define BS3_XPTR_SET(a_Type, a_Name, a_pValue) \ + do { (a_Name).pTyped = (a_pValue); } while (0) +#elif ARCH_BITS == 64 +# define BS3_XPTR_SET(a_Type, a_Name, a_pValue) \ + do { \ + a_Type *pTypeCheck = (a_pValue); \ + (a_Name).XPtr.uFlat = (uint32_t)(uintptr_t)pTypeCheck; \ + } while (0) +#else +# error "ARCH_BITS" +#endif + + +/** @def BS3_XPTR_IS_NULL + * Checks if the cross context pointer is NULL. + * + * @returns true if NULL, false if not. + * @param a_Type The type we're pointing to. + * @param a_Name The member or variable name. + */ +#define BS3_XPTR_IS_NULL(a_Type, a_Name) ((a_Name).XPtr.uFlat == 0) + +/** + * Gets a working pointer from a flat address. + * + * @returns Current context pointer. + * @param uFlatPtr The flat address to convert (32-bit or 64-bit). + */ +DECLINLINE(void BS3_FAR *) Bs3XptrFlatToCurrent(RTCCUINTXREG uFlatPtr) +{ + BS3_XPTR_AUTO(void, pTmp); + BS3_XPTR_SET_FLAT(void, pTmp, uFlatPtr); + return BS3_XPTR_GET(void, pTmp); +} + +/** @} */ + + + +/** @defgroup grp_bs3kit_cmn Common Functions and Data + * + * The common functions comes in three variations: 16-bit, 32-bit and 64-bit. + * Templated code uses the #BS3_CMN_NM macro to mangle the name according to the + * desired + * + * @{ + */ + +/** @def BS3_CMN_PROTO_INT + * Internal macro for prototyping all the variations of a common function. + * @param a_RetType The return type. + * @param a_Name The function basename. + * @param a_Params The parameter list (in parentheses). + * @sa BS3_CMN_PROTO_STUB, BS3_CMN_PROTO_NOSB + */ +#if ARCH_BITS == 16 +# ifndef BS3_USE_ALT_16BIT_TEXT_SEG +# define BS3_CMN_PROTO_INT(a_RetType, a_Name, a_Params) \ + BS3_DECL_NEAR(a_RetType) BS3_CMN_NM(a_Name) a_Params; \ + BS3_DECL_FAR(a_RetType) BS3_CMN_FAR_NM(a_Name) a_Params +# else +# define BS3_CMN_PROTO_INT(a_RetType, a_Name, a_Params) \ + BS3_DECL_FAR(a_RetType) BS3_CMN_FAR_NM(a_Name) a_Params +# endif +#else +# define BS3_CMN_PROTO_INT(a_RetType, a_Name, a_Params) \ + BS3_DECL_NEAR(a_RetType) BS3_CMN_NM(a_Name) a_Params +#endif + +/** @def BS3_CMN_PROTO_STUB + * Macro for prototyping all the variations of a common function with automatic + * near -> far stub. + * + * @param a_RetType The return type. + * @param a_Name The function basename. + * @param a_Params The parameter list (in parentheses). + * @sa BS3_CMN_PROTO_NOSB + */ +#define BS3_CMN_PROTO_STUB(a_RetType, a_Name, a_Params) BS3_CMN_PROTO_INT(a_RetType, a_Name, a_Params) + +/** @def BS3_CMN_PROTO_NOSB + * Macro for prototyping all the variations of a common function without any + * near > far stub. + * + * @param a_RetType The return type. + * @param a_Name The function basename. + * @param a_Params The parameter list (in parentheses). + * @sa BS3_CMN_PROTO_STUB + */ +#define BS3_CMN_PROTO_NOSB(a_RetType, a_Name, a_Params) BS3_CMN_PROTO_INT(a_RetType, a_Name, a_Params) + +/** @def BS3_CMN_PROTO_FARSTUB + * Macro for prototyping all the variations of a common function with automatic + * far -> near stub. + * + * @param a_cbParam16 The size of the 16-bit parameter list in bytes. + * @param a_RetType The return type. + * @param a_Name The function basename. + * @param a_Params The parameter list (in parentheses). + * @sa BS3_CMN_PROTO_STUB + */ +#define BS3_CMN_PROTO_FARSTUB(a_cbParam16, a_RetType, a_Name, a_Params) BS3_CMN_PROTO_INT(a_RetType, a_Name, a_Params) + + +/** @def BS3_CMN_DEF + * Macro for defining a common function. + * + * This makes 16-bit common function far, while 32-bit and 64-bit are near. + * + * @param a_RetType The return type. + * @param a_Name The function basename. + * @param a_Params The parameter list (in parentheses). + */ +#if ARCH_BITS == 16 +# define BS3_CMN_DEF(a_RetType, a_Name, a_Params) \ + BS3_DECL_FAR(a_RetType) BS3_CMN_FAR_NM(a_Name) a_Params +#else +# define BS3_CMN_DEF(a_RetType, a_Name, a_Params) \ + BS3_DECL_NEAR(a_RetType) BS3_CMN_NM(a_Name) a_Params +#endif + +/** @def BS3_ASSERT + * Assert that an expression is true. + * + * Calls Bs3Panic if false and it's a strict build. Does nothing in + * non-strict builds. */ +#ifdef BS3_STRICT +# define BS3_ASSERT(a_Expr) do { if (!!(a_Expr)) { /* likely */ } else { Bs3Panic(); } } while (0) /**< @todo later */ +#else +# define BS3_ASSERT(a_Expr) do { } while (0) +#endif + +/** + * Panic, never return. + * + * The current implementation will only halt the CPU. + */ +BS3_CMN_PROTO_NOSB(DECL_NO_RETURN(void), Bs3Panic,(void)); +#if !defined(BS3_KIT_WITH_NO_RETURN) && defined(__WATCOMC__) +# pragma aux Bs3Panic_c16 __aborts +# pragma aux Bs3Panic_f16 __aborts +# pragma aux Bs3Panic_c32 __aborts +#endif + + +/** + * Translate a mode into a string. + * + * @returns Pointer to read-only mode name string. + * @param bMode The mode value (BS3_MODE_XXX). + */ +BS3_CMN_PROTO_STUB(const char BS3_FAR *, Bs3GetModeName,(uint8_t bMode)); + +/** + * Translate a mode into a short lower case string. + * + * @returns Pointer to read-only short mode name string. + * @param bMode The mode value (BS3_MODE_XXX). + */ +BS3_CMN_PROTO_STUB(const char BS3_FAR *, Bs3GetModeNameShortLower,(uint8_t bMode)); + +/** CPU vendors. */ +typedef enum BS3CPUVENDOR +{ + BS3CPUVENDOR_INVALID = 0, + BS3CPUVENDOR_INTEL, + BS3CPUVENDOR_AMD, + BS3CPUVENDOR_VIA, + BS3CPUVENDOR_CYRIX, + BS3CPUVENDOR_SHANGHAI, + BS3CPUVENDOR_UNKNOWN, + BS3CPUVENDOR_END +} BS3CPUVENDOR; + +/** + * Tries to detect the CPU vendor. + * + * @returns CPU vendor. + */ +BS3_CMN_PROTO_STUB(BS3CPUVENDOR, Bs3GetCpuVendor,(void)); + +/** + * Shutdown the system, never returns. + * + * This currently only works for VMs. When running on real systems it will + * just halt the CPU. + */ +BS3_CMN_PROTO_NOSB(void, Bs3Shutdown,(void)); + +/** + * Prints a 32-bit unsigned value as decimal to the screen. + * + * @param uValue The 32-bit value. + */ +BS3_CMN_PROTO_NOSB(void, Bs3PrintU32,(uint32_t uValue)); + +/** + * Prints a 32-bit unsigned value as hex to the screen. + * + * @param uValue The 32-bit value. + */ +BS3_CMN_PROTO_NOSB(void, Bs3PrintX32,(uint32_t uValue)); + +/** + * Formats and prints a string to the screen. + * + * See #Bs3StrFormatV for supported format types. + * + * @param pszFormat The format string. + * @param ... Format arguments. + */ +BS3_CMN_PROTO_STUB(size_t, Bs3Printf,(const char BS3_FAR *pszFormat, ...)); + +/** + * Formats and prints a string to the screen, va_list version. + * + * See #Bs3StrFormatV for supported format types. + * + * @param pszFormat The format string. + * @param va Format arguments. + */ +BS3_CMN_PROTO_STUB(size_t, Bs3PrintfV,(const char BS3_FAR *pszFormat, va_list BS3_FAR va)); + +/** + * Prints a string to the screen. + * + * @param pszString The string to print. + */ +BS3_CMN_PROTO_STUB(void, Bs3PrintStr,(const char BS3_FAR *pszString)); + +/** + * Prints a string to the screen. + * + * @param pszString The string to print. Any terminator charss will be printed. + * @param cchString The exact number of characters to print. + */ +BS3_CMN_PROTO_NOSB(void, Bs3PrintStrN,(const char BS3_FAR *pszString, size_t cchString)); + +/** + * Prints a char to the screen. + * + * @param ch The character to print. + */ +BS3_CMN_PROTO_NOSB(void, Bs3PrintChr,(char ch)); + + +/** + * An output function for #Bs3StrFormatV. + * + * @returns Number of characters written. + * @param ch The character to write. Zero in the final call. + * @param pvUser User argument supplied to #Bs3StrFormatV. + */ +typedef BS3_DECL_CALLBACK(size_t) FNBS3STRFORMATOUTPUT(char ch, void BS3_FAR *pvUser); +/** Pointer to an output function for #Bs3StrFormatV. */ +typedef FNBS3STRFORMATOUTPUT *PFNBS3STRFORMATOUTPUT; + +/** + * Formats a string, sending the output to @a pfnOutput. + * + * Supported types: + * - %RI8, %RI16, %RI32, %RI64 + * - %RU8, %RU16, %RU32, %RU64 + * - %RX8, %RX16, %RX32, %RX64 + * - %i, %d + * - %u + * - %x + * - %c + * - %p (far pointer) + * - %s (far pointer) + * + * @returns Sum of @a pfnOutput return values. + * @param pszFormat The format string. + * @param va Format arguments. + * @param pfnOutput The output function. + * @param pvUser The user argument for the output function. + */ +BS3_CMN_PROTO_STUB(size_t, Bs3StrFormatV,(const char BS3_FAR *pszFormat, va_list BS3_FAR va, + PFNBS3STRFORMATOUTPUT pfnOutput, void BS3_FAR *pvUser)); + +/** + * Formats a string into a buffer. + * + * See #Bs3StrFormatV for supported format types. + * + * @returns The length of the formatted string (excluding terminator). + * This will be higher or equal to @c cbBuf in case of an overflow. + * @param pszBuf The output buffer. + * @param cbBuf The size of the output buffer. + * @param pszFormat The format string. + * @param va Format arguments. + */ +BS3_CMN_PROTO_STUB(size_t, Bs3StrPrintfV,(char BS3_FAR *pszBuf, size_t cbBuf, const char BS3_FAR *pszFormat, va_list BS3_FAR va)); + +/** + * Formats a string into a buffer. + * + * See #Bs3StrFormatV for supported format types. + * + * @returns The length of the formatted string (excluding terminator). + * This will be higher or equal to @c cbBuf in case of an overflow. + * @param pszBuf The output buffer. + * @param cbBuf The size of the output buffer. + * @param pszFormat The format string. + * @param ... Format arguments. + */ +BS3_CMN_PROTO_STUB(size_t, Bs3StrPrintf,(char BS3_FAR *pszBuf, size_t cbBuf, const char BS3_FAR *pszFormat, ...)); + + +/** + * Finds the length of a zero terminated string. + * + * @returns String length in chars/bytes. + * @param pszString The string to examine. + */ +BS3_CMN_PROTO_STUB(size_t, Bs3StrLen,(const char BS3_FAR *pszString)); + +/** + * Finds the length of a zero terminated string, but with a max length. + * + * @returns String length in chars/bytes, or @a cchMax if no zero-terminator + * was found before we reached the limit. + * @param pszString The string to examine. + * @param cchMax The max length to examine. + */ +BS3_CMN_PROTO_STUB(size_t, Bs3StrNLen,(const char BS3_FAR *pszString, size_t cchMax)); + +/** + * CRT style unsafe strcpy. + * + * @returns pszDst. + * @param pszDst The destination buffer. Must be large enough to + * hold the source string. + * @param pszSrc The source string. + */ +BS3_CMN_PROTO_STUB(char BS3_FAR *, Bs3StrCpy,(char BS3_FAR *pszDst, const char BS3_FAR *pszSrc)); + +/** + * CRT style memcpy. + * + * @returns pvDst + * @param pvDst The destination buffer. + * @param pvSrc The source buffer. + * @param cbToCopy The number of bytes to copy. + */ +BS3_CMN_PROTO_STUB(void BS3_FAR *, Bs3MemCpy,(void BS3_FAR *pvDst, const void BS3_FAR *pvSrc, size_t cbToCopy)); + +/** + * GNU (?) style mempcpy. + * + * @returns pvDst + cbCopy + * @param pvDst The destination buffer. + * @param pvSrc The source buffer. + * @param cbToCopy The number of bytes to copy. + */ +BS3_CMN_PROTO_STUB(void BS3_FAR *, Bs3MemPCpy,(void BS3_FAR *pvDst, const void BS3_FAR *pvSrc, size_t cbToCopy)); + +/** + * CRT style memmove (overlapping buffers is fine). + * + * @returns pvDst + * @param pvDst The destination buffer. + * @param pvSrc The source buffer. + * @param cbToCopy The number of bytes to copy. + */ +BS3_CMN_PROTO_STUB(void BS3_FAR *, Bs3MemMove,(void BS3_FAR *pvDst, const void BS3_FAR *pvSrc, size_t cbToCopy)); + +/** + * BSD style bzero. + * + * @param pvDst The buffer to be zeroed. + * @param cbDst The number of bytes to zero. + */ +BS3_CMN_PROTO_NOSB(void, Bs3MemZero,(void BS3_FAR *pvDst, size_t cbDst)); + +/** + * CRT style memset. + * + * @param pvDst The buffer to be fill. + * @param bFiller The filler byte. + * @param cbDst The number of bytes to fill. + */ +BS3_CMN_PROTO_NOSB(void, Bs3MemSet,(void BS3_FAR *pvDst, uint8_t bFiller, size_t cbDst)); + +/** + * CRT style memchr. + * + * @param pvHaystack The memory to scan for @a bNeedle. + * @param bNeedle The byte to search for. + * @param cbHaystack The amount of memory to search. + */ +BS3_CMN_PROTO_NOSB(void BS3_FAR *, Bs3MemChr,(void const BS3_FAR *pvHaystack, uint8_t bNeedle, size_t cbHaystack)); + +/** + * CRT style memcmp. + * + * @returns 0 if equal. Negative if the left side is 'smaller' than the right + * side, and positive in the other case. + * @param pv1 The left hand memory. + * @param pv2 The right hand memory. + * @param cb The number of bytes to compare. + */ +BS3_CMN_PROTO_NOSB(int, Bs3MemCmp,(void const BS3_FAR *pv1, void const BS3_FAR *pv2, size_t cb)); + +BS3_CMN_PROTO_STUB(void, Bs3UInt64Div,(RTUINT64U uDividend, RTUINT64U uDivisor, RTUINT64U BS3_FAR *paQuotientReminder)); +BS3_CMN_PROTO_STUB(void, Bs3UInt32Div,(RTUINT32U uDividend, RTUINT32U uDivisor, RTUINT32U BS3_FAR *paQuotientReminder)); + + +/** + * Converts a protected mode 32-bit far pointer to a 32-bit flat address. + * + * @returns 32-bit flat address. + * @param off The segment offset. + * @param uSel The protected mode segment selector. + */ +BS3_CMN_PROTO_STUB(uint32_t, Bs3SelProtFar32ToFlat32,(uint32_t off, uint16_t uSel)); + +/** + * Converts a current mode 32-bit far pointer to a 32-bit flat address. + * + * @returns 32-bit flat address. + * @param off The segment offset. + * @param uSel The current mode segment selector. + */ +BS3_CMN_PROTO_STUB(uint32_t, Bs3SelFar32ToFlat32,(uint32_t off, uint16_t uSel)); + +/** + * Wrapper around Bs3SelFar32ToFlat32 that makes it easier to use in tight + * assembly spots. + * + * @returns 32-bit flat address. + * @param off The segment offset. + * @param uSel The current mode segment selector. + * @remarks All register are preserved, except return. + * @remarks No 20h scratch space required in 64-bit mode. + */ +BS3_CMN_PROTO_FARSTUB(6, uint32_t, Bs3SelFar32ToFlat32NoClobber,(uint32_t off, uint16_t uSel)); + +/** + * Converts a real mode code segment to a protected mode code segment selector. + * + * @returns protected mode segment selector. + * @param uRealSeg Real mode code segment. + * @remarks All register are preserved, except return and parameter. + */ +BS3_CMN_PROTO_NOSB(uint16_t, Bs3SelRealModeCodeToProtMode,(uint16_t uRealSeg)); + +/** + * Converts a real mode code segment to a protected mode code segment selector. + * + * @returns protected mode segment selector. + * @param uProtSel Real mode code segment. + * @remarks All register are preserved, except return and parameter. + */ +BS3_CMN_PROTO_NOSB(uint16_t, Bs3SelProtModeCodeToRealMode,(uint16_t uProtSel)); + +/** + * Converts a flat code address to a real mode segment and offset. + * + * @returns Far real mode address (high 16-bit is segment, low is offset). + * @param uFlatAddr Flat code address. + * @remarks All register are preserved, except return and parameter. + */ +BS3_CMN_PROTO_NOSB(uint32_t, Bs3SelFlatCodeToRealMode,(uint32_t uFlatAddr)); + +/** + * Converts a flat code address to a protected mode 16-bit far pointer (ring-0). + * + * @returns Far 16-bit protected mode address (high 16-bit is segment selector, + * low is segment offset). + * @param uFlatAddr Flat code address. + * @remarks All register are preserved, except return and parameter. + */ +BS3_CMN_PROTO_NOSB(uint32_t, Bs3SelFlatCodeToProtFar16,(uint32_t uFlatAddr)); + +/** + * Converts a far 16:16 real mode (code) address to a flat address. + * + * @returns 32-bit flat address. + * @param uFar1616 Far real mode address (high 16-bit is segment, low + * is offset). + * @remarks All register are preserved, except return. + * @remarks No 20h scratch space required in 64-bit mode. + * @remarks Exactly the same as Bs3SelRealModeDataToFlat, except for param. + */ +BS3_CMN_PROTO_FARSTUB(4, uint32_t, Bs3SelRealModeCodeToFlat,(PFNBS3FARADDRCONV uFar1616)); + +/** + * Converts a flat data address to a real mode segment and offset. + * + * @returns Far real mode address (high 16-bit is segment, low is offset) + * @param uFlatAddr Flat code address. + * @remarks All register are preserved, except return. + * @remarks No 20h scratch space required in 64-bit mode. + */ +BS3_CMN_PROTO_FARSTUB(4, uint32_t, Bs3SelFlatDataToRealMode,(uint32_t uFlatAddr)); + +/** + * Converts a flat data address to a real mode segment and offset. + * + * @returns Far 16-bit protected mode address (high 16-bit is segment selector, + * low is segment offset). + * @param uFlatAddr Flat code address. + * @remarks All register are preserved, except return. + * @remarks No 20h scratch space required in 64-bit mode. + */ +BS3_CMN_PROTO_FARSTUB(4, uint32_t, Bs3SelFlatDataToProtFar16,(uint32_t uFlatAddr)); + +/** + * Converts a far 16:16 data address to a real mode segment and offset. + * + * @returns Far real mode address (high 16-bit is segment, low is offset) + * @param uFar1616 Far 16-bit protected mode address (high 16-bit is + * segment selector, low is segment offset). + * @remarks All register are preserved, except return. + * @remarks No 20h scratch space required in 64-bit mode. + */ +BS3_CMN_PROTO_FARSTUB(4, uint32_t, Bs3SelProtFar16DataToRealMode,(uint32_t uFar1616)); + +/** + * Converts a far 16:16 real mode address to a 16-bit protected mode address. + * + * @returns Far real mode address (high 16-bit is segment, low is offset) + * @param uFar1616 Far real mode address (high 16-bit is segment, low + * is offset). + * @remarks All register are preserved, except return. + * @remarks No 20h scratch space required in 64-bit mode. + */ +BS3_CMN_PROTO_FARSTUB(4, uint32_t, Bs3SelRealModeDataToProtFar16,(uint32_t uFar1616)); + +/** + * Converts a far 16:16 data address to a flat 32-bit address. + * + * @returns 32-bit flat address. + * @param uFar1616 Far 16-bit protected mode address (high 16-bit is + * segment selector, low is segment offset). + * @remarks All register are preserved, except return. + * @remarks No 20h scratch space required in 64-bit mode. + */ +BS3_CMN_PROTO_FARSTUB(4, uint32_t, Bs3SelProtFar16DataToFlat,(uint32_t uFar1616)); + +/** + * Converts a far 16:16 real mode address to a flat address. + * + * @returns 32-bit flat address. + * @param uFar1616 Far real mode address (high 16-bit is segment, low + * is offset). + * @remarks All register are preserved, except return. + * @remarks No 20h scratch space required in 64-bit mode. + */ +BS3_CMN_PROTO_FARSTUB(4, uint32_t, Bs3SelRealModeDataToFlat,(uint32_t uFar1616)); + +/** + * Gets a flat address from a working poitner. + * + * @returns flat address (32-bit or 64-bit). + * @param pv Current context pointer. + */ +DECLINLINE(RTCCUINTXREG) Bs3SelPtrToFlat(void BS3_FAR *pv) +{ +#if ARCH_BITS == 16 + return BS3_CMN_FN_NM(Bs3SelFar32ToFlat32)(BS3_FP_OFF(pv), BS3_FP_SEG(pv)); +#else + return (uintptr_t)pv; +#endif +} + +/** + * Sets up a 16-bit read-write data selector with ring-3 access and 64KB limit. + * + * @param pDesc Pointer to the descriptor table entry. + * @param uBaseAddr The base address of the descriptor. + */ +BS3_CMN_PROTO_STUB(void, Bs3SelSetup16BitData,(X86DESC BS3_FAR *pDesc, uint32_t uBaseAddr)); + +/** + * Sets up a 16-bit execute-read selector with a 64KB limit. + * + * @param pDesc Pointer to the descriptor table entry. + * @param uBaseAddr The base address of the descriptor. + * @param bDpl The descriptor privilege level. + */ +BS3_CMN_PROTO_STUB(void, Bs3SelSetup16BitCode,(X86DESC BS3_FAR *pDesc, uint32_t uBaseAddr, uint8_t bDpl)); + + +/** + * Slab control structure list head. + * + * The slabs on the list must all have the same chunk size. + */ +typedef struct BS3SLABHEAD +{ + /** Pointer to the first slab. */ + BS3_XPTR_MEMBER(struct BS3SLABCTL, pFirst); + /** The allocation chunk size. */ + uint16_t cbChunk; + /** Number of slabs in the list. */ + uint16_t cSlabs; + /** Number of chunks in the list. */ + uint32_t cChunks; + /** Number of free chunks. */ + uint32_t cFreeChunks; +} BS3SLABHEAD; +AssertCompileSize(BS3SLABHEAD, 16); +/** Pointer to a slab list head. */ +typedef BS3SLABHEAD BS3_FAR *PBS3SLABHEAD; + +/** + * Allocation slab control structure. + * + * This may live at the start of the slab for 4KB slabs, while in a separate + * static location for the larger ones. + */ +typedef struct BS3SLABCTL +{ + /** Pointer to the next slab control structure in this list. */ + BS3_XPTR_MEMBER(struct BS3SLABCTL, pNext); + /** Pointer to the slab list head. */ + BS3_XPTR_MEMBER(BS3SLABHEAD, pHead); + /** The base address of the slab. */ + BS3_XPTR_MEMBER(uint8_t, pbStart); + /** Number of chunks in this slab. */ + uint16_t cChunks; + /** Number of currently free chunks. */ + uint16_t cFreeChunks; + /** The chunk size. */ + uint16_t cbChunk; + /** The shift count corresponding to cbChunk. + * This is for turning a chunk number into a byte offset and vice versa. */ + uint16_t cChunkShift; + /** Bitmap where set bits indicates allocated blocks (variable size, + * multiple of 4). */ + uint8_t bmAllocated[4]; +} BS3SLABCTL; +/** Pointer to a bs3kit slab control structure. */ +typedef BS3SLABCTL BS3_FAR *PBS3SLABCTL; + +/** The chunks must all be in the same 16-bit segment tile. */ +#define BS3_SLAB_ALLOC_F_SAME_TILE UINT16_C(0x0001) + +/** + * Initializes a slab. + * + * @param pSlabCtl The slab control structure to initialize. + * @param cbSlabCtl The size of the slab control structure. + * @param uFlatSlabPtr The base address of the slab. + * @param cbSlab The size of the slab. + * @param cbChunk The chunk size. + */ +BS3_CMN_PROTO_STUB(void, Bs3SlabInit,(PBS3SLABCTL pSlabCtl, size_t cbSlabCtl, uint32_t uFlatSlabPtr, + uint32_t cbSlab, uint16_t cbChunk)); + +/** + * Allocates one chunk from a slab. + * + * @returns Pointer to a chunk on success, NULL if we're out of chunks. + * @param pSlabCtl The slab constrol structure to allocate from. + */ +BS3_CMN_PROTO_STUB(void BS3_FAR *, Bs3SlabAlloc,(PBS3SLABCTL pSlabCtl)); + +/** + * Allocates one or more chunks rom a slab. + * + * @returns Pointer to the request number of chunks on success, NULL if we're + * out of chunks. + * @param pSlabCtl The slab constrol structure to allocate from. + * @param cChunks The number of contiguous chunks we want. + * @param fFlags Flags, see BS3_SLAB_ALLOC_F_XXX + */ +BS3_CMN_PROTO_STUB(void BS3_FAR *, Bs3SlabAllocEx,(PBS3SLABCTL pSlabCtl, uint16_t cChunks, uint16_t fFlags)); + +/** + * Frees one or more chunks from a slab. + * + * @returns Number of chunks actually freed. When correctly used, this will + * match the @a cChunks parameter, of course. + * @param pSlabCtl The slab constrol structure to free from. + * @param uFlatChunkPtr The flat address of the chunks to free. + * @param cChunks The number of contiguous chunks to free. + */ +BS3_CMN_PROTO_STUB(uint16_t, Bs3SlabFree,(PBS3SLABCTL pSlabCtl, uint32_t uFlatChunkPtr, uint16_t cChunks)); + + +/** + * Initializes the given slab list head. + * + * @param pHead The slab list head. + * @param cbChunk The chunk size. + */ +BS3_CMN_PROTO_STUB(void, Bs3SlabListInit,(PBS3SLABHEAD pHead, uint16_t cbChunk)); + +/** + * Adds an initialized slab control structure to the list. + * + * @param pHead The slab list head to add it to. + * @param pSlabCtl The slab control structure to add. + */ +BS3_CMN_PROTO_STUB(void, Bs3SlabListAdd,(PBS3SLABHEAD pHead, PBS3SLABCTL pSlabCtl)); + +/** + * Allocates one chunk. + * + * @returns Pointer to a chunk on success, NULL if we're out of chunks. + * @param pHead The slab list to allocate from. + */ +BS3_CMN_PROTO_STUB(void BS3_FAR *, Bs3SlabListAlloc,(PBS3SLABHEAD pHead)); + +/** + * Allocates one or more chunks. + * + * @returns Pointer to the request number of chunks on success, NULL if we're + * out of chunks. + * @param pHead The slab list to allocate from. + * @param cChunks The number of contiguous chunks we want. + * @param fFlags Flags, see BS3_SLAB_ALLOC_F_XXX + */ +BS3_CMN_PROTO_STUB(void BS3_FAR *, Bs3SlabListAllocEx,(PBS3SLABHEAD pHead, uint16_t cChunks, uint16_t fFlags)); + +/** + * Frees one or more chunks from a slab list. + * + * @param pHead The slab list to allocate from. + * @param pvChunks Pointer to the first chunk to free. + * @param cChunks The number of contiguous chunks to free. + */ +BS3_CMN_PROTO_STUB(void, Bs3SlabListFree,(PBS3SLABHEAD pHead, void BS3_FAR *pvChunks, uint16_t cChunks)); + +/** + * Allocation addressing constraints. + */ +typedef enum BS3MEMKIND +{ + /** Invalid zero type. */ + BS3MEMKIND_INVALID = 0, + /** Real mode addressable memory. */ + BS3MEMKIND_REAL, + /** Memory addressable using the 16-bit protected mode tiling. */ + BS3MEMKIND_TILED, + /** Memory addressable using 32-bit flat addressing. */ + BS3MEMKIND_FLAT32, + /** Memory addressable using 64-bit flat addressing. */ + BS3MEMKIND_FLAT64, + /** End of valid types. */ + BS3MEMKIND_END, +} BS3MEMKIND; + +/** + * Allocates low memory. + * + * @returns Pointer to a chunk on success, NULL if we're out of chunks. + * @param enmKind The kind of addressing constraints imposed on the + * allocation. + * @param cb How much to allocate. Must be 4KB or less. + */ +BS3_CMN_PROTO_STUB(void BS3_FAR *, Bs3MemAlloc,(BS3MEMKIND enmKind, size_t cb)); + +/** + * Allocates zero'ed memory. + * + * @param enmKind The kind of addressing constraints imposed on the + * allocation. + * @param cb How much to allocate. Must be 4KB or less. + */ +BS3_CMN_PROTO_STUB(void BS3_FAR *, Bs3MemAllocZ,(BS3MEMKIND enmKind, size_t cb)); + +/** + * Frees memory. + * + * @returns Pointer to a chunk on success, NULL if we're out of chunks. + * @param pv The memory to free (returned by #Bs3MemAlloc). + * @param cb The size of the allocation. + */ +BS3_CMN_PROTO_STUB(void, Bs3MemFree,(void BS3_FAR *pv, size_t cb)); + +/** + * Allocates a page with non-present pages on each side. + * + * @returns Pointer to the usable page. NULL on failure. Use + * Bs3MemGuardedTestPageFree to free the allocation. + * @param enmKind The kind of addressing constraints imposed on the + * allocation. + */ +BS3_CMN_PROTO_STUB(void BS3_FAR *, Bs3MemGuardedTestPageAlloc,(BS3MEMKIND enmKind)); + +/** + * Allocates a page with pages on each side to the @a fPte specification. + * + * @returns Pointer to the usable page. NULL on failure. Use + * Bs3MemGuardedTestPageFree to free the allocation. + * @param enmKind The kind of addressing constraints imposed on the + * allocation. + * @param fPte The page table entry specification for the guard pages. + */ +BS3_CMN_PROTO_STUB(void BS3_FAR *, Bs3MemGuardedTestPageAllocEx,(BS3MEMKIND enmKind, uint64_t fPte)); + +/** + * Frees guarded page allocated by Bs3MemGuardedTestPageAlloc or + * Bs3MemGuardedTestPageAllocEx. + * + * @param pvGuardedPage Pointer returned by Bs3MemGuardedTestPageAlloc or + * Bs3MemGuardedTestPageAllocEx. NULL is ignored. + */ +BS3_CMN_PROTO_STUB(void, Bs3MemGuardedTestPageFree,(void BS3_FAR *pvGuardedPage)); + +/** + * Print all heap info. + */ +BS3_CMN_PROTO_STUB(void, Bs3MemPrintInfo, (void)); + +/** Highes RAM byte below 4G. */ +extern uint32_t g_uBs3EndOfRamBelow4G; + + +/** + * Enables the A20 gate. + */ +BS3_CMN_PROTO_NOSB(void, Bs3A20Enable,(void)); + +/** + * Enables the A20 gate via the keyboard controller + */ +BS3_CMN_PROTO_NOSB(void, Bs3A20EnableViaKbd,(void)); + +/** + * Enables the A20 gate via the PS/2 control port A. + */ +BS3_CMN_PROTO_NOSB(void, Bs3A20EnableViaPortA,(void)); + +/** + * Disables the A20 gate. + */ +BS3_CMN_PROTO_NOSB(void, Bs3A20Disable,(void)); + +/** + * Disables the A20 gate via the keyboard controller + */ +BS3_CMN_PROTO_NOSB(void, Bs3A20DisableViaKbd,(void)); + +/** + * Disables the A20 gate via the PS/2 control port A. + */ +BS3_CMN_PROTO_NOSB(void, Bs3A20DisableViaPortA,(void)); + + +/** + * Initializes root page tables for page protected mode (PP16, PP32). + * + * @returns IPRT status code. + * @remarks Must not be called in real-mode! + */ +BS3_CMN_PROTO_STUB(int, Bs3PagingInitRootForPP,(void)); + +/** + * Initializes root page tables for PAE page protected mode (PAE16, PAE32). + * + * @returns IPRT status code. + * @remarks The default long mode page tables depends on the PAE ones. + * @remarks Must not be called in real-mode! + */ +BS3_CMN_PROTO_STUB(int, Bs3PagingInitRootForPAE,(void)); + +/** + * Initializes root page tables for long mode (LM16, LM32, LM64). + * + * @returns IPRT status code. + * @remarks The default long mode page tables depends on the PAE ones. + * @remarks Must not be called in real-mode! + */ +BS3_CMN_PROTO_STUB(int, Bs3PagingInitRootForLM,(void)); + +/** + * Modifies the page table protection of an address range. + * + * This only works on the lowest level of the page tables in the current mode. + * + * Since we generally use the largest pages available when setting up the + * initial page tables, this function will usually have to allocate and create + * more tables. This may fail if we're low on memory. + * + * @returns IPRT status code. + * @param uFlat The flat address of the first page in the range (rounded + * down nearest page boundrary). + * @param cb The range size from @a pv (rounded up to nearest page boundrary). + * @param fSet Mask of zero or more X86_PTE_XXX values to set for the range. + * @param fClear Mask of zero or more X86_PTE_XXX values to clear for the range. + */ +BS3_CMN_PROTO_STUB(int, Bs3PagingProtect,(uint64_t uFlat, uint64_t cb, uint64_t fSet, uint64_t fClear)); + +/** + * Modifies the page table protection of an address range. + * + * This only works on the lowest level of the page tables in the current mode. + * + * Since we generally use the largest pages available when setting up the + * initial page tables, this function will usually have to allocate and create + * more tables. This may fail if we're low on memory. + * + * @returns IPRT status code. + * @param pv The address of the first page in the range (rounded + * down nearest page boundrary). + * @param cb The range size from @a pv (rounded up to nearest page boundrary). + * @param fSet Mask of zero or more X86_PTE_XXX values to set for the range. + * @param fClear Mask of zero or more X86_PTE_XXX values to clear for the range. + */ +BS3_CMN_PROTO_STUB(int, Bs3PagingProtectPtr,(void BS3_FAR *pv, size_t cb, uint64_t fSet, uint64_t fClear)); + +/** + * Aliases (maps) one or more contiguous physical pages to a virtual range. + * + * @returns VBox status code. + * @retval VERR_INVALID_PARAMETER if we're in legacy paging mode and @a uDst or + * @a uPhysToAlias are not compatible with legacy paging. + * @retval VERR_OUT_OF_RANGE if we cannot traverse the page tables in this mode + * (typically real mode or v86, maybe 16-bit PE). + * @retval VERR_NO_MEMORY if we cannot allocate page tables for splitting up + * the necessary large pages. No aliasing was performed. + * + * @param uDst The virtual address to map it at. Rounded down + * to the nearest page (@a cbHowMuch is adjusted + * up). + * @param uPhysToAlias The physical address of the first page in the + * (contiguous) range to map. Chopped down to + * nearest page boundrary (@a cbHowMuch is not + * adjusted). + * @param cbHowMuch How much to map. Rounded up to nearest page. + * @param fPte The PTE flags. + */ +BS3_CMN_PROTO_STUB(int, Bs3PagingAlias,(uint64_t uDst, uint64_t uPhysToAlias, uint32_t cbHowMuch, uint64_t fPte)); + +/** + * Unaliases memory, i.e. restores the 1:1 mapping. + * + * @returns VBox status code. Cannot fail if @a uDst and @a cbHowMuch specify + * the range of a successful Bs3PagingAlias call, however it may run + * out of memory if it's breaking new ground. + * + * @param uDst The virtual address to restore to 1:1 mapping. + * Rounded down to the nearest page (@a cbHowMuch + * is adjusted up). + * @param cbHowMuch How much to restore. Rounded up to nearest page. + */ +BS3_CMN_PROTO_STUB(int, Bs3PagingUnalias,(uint64_t uDst, uint32_t cbHowMuch)); + +/** + * Get the pointer to the PTE for the given address. + * + * @returns Pointer to the PTE. + * @param uFlat The flat address of the page which PTE we want. + * @param prc Where to return additional error info. Optional. + */ +BS3_CMN_PROTO_STUB(void BS3_FAR *, Bs3PagingGetPte,(uint64_t uFlat, int *prc)); + +/** + * Paging information for an address. + */ +typedef struct BS3PAGINGINFO4ADDR +{ + /** The depth of the system's paging mode. + * This is always 2 for legacy, 3 for PAE and 4 for long mode. */ + uint8_t cEntries; + /** The size of the page structures (the entires). */ + uint8_t cbEntry; + /** Flags defined for future fun, currently zero. */ + uint16_t fFlags; + /** Union display different view on the entry pointers. */ + union + { + /** Pointer to the page structure entries, starting with the PTE as 0. + * If large pages are involved, the first entry will be NULL (first two if 1GB + * page). Same if the address is invalid on a higher level. */ + uint8_t BS3_FAR *apbEntries[4]; + /** Alternative view for legacy mode. */ + struct + { + X86PTE BS3_FAR *pPte; + X86PDE BS3_FAR *pPde; + void *pvUnused2; + void *pvUnused3; + } Legacy; + /** Alternative view for PAE and Long mode. */ + struct + { + X86PTEPAE BS3_FAR *pPte; + X86PDEPAE BS3_FAR *pPde; + X86PDPE BS3_FAR *pPdpe; + X86PML4E BS3_FAR *pPml4e; + } Pae; + } u; +} BS3PAGINGINFO4ADDR; +/** Pointer to paging information for and address. */ +typedef BS3PAGINGINFO4ADDR BS3_FAR *PBS3PAGINGINFO4ADDR; + +/** + * Queries paging information about the given virtual address. + * + * @returns VBox status code. + * @param uFlat The flat address to query information about. + * @param pPgInfo Where to return the information. + */ +BS3_CMN_PROTO_STUB(int, Bs3PagingQueryAddressInfo,(uint64_t uFlat, PBS3PAGINGINFO4ADDR pPgInfo)); + + +/** The physical / flat address of the buffer backing the canonical traps. + * This buffer is spread equally on each side of the 64-bit non-canonical + * address divide. Non-64-bit code can use this to setup trick shots and + * inspect their results. */ +extern uint32_t g_uBs3PagingCanonicalTrapsAddr; +/** The size of the buffer at g_uPagingCanonicalTraps (both sides). */ +extern uint16_t g_cbBs3PagingCanonicalTraps; +/** The size of one trap buffer (low or high). + * This is g_cbBs3PagingCanonicalTraps divided by two. */ +extern uint16_t g_cbBs3PagingOneCanonicalTrap; + +/** + * Sets up the 64-bit canonical address space trap buffers, if neceessary. + * + * @returns Pointer to the buffers (i.e. the first page of the low one) on + * success. NULL on failure. + */ +BS3_CMN_PROTO_STUB(void BS3_FAR *, Bs3PagingSetupCanonicalTraps,(void)); + +/** + * Waits for the keyboard controller to become ready. + */ +BS3_CMN_PROTO_NOSB(void, Bs3KbdWait,(void)); + +/** + * Sends a read command to the keyboard controller and gets the result. + * + * The caller is responsible for making sure the keyboard controller is ready + * for a command (call #Bs3KbdWait if unsure). + * + * @returns The value read is returned (in al). + * @param bCmd The read command. + */ +BS3_CMN_PROTO_NOSB(uint8_t, Bs3KbdRead,(uint8_t bCmd)); + +/** + * Sends a write command to the keyboard controller and then sends the data. + * + * The caller is responsible for making sure the keyboard controller is ready + * for a command (call #Bs3KbdWait if unsure). + * + * @param bCmd The write command. + * @param bData The data to write. + */ +BS3_CMN_PROTO_NOSB(void, Bs3KbdWrite,(uint8_t bCmd, uint8_t bData)); + + +/** + * Configures the PIC, once only. + * + * Subsequent calls to this function will not do anything. + * + * The PIC will be programmed to use IDT/IVT vectors 0x70 thru 0x7f, auto + * end-of-interrupt, and all IRQs masked. The individual PIC users will have to + * use #Bs3PicUpdateMask unmask their IRQ once they've got all the handlers + * installed. + */ +BS3_CMN_PROTO_STUB(void, Bs3PicSetup,(void)); + +/** + * Updates the PIC masks. + * + * @returns The new mask - master in low, slave in high byte. + * @param fAndMask Things to keep as-is. Master in low, slave in high byte. + * @param fOrMask Things to start masking. Ditto wrt bytes. + */ +BS3_CMN_PROTO_STUB(uint16_t, Bs3PicUpdateMask,(uint16_t fAndMask, uint16_t fOrMask)); + +/** + * Disables all IRQs on the PIC. + */ +BS3_CMN_PROTO_STUB(void, Bs3PicMaskAll,(void)); + + +/** + * Sets up the PIT for periodic callback. + * + * @param cHzDesired The desired Hz. Zero means max interval length + * (18.2Hz). Plase check the various PIT globals for + * the actual interval length. + */ +BS3_CMN_PROTO_STUB(void, Bs3PitSetupAndEnablePeriodTimer,(uint16_t cHzDesired)); + +/** + * Disables the PIT if active. + */ +BS3_CMN_PROTO_STUB(void, Bs3PitDisable,(void)); + +/** Nano seconds (approx) since last the PIT timer was started. */ +extern uint64_t volatile g_cBs3PitNs; +/** Milliseconds seconds (very approx) since last the PIT timer was started. */ +extern uint64_t volatile g_cBs3PitMs; +/** Number of ticks since last the PIT timer was started. */ +extern uint32_t volatile g_cBs3PitTicks; +/** The current interval in nanon seconds. */ +extern uint32_t g_cBs3PitIntervalNs; +/** The current interval in milliseconds (approximately). + * This is 0 if not yet started (used for checking the state internally). */ +extern uint16_t volatile g_cBs3PitIntervalMs; +/** The current PIT frequency (approximately). 0 if not yet started. */ +extern uint16_t g_cBs3PitIntervalHz; + + +/** + * Call 16-bit prot mode function from v8086 mode. + * + * This switches from v8086 mode to 16-bit protected mode (code) and executed + * @a fpfnCall with @a cbParams bytes of parameters pushed on the stack. + * Afterwards it switches back to v8086 mode and returns a 16-bit status code. + * + * @returns 16-bit status code if the function returned anything. + * @param fpfnCall Far real mode pointer to the function to call. + * @param cbParams The size of the parameter list, in bytes. + * @param ... The parameters. + * @sa Bs3SwitchTo32BitAndCallC + */ +BS3_CMN_PROTO_STUB(int, Bs3SwitchFromV86To16BitAndCallC,(FPFNBS3FAR fpfnCall, unsigned cbParams, ...)); + + +/** + * BS3 integer register. + */ +typedef union BS3REG +{ + /** 8-bit unsigned integer. */ + uint8_t u8; + /** 16-bit unsigned integer. */ + uint16_t u16; + /** 32-bit unsigned integer. */ + uint32_t u32; + /** 64-bit unsigned integer. */ + uint64_t u64; + /** Full unsigned integer. */ + uint64_t u; + /** High/low byte view. */ + struct + { + uint8_t bLo; + uint8_t bHi; + } b; + /** 8-bit view. */ + uint8_t au8[8]; + /** 16-bit view. */ + uint16_t au16[4]; + /** 32-bit view. */ + uint32_t au32[2]; +} BS3REG; +/** Pointer to an integer register. */ +typedef BS3REG BS3_FAR *PBS3REG; +/** Pointer to a const integer register. */ +typedef BS3REG const BS3_FAR *PCBS3REG; + +/** + * Register context (without FPU). + */ +typedef struct BS3REGCTX +{ + BS3REG rax; /**< 0x00 */ + BS3REG rcx; /**< 0x08 */ + BS3REG rdx; /**< 0x10 */ + BS3REG rbx; /**< 0x18 */ + BS3REG rsp; /**< 0x20 */ + BS3REG rbp; /**< 0x28 */ + BS3REG rsi; /**< 0x30 */ + BS3REG rdi; /**< 0x38 */ + BS3REG r8; /**< 0x40 */ + BS3REG r9; /**< 0x48 */ + BS3REG r10; /**< 0x50 */ + BS3REG r11; /**< 0x58 */ + BS3REG r12; /**< 0x60 */ + BS3REG r13; /**< 0x68 */ + BS3REG r14; /**< 0x70 */ + BS3REG r15; /**< 0x78 */ + BS3REG rflags; /**< 0x80 */ + BS3REG rip; /**< 0x88 */ + uint16_t cs; /**< 0x90 */ + uint16_t ds; /**< 0x92 */ + uint16_t es; /**< 0x94 */ + uint16_t fs; /**< 0x96 */ + uint16_t gs; /**< 0x98 */ + uint16_t ss; /**< 0x9a */ + uint16_t tr; /**< 0x9c */ + uint16_t ldtr; /**< 0x9e */ + uint8_t bMode; /**< 0xa0: BS3_MODE_XXX. */ + uint8_t bCpl; /**< 0xa1: 0-3, 0 is used for real mode. */ + uint8_t fbFlags; /**< 0xa2: BS3REG_CTX_F_XXX */ + uint8_t abPadding[5]; /**< 0xa3 */ + BS3REG cr0; /**< 0xa8 */ + BS3REG cr2; /**< 0xb0 */ + BS3REG cr3; /**< 0xb8 */ + BS3REG cr4; /**< 0xc0 */ + uint64_t uUnused; /**< 0xc8 */ +} BS3REGCTX; +AssertCompileSize(BS3REGCTX, 0xd0); +/** Pointer to a register context. */ +typedef BS3REGCTX BS3_FAR *PBS3REGCTX; +/** Pointer to a const register context. */ +typedef BS3REGCTX const BS3_FAR *PCBS3REGCTX; + +/** @name BS3REG_CTX_F_XXX - BS3REGCTX::fbFlags masks. + * @{ */ +/** The CR0 is MSW (only low 16-bit). */ +#define BS3REG_CTX_F_NO_CR0_IS_MSW UINT8_C(0x01) +/** No CR2 and CR3 values. Not in CPL 0 or CPU too old for CR2 & CR3. */ +#define BS3REG_CTX_F_NO_CR2_CR3 UINT8_C(0x02) +/** No CR4 value. The CPU is too old for CR4. */ +#define BS3REG_CTX_F_NO_CR4 UINT8_C(0x04) +/** No TR and LDTR values. Context gathered in real mode or v8086 mode. */ +#define BS3REG_CTX_F_NO_TR_LDTR UINT8_C(0x08) +/** The context doesn't have valid values for AMD64 GPR extensions. */ +#define BS3REG_CTX_F_NO_AMD64 UINT8_C(0x10) +/** @} */ + +/** + * Saves the current register context. + * + * @param pRegCtx Where to store the register context. + */ +BS3_CMN_PROTO_NOSB(void, Bs3RegCtxSave,(PBS3REGCTX pRegCtx)); + +/** + * Switch to the specified CPU bitcount, reserve additional stack and save the + * CPU context. + * + * This is for writing more flexible test drivers that can test more than the + * CPU bitcount (16-bit, 32-bit, 64-bit, and virtual 8086) of the driver itself. + * For instance a 32-bit driver can do V86 and 16-bit testing, thus saving more + * precious and problematic 16-bit code. + * + * @param pRegCtx Where to store the register context. + * @param bBitMode Bit mode to switch to, BS3_MODE_CODE_XXX. Only + * BS3_MODE_CODE_MASK is used, other bits are ignored + * to make it possible to pass a full mode value. + * @param cbExtraStack Number of bytes of additional stack to allocate. + */ +BS3_CMN_PROTO_FARSTUB(8, void, Bs3RegCtxSaveEx,(PBS3REGCTX pRegCtx, uint8_t bBitMode, uint16_t cbExtraStack)); + +/** + * Transforms a register context to a different ring. + * + * @param pRegCtx The register context. + * @param bRing The target ring (0..3). + */ +BS3_CMN_PROTO_STUB(void, Bs3RegCtxConvertToRingX,(PBS3REGCTX pRegCtx, uint8_t bRing)); + +/** + * Restores a register context. + * + * @param pRegCtx The register context to be restored and resumed. + * @param fFlags BS3REGCTXRESTORE_F_XXX. + * + * @remarks Will switch to ring-0. + * @remarks Does not return. + */ +BS3_CMN_PROTO_NOSB(DECL_NO_RETURN(void), Bs3RegCtxRestore,(PCBS3REGCTX pRegCtx, uint16_t fFlags)); +#if !defined(BS3_KIT_WITH_NO_RETURN) && defined(__WATCOMC__) +# pragma aux Bs3RegCtxRestore_c16 "_Bs3RegCtxRestore_aborts_c16" __aborts +# pragma aux Bs3RegCtxRestore_f16 "_Bs3RegCtxRestore_aborts_f16" __aborts +# pragma aux Bs3RegCtxRestore_c32 "_Bs3RegCtxRestore_aborts_c32" __aborts +#endif + +/** @name Flags for Bs3RegCtxRestore + * @{ */ +/** Skip restoring the CRx registers. */ +#define BS3REGCTXRESTORE_F_SKIP_CRX UINT16_C(0x0001) +/** Sets g_fBs3TrapNoV86Assist. */ +#define BS3REGCTXRESTORE_F_NO_V86_ASSIST UINT16_C(0x0002) +/** @} */ + +/** + * Prints the register context. + * + * @param pRegCtx The register context to be printed. + */ +BS3_CMN_PROTO_STUB(void, Bs3RegCtxPrint,(PCBS3REGCTX pRegCtx)); + +/** + * Sets a GPR and segment register to point at the same location as @a uFlat. + * + * @param pRegCtx The register context. + * @param pGpr The general purpose register to set (points within + * @a pRegCtx). + * @param pSel The selector register (points within @a pRegCtx). + * @param uFlat Flat location address. + */ +BS3_CMN_PROTO_STUB(void, Bs3RegCtxSetGrpSegFromFlat,(PBS3REGCTX pRegCtx, PBS3REG pGpr, PRTSEL pSel, RTCCUINTXREG uFlat)); + +/** + * Sets a GPR and segment register to point at the same location as @a ovPtr. + * + * @param pRegCtx The register context. + * @param pGpr The general purpose register to set (points within + * @a pRegCtx). + * @param pSel The selector register (points within @a pRegCtx). + * @param pvPtr Current context pointer. + */ +BS3_CMN_PROTO_STUB(void, Bs3RegCtxSetGrpSegFromCurPtr,(PBS3REGCTX pRegCtx, PBS3REG pGpr, PRTSEL pSel, void BS3_FAR *pvPtr)); + +/** + * Sets a GPR and DS to point at the same location as @a ovPtr. + * + * @param pRegCtx The register context. + * @param pGpr The general purpose register to set (points within + * @a pRegCtx). + * @param pvPtr Current context pointer. + */ +BS3_CMN_PROTO_STUB(void, Bs3RegCtxSetGrpDsFromCurPtr,(PBS3REGCTX pRegCtx, PBS3REG pGpr, void BS3_FAR *pvPtr)); + +/** + * Sets CS:RIP to point at the same piece of code as @a uFlatCode. + * + * @param pRegCtx The register context. + * @param uFlatCode Flat code pointer + * @sa Bs3RegCtxSetRipCsFromLnkPtr, Bs3RegCtxSetRipCsFromCurPtr + */ +BS3_CMN_PROTO_STUB(void, Bs3RegCtxSetRipCsFromFlat,(PBS3REGCTX pRegCtx, RTCCUINTXREG uFlatCode)); + +/** + * Sets CS:RIP to point at the same piece of code as @a pfnCode. + * + * The 16-bit edition of this function expects a far 16:16 address as written by + * the linker (i.e. real mode). + * + * @param pRegCtx The register context. + * @param pfnCode Pointer to the code. In 32-bit and 64-bit mode this is a + * flat address, while in 16-bit it's a far 16:16 address + * as fixed up by the linker (real mode selector). This + * address is converted to match the mode of the context. + * @sa Bs3RegCtxSetRipCsFromCurPtr, Bs3RegCtxSetRipCsFromFlat + */ +BS3_CMN_PROTO_STUB(void, Bs3RegCtxSetRipCsFromLnkPtr,(PBS3REGCTX pRegCtx, FPFNBS3FAR pfnCode)); + +/** + * Sets CS:RIP to point at the same piece of code as @a pfnCode. + * + * @param pRegCtx The register context. + * @param pfnCode Pointer to the code. Current mode pointer. + * @sa Bs3RegCtxSetRipCsFromLnkPtr, Bs3RegCtxSetRipCsFromFlat + */ +BS3_CMN_PROTO_STUB(void, Bs3RegCtxSetRipCsFromCurPtr,(PBS3REGCTX pRegCtx, FPFNBS3FAR pfnCode)); + + +/** + * The method to be used to save and restore the extended context. + */ +typedef enum BS3EXTCTXMETHOD +{ + BS3EXTCTXMETHOD_INVALID = 0, + BS3EXTCTXMETHOD_ANCIENT, /**< Ancient fnsave/frstor format. */ + BS3EXTCTXMETHOD_FXSAVE, /**< fxsave/fxrstor format. */ + BS3EXTCTXMETHOD_XSAVE, /**< xsave/xrstor format. */ + BS3EXTCTXMETHOD_END, +} BS3EXTCTXMETHOD; + + +/** + * Extended CPU context (FPU, SSE, AVX, ++). + * + * @remarks Also in bs3kit.inc + */ +typedef struct BS3EXTCTX +{ + /** Dummy/magic value. */ + uint16_t u16Magic; + /** The size of the structure. */ + uint16_t cb; + /** The method used to save and restore the context (BS3EXTCTXMETHOD). */ + uint8_t enmMethod; + uint8_t abPadding0[3]; + /** Nominal XSAVE_C_XXX. */ + uint64_t fXcr0Nominal; + /** The saved XCR0 mask (restored after xrstor). */ + uint64_t fXcr0Saved; + + /** Explicit alignment padding. */ + uint8_t abPadding[64 - 2 - 2 - 1 - 3 - 8 - 8]; + + /** The context, variable size (see above). + * This must be aligned on a 64 byte boundrary. */ + union + { + /** fnsave/frstor. */ + X86FPUSTATE Ancient; + /** fxsave/fxrstor */ + X86FXSTATE x87; + /** xsave/xrstor */ + X86XSAVEAREA x; + /** Byte array view. */ + uint8_t ab[sizeof(X86XSAVEAREA)]; + } Ctx; +} BS3EXTCTX; +AssertCompileMemberAlignment(BS3EXTCTX, Ctx, 64); +/** Pointer to an extended CPU context. */ +typedef BS3EXTCTX BS3_FAR *PBS3EXTCTX; +/** Pointer to a const extended CPU context. */ +typedef BS3EXTCTX const BS3_FAR *PCBS3EXTCTX; + +/** Magic value for BS3EXTCTX. */ +#define BS3EXTCTX_MAGIC UINT16_C(0x1980) + +/** + * Allocates and initializes the extended CPU context structure. + * + * @returns The new extended CPU context structure. + * @param enmKind The kind of allocation to make. + */ +BS3_CMN_PROTO_STUB(PBS3EXTCTX, Bs3ExtCtxAlloc,(BS3MEMKIND enmKind)); + +/** + * Frees an extended CPU context structure. + * + * @param pExtCtx The extended CPU context (returned by + * Bs3ExtCtxAlloc). + */ +BS3_CMN_PROTO_STUB(void, Bs3ExtCtxFree,(PBS3EXTCTX pExtCtx)); + +/** + * Get the size required for a BS3EXTCTX structure. + * + * @returns size in bytes of the whole structure. + * @param pfFlags Where to return flags for Bs3ExtCtxInit. + * @note Use Bs3ExtCtxAlloc when possible. + */ +BS3_CMN_PROTO_STUB(uint16_t, Bs3ExtCtxGetSize,(uint64_t *pfFlags)); + +/** + * Initializes the extended CPU context structure. + * @returns pExtCtx + * @param pExtCtx The extended CPU context. + * @param cbExtCtx The size of the @a pExtCtx allocation. + * @param fFlags XSAVE_C_XXX flags. + */ +BS3_CMN_PROTO_STUB(PBS3EXTCTX, Bs3ExtCtxInit,(PBS3EXTCTX pExtCtx, uint16_t cbExtCtx, uint64_t fFlags)); + +/** + * Saves the extended CPU state to the given structure. + * + * @param pExtCtx The extended CPU context. + * @remarks All GPRs preserved. + */ +BS3_CMN_PROTO_FARSTUB(4, void, Bs3ExtCtxSave,(PBS3EXTCTX pExtCtx)); + +/** + * Restores the extended CPU state from the given structure. + * + * @param pExtCtx The extended CPU context. + * @remarks All GPRs preserved. + */ +BS3_CMN_PROTO_FARSTUB(4, void, Bs3ExtCtxRestore,(PBS3EXTCTX pExtCtx)); + +/** + * Copies the state from one context to another. + * + * @returns pDst + * @param pDst The destination extended CPU context. + * @param pSrc The source extended CPU context. + */ +BS3_CMN_PROTO_STUB(PBS3EXTCTX, Bs3ExtCtxCopy,(PBS3EXTCTX pDst, PCBS3EXTCTX pSrc)); + + +/** @name Debug register accessors for V8086 mode (works everwhere). + * @{ */ +BS3_CMN_PROTO_NOSB(RTCCUINTXREG, Bs3RegGetDr0,(void)); +BS3_CMN_PROTO_NOSB(RTCCUINTXREG, Bs3RegGetDr1,(void)); +BS3_CMN_PROTO_NOSB(RTCCUINTXREG, Bs3RegGetDr2,(void)); +BS3_CMN_PROTO_NOSB(RTCCUINTXREG, Bs3RegGetDr3,(void)); +BS3_CMN_PROTO_NOSB(RTCCUINTXREG, Bs3RegGetDr6,(void)); +BS3_CMN_PROTO_NOSB(RTCCUINTXREG, Bs3RegGetDr7,(void)); + +BS3_CMN_PROTO_NOSB(void, Bs3RegSetDr0,(RTCCUINTXREG uValue)); +BS3_CMN_PROTO_NOSB(void, Bs3RegSetDr1,(RTCCUINTXREG uValue)); +BS3_CMN_PROTO_NOSB(void, Bs3RegSetDr2,(RTCCUINTXREG uValue)); +BS3_CMN_PROTO_NOSB(void, Bs3RegSetDr3,(RTCCUINTXREG uValue)); +BS3_CMN_PROTO_NOSB(void, Bs3RegSetDr6,(RTCCUINTXREG uValue)); +BS3_CMN_PROTO_NOSB(void, Bs3RegSetDr7,(RTCCUINTXREG uValue)); + +BS3_CMN_PROTO_NOSB(RTCCUINTXREG, Bs3RegGetDrX,(uint8_t iReg)); +BS3_CMN_PROTO_NOSB(void, Bs3RegSetDrX,(uint8_t iReg, RTCCUINTXREG uValue)); +/** @} */ + + +/** @name Control register accessors for V8086 mode (works everwhere). + * @{ */ +BS3_CMN_PROTO_NOSB(RTCCUINTXREG, Bs3RegGetCr0,(void)); +BS3_CMN_PROTO_NOSB(RTCCUINTXREG, Bs3RegGetCr2,(void)); +BS3_CMN_PROTO_NOSB(RTCCUINTXREG, Bs3RegGetCr3,(void)); +BS3_CMN_PROTO_NOSB(RTCCUINTXREG, Bs3RegGetCr4,(void)); +BS3_CMN_PROTO_NOSB(uint16_t, Bs3RegGetTr,(void)); +BS3_CMN_PROTO_NOSB(uint16_t, Bs3RegGetLdtr,(void)); + +BS3_CMN_PROTO_NOSB(void, Bs3RegSetCr0,(RTCCUINTXREG uValue)); +BS3_CMN_PROTO_NOSB(void, Bs3RegSetCr2,(RTCCUINTXREG uValue)); +BS3_CMN_PROTO_NOSB(void, Bs3RegSetCr3,(RTCCUINTXREG uValue)); +BS3_CMN_PROTO_NOSB(void, Bs3RegSetCr4,(RTCCUINTXREG uValue)); +BS3_CMN_PROTO_NOSB(void, Bs3RegSetTr,(uint16_t uValue)); +BS3_CMN_PROTO_NOSB(void, Bs3RegSetLdtr,(uint16_t uValue)); +/** @} */ + + +/** + * Trap frame. + */ +typedef struct BS3TRAPFRAME +{ + /** 0x00: Exception/interrupt number. */ + uint8_t bXcpt; + /** 0x01: The size of the IRET frame. */ + uint8_t cbIretFrame; + /** 0x02: The handler CS. */ + uint16_t uHandlerCs; + /** 0x04: The handler SS. */ + uint16_t uHandlerSs; + /** 0x06: Explicit alignment. */ + uint16_t usAlignment; + /** 0x08: The handler RSP (pointer to the iret frame, skipping ErrCd). */ + uint64_t uHandlerRsp; + /** 0x10: The handler RFLAGS value. */ + uint64_t fHandlerRfl; + /** 0x18: The error code (if applicable). */ + uint64_t uErrCd; + /** 0x20: The register context. */ + BS3REGCTX Ctx; +} BS3TRAPFRAME; +AssertCompileSize(BS3TRAPFRAME, 0x20 + 0xd0); +/** Pointer to a trap frame. */ +typedef BS3TRAPFRAME BS3_FAR *PBS3TRAPFRAME; +/** Pointer to a const trap frame. */ +typedef BS3TRAPFRAME const BS3_FAR *PCBS3TRAPFRAME; + + +/** + * Re-initializes the trap handling for the current mode. + * + * Useful after a test that messes with the IDT/IVT. + * + * @sa Bs3TrapInit + */ +BS3_CMN_PROTO_STUB(void, Bs3TrapReInit,(void)); + +/** + * Initializes real mode and v8086 trap handling. + * + * @remarks Does not install RM/V86 trap handling, just initializes the + * structures. + */ +BS3_CMN_PROTO_STUB(void, Bs3TrapRmV86Init,(void)); + +/** + * Initializes real mode and v8086 trap handling, extended version. + * + * @param f386Plus Set if the CPU is 80386 or later and + * extended registers should be saved. Once initialized + * with this parameter set to @a true, the effect cannot be + * reversed. + * + * @remarks Does not install RM/V86 trap handling, just initializes the + * structures. + */ +BS3_CMN_PROTO_STUB(void, Bs3TrapRmV86InitEx,(bool f386Plus)); + +/** + * Initializes 16-bit (protected mode) trap handling. + * + * @remarks Does not install 16-bit trap handling, just initializes the + * structures. + */ +BS3_CMN_PROTO_STUB(void, Bs3Trap16Init,(void)); + +/** + * Initializes 16-bit (protected mode) trap handling, extended version. + * + * @param f386Plus Set if the CPU is 80386 or later and + * extended registers should be saved. Once initialized + * with this parameter set to @a true, the effect cannot be + * reversed. + * + * @remarks Does not install 16-bit trap handling, just initializes the + * structures. + */ +BS3_CMN_PROTO_STUB(void, Bs3Trap16InitEx,(bool f386Plus)); + +/** + * Initializes 32-bit trap handling. + * + * @remarks Does not install 32-bit trap handling, just initializes the + * structures. + */ +BS3_CMN_PROTO_STUB(void, Bs3Trap32Init,(void)); + +/** + * Initializes 64-bit trap handling + * + * @remarks Does not install 64-bit trap handling, just initializes the + * structures. + */ +BS3_CMN_PROTO_STUB(void, Bs3Trap64Init,(void)); + +/** + * Modifies the real-mode / V86 IVT entry specified by @a iIvt. + * + * @param iIvt The index of the IDT entry to set. + * @param uSeg The handler real-mode segment. + * @param off The handler offset. + */ +BS3_CMN_PROTO_STUB(void, Bs3TrapRmV86SetGate,(uint8_t iIvt, uint16_t uSeg, uint16_t off)); + +/** + * Modifies the 16-bit IDT entry (protected mode) specified by @a iIdt. + * + * @param iIdt The index of the IDT entry to set. + * @param bType The gate type (X86_SEL_TYPE_SYS_XXX). + * @param bDpl The DPL. + * @param uSel The handler selector. + * @param off The handler offset (if applicable). + * @param cParams The parameter count (for call gates). + */ +BS3_CMN_PROTO_STUB(void, Bs3Trap16SetGate,(uint8_t iIdt, uint8_t bType, uint8_t bDpl, + uint16_t uSel, uint16_t off, uint8_t cParams)); + +/** The address of Bs3Trap16GenericEntries. + * Bs3Trap16GenericEntries is an array of interrupt/trap/whatever entry + * points, 8 bytes each, that will create a register frame and call the generic + * C compatible trap handlers. */ +extern uint32_t g_Bs3Trap16GenericEntriesFlatAddr; + +/** + * Modifies the 32-bit IDT entry specified by @a iIdt. + * + * @param iIdt The index of the IDT entry to set. + * @param bType The gate type (X86_SEL_TYPE_SYS_XXX). + * @param bDpl The DPL. + * @param uSel The handler selector. + * @param off The handler offset (if applicable). + * @param cParams The parameter count (for call gates). + */ +BS3_CMN_PROTO_STUB(void, Bs3Trap32SetGate,(uint8_t iIdt, uint8_t bType, uint8_t bDpl, + uint16_t uSel, uint32_t off, uint8_t cParams)); + +/** The address of Bs3Trap32GenericEntries. + * Bs3Trap32GenericEntries is an array of interrupt/trap/whatever entry + * points, 10 bytes each, that will create a register frame and call the generic + * C compatible trap handlers. */ +extern uint32_t g_Bs3Trap32GenericEntriesFlatAddr; + +/** + * Modifies the 64-bit IDT entry specified by @a iIdt. + * + * @param iIdt The index of the IDT entry to set. + * @param bType The gate type (X86_SEL_TYPE_SYS_XXX). + * @param bDpl The DPL. + * @param uSel The handler selector. + * @param off The handler offset (if applicable). + * @param bIst The interrupt stack to use. + */ +BS3_CMN_PROTO_STUB(void, Bs3Trap64SetGate,(uint8_t iIdt, uint8_t bType, uint8_t bDpl, uint16_t uSel, uint64_t off, uint8_t bIst)); + +/** The address of Bs3Trap64GenericEntries. + * Bs3Trap64GenericEntries is an array of interrupt/trap/whatever entry + * points, 8 bytes each, that will create a register frame and call the generic + * C compatible trap handlers. */ +extern uint32_t g_Bs3Trap64GenericEntriesFlatAddr; + +/** + * Adjusts the DPL the IDT entry specified by @a iIdt. + * + * The change is applied to the 16-bit, 32-bit and 64-bit IDTs. + * + * @returns Old DPL (from 64-bit IDT). + * @param iIdt The index of the IDT and IVT entry to set. + * @param bDpl The DPL. + */ +BS3_CMN_PROTO_STUB(uint8_t, Bs3TrapSetDpl,(uint8_t iIdt, uint8_t bDpl)); + +/** + * C-style trap handler. + * + * The caller will resume the context in @a pTrapFrame upon return. + * + * @param pTrapFrame The trap frame. Registers can be modified. + * @note The 16-bit versions must be in CGROUP16! + */ +typedef BS3_DECL_NEAR_CALLBACK(void) FNBS3TRAPHANDLER(PBS3TRAPFRAME pTrapFrame); +/** Pointer to a trap handler (current template context). */ +typedef FNBS3TRAPHANDLER *PFNBS3TRAPHANDLER; + +#if ARCH_BITS == 16 +/** @copydoc FNBS3TRAPHANDLER */ +typedef FNBS3FAR FNBS3TRAPHANDLER32; +/** @copydoc FNBS3TRAPHANDLER */ +typedef FNBS3FAR FNBS3TRAPHANDLER64; +#else +/** @copydoc FNBS3TRAPHANDLER */ +typedef FNBS3TRAPHANDLER FNBS3TRAPHANDLER32; +/** @copydoc FNBS3TRAPHANDLER */ +typedef FNBS3TRAPHANDLER FNBS3TRAPHANDLER64; +#endif +/** @copydoc PFNBS3TRAPHANDLER */ +typedef FNBS3TRAPHANDLER32 *PFNBS3TRAPHANDLER32; +/** @copydoc PFNBS3TRAPHANDLER */ +typedef FNBS3TRAPHANDLER64 *PFNBS3TRAPHANDLER64; + + +/** + * C-style trap handler, near 16-bit (CGROUP16). + * + * The caller will resume the context in @a pTrapFrame upon return. + * + * @param pTrapFrame The trap frame. Registers can be modified. + */ +typedef BS3_DECL_NEAR_CALLBACK(void) FNBS3TRAPHANDLER16(PBS3TRAPFRAME pTrapFrame); +/** Pointer to a trap handler (current template context). */ +typedef FNBS3TRAPHANDLER16 *PFNBS3TRAPHANDLER16; + +/** + * C-style trap handler, near 16-bit (CGROUP16). + * + * The caller will resume the context in @a pTrapFrame upon return. + * + * @param pTrapFrame The trap frame. Registers can be modified. + */ +typedef BS3_DECL_CALLBACK(void) FNBS3TRAPHANDLER3264(PBS3TRAPFRAME pTrapFrame); +/** Pointer to a trap handler (current template context). */ +typedef FNBS3TRAPHANDLER3264 *FPFNBS3TRAPHANDLER3264; + + +/** + * Sets a trap handler (C/C++/assembly) for the current bitcount. + * + * @returns Previous handler. + * @param iIdt The index of the IDT entry to set. + * @param pfnHandler Pointer to the handler. + * @sa Bs3TrapSetHandlerEx + */ +BS3_CMN_PROTO_STUB(PFNBS3TRAPHANDLER, Bs3TrapSetHandler,(uint8_t iIdt, PFNBS3TRAPHANDLER pfnHandler)); + +/** + * Sets a trap handler (C/C++/assembly) for all the bitcounts. + * + * @param iIdt The index of the IDT and IVT entry to set. + * @param pfnHandler16 Pointer to the 16-bit handler. (Assumes linker addresses.) + * @param pfnHandler32 Pointer to the 32-bit handler. (Assumes linker addresses.) + * @param pfnHandler64 Pointer to the 64-bit handler. (Assumes linker addresses.) + * @sa Bs3TrapSetHandler + */ +BS3_CMN_PROTO_STUB(void, Bs3TrapSetHandlerEx,(uint8_t iIdt, PFNBS3TRAPHANDLER16 pfnHandler16, + PFNBS3TRAPHANDLER32 pfnHandler32, PFNBS3TRAPHANDLER64 pfnHandler64)); + +/** + * Default C/C++ trap handler. + * + * This will check trap record and panic if no match was found. + * + * @param pTrapFrame Trap frame of the trap to handle. + */ +BS3_CMN_PROTO_STUB(void, Bs3TrapDefaultHandler,(PBS3TRAPFRAME pTrapFrame)); + +/** + * Prints the trap frame (to screen). + * @param pTrapFrame Trap frame to print. + */ +BS3_CMN_PROTO_STUB(void, Bs3TrapPrintFrame,(PCBS3TRAPFRAME pTrapFrame)); + +/** + * Sets up a long jump from a trap handler. + * + * The long jump will only be performed onced, but will catch any kind of trap, + * fault, interrupt or irq. + * + * @retval true on the initial call. + * @retval false on trap return. + * @param pTrapFrame Where to store the trap information when + * returning @c false. + * @sa #Bs3TrapUnsetJmp + */ +BS3_CMN_PROTO_NOSB(DECL_RETURNS_TWICE(bool),Bs3TrapSetJmp,(PBS3TRAPFRAME pTrapFrame)); + +/** + * Combination of #Bs3TrapSetJmp and #Bs3RegCtxRestore. + * + * @param pCtxRestore The context to restore. + * @param pTrapFrame Where to store the trap information. + */ +BS3_CMN_PROTO_STUB(void, Bs3TrapSetJmpAndRestore,(PCBS3REGCTX pCtxRestore, PBS3TRAPFRAME pTrapFrame)); + +/** + * Disables a previous #Bs3TrapSetJmp call. + */ +BS3_CMN_PROTO_STUB(void, Bs3TrapUnsetJmp,(void)); + + +/** + * The current test step. + */ +extern uint16_t g_usBs3TestStep; + +/** + * Equivalent to RTTestCreate + RTTestBanner. + * + * @param pszTest The test name. + */ +BS3_CMN_PROTO_STUB(void, Bs3TestInit,(const char BS3_FAR *pszTest)); + + +/** + * Equivalent to RTTestSummaryAndDestroy. + */ +BS3_CMN_PROTO_STUB(void, Bs3TestTerm,(void)); + +/** + * Equivalent to RTTestISub. + */ +BS3_CMN_PROTO_STUB(void, Bs3TestSub,(const char BS3_FAR *pszSubTest)); + +/** + * Equivalent to RTTestIFailedF. + */ +BS3_CMN_PROTO_STUB(void, Bs3TestSubF,(const char BS3_FAR *pszFormat, ...)); + +/** + * Equivalent to RTTestISubV. + */ +BS3_CMN_PROTO_STUB(void, Bs3TestSubV,(const char BS3_FAR *pszFormat, va_list BS3_FAR va)); + +/** + * Equivalent to RTTestISubDone. + */ +BS3_CMN_PROTO_STUB(void, Bs3TestSubDone,(void)); + +/** + * Equivalent to RTTestSubErrorCount. + */ +BS3_CMN_PROTO_STUB(uint16_t, Bs3TestSubErrorCount,(void)); + +/** + * Equivalent to RTTestIPrintf with RTTESTLVL_ALWAYS. + * + * @param pszFormat What to print, format string. Explicit newline char. + * @param ... String format arguments. + */ +BS3_CMN_PROTO_STUB(void, Bs3TestPrintf,(const char BS3_FAR *pszFormat, ...)); + +/** + * Equivalent to RTTestIPrintfV with RTTESTLVL_ALWAYS. + * + * @param pszFormat What to print, format string. Explicit newline char. + * @param va String format arguments. + */ +BS3_CMN_PROTO_STUB(void, Bs3TestPrintfV,(const char BS3_FAR *pszFormat, va_list BS3_FAR va)); + +/** + * Same as Bs3TestPrintf, except no guest screen echo. + * + * @param pszFormat What to print, format string. Explicit newline char. + * @param ... String format arguments. + */ +BS3_CMN_PROTO_STUB(void, Bs3TestHostPrintf,(const char BS3_FAR *pszFormat, ...)); + +/** + * Same as Bs3TestPrintfV, except no guest screen echo. + * + * @param pszFormat What to print, format string. Explicit newline char. + * @param va String format arguments. + */ +BS3_CMN_PROTO_STUB(void, Bs3TestHostPrintfV,(const char BS3_FAR *pszFormat, va_list BS3_FAR va)); + +/** + * Equivalent to RTTestIFailed. + * @returns false. + */ +BS3_CMN_PROTO_STUB(bool, Bs3TestFailed,(const char BS3_FAR *pszMessage)); + +/** + * Equivalent to RTTestIFailedF. + * @returns false. + */ +BS3_CMN_PROTO_STUB(bool, Bs3TestFailedF,(const char BS3_FAR *pszFormat, ...)); + +/** + * Equivalent to RTTestIFailedV. + * @returns false. + */ +BS3_CMN_PROTO_STUB(bool, Bs3TestFailedV,(const char BS3_FAR *pszFormat, va_list BS3_FAR va)); + +/** + * Equivalent to RTTestISkipped. + * + * @param pszWhy Optional reason why it's being skipped. + */ +BS3_CMN_PROTO_STUB(void, Bs3TestSkipped,(const char BS3_FAR *pszWhy)); + +/** + * Equivalent to RTTestISkippedF. + * + * @param pszFormat Optional reason why it's being skipped. + * @param ... Format arguments. + */ +BS3_CMN_PROTO_STUB(void, Bs3TestSkippedF,(const char BS3_FAR *pszFormat, ...)); + +/** + * Equivalent to RTTestISkippedV. + * + * @param pszFormat Optional reason why it's being skipped. + * @param va Format arguments. + */ +BS3_CMN_PROTO_STUB(void, Bs3TestSkippedV,(const char BS3_FAR *pszFormat, va_list BS3_FAR va)); + +/** + * Compares two register contexts, with PC and SP adjustments. + * + * Differences will be reported as test failures. + * + * @returns true if equal, false if not. + * @param pActualCtx The actual register context. + * @param pExpectedCtx Expected register context. + * @param cbPcAdjust Program counter adjustment (applied to @a pExpectedCtx). + * @param cbSpAdjust Stack pointer adjustment (applied to @a pExpectedCtx). + * @param fExtraEfl Extra EFLAGS to OR into @a pExepctedCtx. + * @param pszMode CPU mode or some other helpful text. + * @param idTestStep Test step identifier. + */ +BS3_CMN_PROTO_STUB(bool, Bs3TestCheckRegCtxEx,(PCBS3REGCTX pActualCtx, PCBS3REGCTX pExpectedCtx, uint16_t cbPcAdjust, + int16_t cbSpAdjust, uint32_t fExtraEfl, const char *pszMode, uint16_t idTestStep)); + +/** + * Performs the testing for the given mode. + * + * This is called with the CPU already switch to that mode. + * + * @returns 0 on success or directly Bs3TestFailed calls, non-zero to indicate + * where the test when wrong. Special value BS3TESTDOMODE_SKIPPED + * should be returned to indicate that the test has been skipped. + * @param bMode The current CPU mode. + */ +typedef BS3_DECL_CALLBACK(uint8_t) FNBS3TESTDOMODE(uint8_t bMode); +/** Pointer (far) to a test (for 32-bit and 64-bit code, will be flatten). */ +typedef FNBS3TESTDOMODE *PFNBS3TESTDOMODE; + +/** Special FNBS3TESTDOMODE return code for indicating a skipped mode test. */ +#define BS3TESTDOMODE_SKIPPED UINT8_MAX + +/** + * Mode sub-test entry. + * + * This can only be passed around to functions with the same bit count, as it + * contains function pointers. In 16-bit mode, the 16-bit pointers are near and + * implies BS3TEXT16, whereas the 32-bit and 64-bit pointers are far real mode + * addresses that will be converted to flat address prior to calling them. + * Similarly, in 32-bit and 64-bit the addresses are all flat and the 16-bit + * ones will be converted to BS3TEXT16 based addresses prior to calling. + */ +typedef struct BS3TESTMODEENTRY +{ + /** The sub-test name to be passed to Bs3TestSub if not NULL. */ + const char * BS3_FAR pszSubTest; + + PFNBS3TESTDOMODE pfnDoRM; + + PFNBS3TESTDOMODE pfnDoPE16; + PFNBS3TESTDOMODE pfnDoPE16_32; + PFNBS3TESTDOMODE pfnDoPE16_V86; + PFNBS3TESTDOMODE pfnDoPE32; + PFNBS3TESTDOMODE pfnDoPE32_16; + PFNBS3TESTDOMODE pfnDoPEV86; + + PFNBS3TESTDOMODE pfnDoPP16; + PFNBS3TESTDOMODE pfnDoPP16_32; + PFNBS3TESTDOMODE pfnDoPP16_V86; + PFNBS3TESTDOMODE pfnDoPP32; + PFNBS3TESTDOMODE pfnDoPP32_16; + PFNBS3TESTDOMODE pfnDoPPV86; + + PFNBS3TESTDOMODE pfnDoPAE16; + PFNBS3TESTDOMODE pfnDoPAE16_32; + PFNBS3TESTDOMODE pfnDoPAE16_V86; + PFNBS3TESTDOMODE pfnDoPAE32; + PFNBS3TESTDOMODE pfnDoPAE32_16; + PFNBS3TESTDOMODE pfnDoPAEV86; + + PFNBS3TESTDOMODE pfnDoLM16; + PFNBS3TESTDOMODE pfnDoLM32; + PFNBS3TESTDOMODE pfnDoLM64; + +} BS3TESTMODEENTRY; +/** Pointer to a mode sub-test entry. */ +typedef BS3TESTMODEENTRY const *PCBS3TESTMODEENTRY; + +/** @def BS3TESTMODEENTRY_CMN + * Produces a BS3TESTMODEENTRY initializer for common (c16,c32,c64) test + * functions. */ +#define BS3TESTMODEENTRY_CMN(a_szTest, a_BaseNm) \ + { /*pszSubTest =*/ a_szTest, \ + /*RM*/ RT_CONCAT(a_BaseNm, _c16), \ + /*PE16*/ RT_CONCAT(a_BaseNm, _c16), \ + /*PE16_32*/ RT_CONCAT(a_BaseNm, _c32), \ + /*PE16_V86*/ RT_CONCAT(a_BaseNm, _c16), \ + /*PE32*/ RT_CONCAT(a_BaseNm, _c32), \ + /*PE32_16*/ RT_CONCAT(a_BaseNm, _c16), \ + /*PEV86*/ RT_CONCAT(a_BaseNm, _c16), \ + /*PP16*/ RT_CONCAT(a_BaseNm, _c16), \ + /*PP16_32*/ RT_CONCAT(a_BaseNm, _c32), \ + /*PP16_V86*/ RT_CONCAT(a_BaseNm, _c16), \ + /*PP32*/ RT_CONCAT(a_BaseNm, _c32), \ + /*PP32_16*/ RT_CONCAT(a_BaseNm, _c16), \ + /*PPV86*/ RT_CONCAT(a_BaseNm, _c16), \ + /*PAE16*/ RT_CONCAT(a_BaseNm, _c16), \ + /*PAE16_32*/ RT_CONCAT(a_BaseNm, _c32), \ + /*PAE16_V86*/ RT_CONCAT(a_BaseNm, _c16), \ + /*PAE32*/ RT_CONCAT(a_BaseNm, _c32), \ + /*PAE32_16*/ RT_CONCAT(a_BaseNm, _c16), \ + /*PAEV86*/ RT_CONCAT(a_BaseNm, _c16), \ + /*LM16*/ RT_CONCAT(a_BaseNm, _c16), \ + /*LM32*/ RT_CONCAT(a_BaseNm, _c32), \ + /*LM64*/ RT_CONCAT(a_BaseNm, _c64), \ + } + +/** @def BS3TESTMODE_PROTOTYPES_CMN + * A set of standard protypes to go with #BS3TESTMODEENTRY_CMN. */ +#define BS3TESTMODE_PROTOTYPES_CMN(a_BaseNm) \ + FNBS3TESTDOMODE /*BS3_FAR_CODE*/ RT_CONCAT(a_BaseNm, _c16); \ + FNBS3TESTDOMODE /*BS3_FAR_CODE*/ RT_CONCAT(a_BaseNm, _c32); \ + FNBS3TESTDOMODE /*BS3_FAR_CODE*/ RT_CONCAT(a_BaseNm, _c64) + +/** @def BS3TESTMODEENTRY_CMN_64 + * Produces a BS3TESTMODEENTRY initializer for common 64-bit test functions. */ +#define BS3TESTMODEENTRY_CMN_64(a_szTest, a_BaseNm) \ + { /*pszSubTest =*/ a_szTest, \ + /*RM*/ NULL, \ + /*PE16*/ NULL, \ + /*PE16_32*/ NULL, \ + /*PE16_V86*/ NULL, \ + /*PE32*/ NULL, \ + /*PE32_16*/ NULL, \ + /*PEV86*/ NULL, \ + /*PP16*/ NULL, \ + /*PP16_32*/ NULL, \ + /*PP16_V86*/ NULL, \ + /*PP32*/ NULL, \ + /*PP32_16*/ NULL, \ + /*PPV86*/ NULL, \ + /*PAE16*/ NULL, \ + /*PAE16_32*/ NULL, \ + /*PAE16_V86*/ NULL, \ + /*PAE32*/ NULL, \ + /*PAE32_16*/ NULL, \ + /*PAEV86*/ NULL, \ + /*LM16*/ NULL, \ + /*LM32*/ NULL, \ + /*LM64*/ RT_CONCAT(a_BaseNm, _c64), \ + } + +/** @def BS3TESTMODE_PROTOTYPES_CMN + * Standard protype to go with #BS3TESTMODEENTRY_CMN_64. */ +#define BS3TESTMODE_PROTOTYPES_CMN_64(a_BaseNm) \ + FNBS3TESTDOMODE /*BS3_FAR_CODE*/ RT_CONCAT(a_BaseNm, _c64) + +/** @def BS3TESTMODEENTRY_MODE + * Produces a BS3TESTMODEENTRY initializer for a full set of mode test + * functions. */ +#define BS3TESTMODEENTRY_MODE(a_szTest, a_BaseNm) \ + { /*pszSubTest =*/ a_szTest, \ + /*RM*/ RT_CONCAT(a_BaseNm, _rm), \ + /*PE16*/ RT_CONCAT(a_BaseNm, _pe16), \ + /*PE16_32*/ RT_CONCAT(a_BaseNm, _pe16_32), \ + /*PE16_V86*/ RT_CONCAT(a_BaseNm, _pe16_v86), \ + /*PE32*/ RT_CONCAT(a_BaseNm, _pe32), \ + /*PE32_16*/ RT_CONCAT(a_BaseNm, _pe32_16), \ + /*PEV86*/ RT_CONCAT(a_BaseNm, _pev86), \ + /*PP16*/ RT_CONCAT(a_BaseNm, _pp16), \ + /*PP16_32*/ RT_CONCAT(a_BaseNm, _pp16_32), \ + /*PP16_V86*/ RT_CONCAT(a_BaseNm, _pp16_v86), \ + /*PP32*/ RT_CONCAT(a_BaseNm, _pp32), \ + /*PP32_16*/ RT_CONCAT(a_BaseNm, _pp32_16), \ + /*PPV86*/ RT_CONCAT(a_BaseNm, _ppv86), \ + /*PAE16*/ RT_CONCAT(a_BaseNm, _pae16), \ + /*PAE16_32*/ RT_CONCAT(a_BaseNm, _pae16_32), \ + /*PAE16_V86*/ RT_CONCAT(a_BaseNm, _pae16_v86), \ + /*PAE32*/ RT_CONCAT(a_BaseNm, _pae32), \ + /*PAE32_16*/ RT_CONCAT(a_BaseNm, _pae32_16), \ + /*PAEV86*/ RT_CONCAT(a_BaseNm, _paev86), \ + /*LM16*/ RT_CONCAT(a_BaseNm, _lm16), \ + /*LM32*/ RT_CONCAT(a_BaseNm, _lm32), \ + /*LM64*/ RT_CONCAT(a_BaseNm, _lm64), \ + } + +/** @def BS3TESTMODE_PROTOTYPES_MODE + * A set of standard protypes to go with #BS3TESTMODEENTRY_MODE. */ +#define BS3TESTMODE_PROTOTYPES_MODE(a_BaseNm) \ + FNBS3TESTDOMODE RT_CONCAT(a_BaseNm, _rm); \ + FNBS3TESTDOMODE RT_CONCAT(a_BaseNm, _pe16); \ + FNBS3TESTDOMODE RT_CONCAT(a_BaseNm, _pe16_32); \ + FNBS3TESTDOMODE RT_CONCAT(a_BaseNm, _pe16_v86); \ + FNBS3TESTDOMODE RT_CONCAT(a_BaseNm, _pe32); \ + FNBS3TESTDOMODE RT_CONCAT(a_BaseNm, _pe32_16); \ + FNBS3TESTDOMODE RT_CONCAT(a_BaseNm, _pev86); \ + FNBS3TESTDOMODE RT_CONCAT(a_BaseNm, _pp16); \ + FNBS3TESTDOMODE RT_CONCAT(a_BaseNm, _pp16_32); \ + FNBS3TESTDOMODE RT_CONCAT(a_BaseNm, _pp16_v86); \ + FNBS3TESTDOMODE RT_CONCAT(a_BaseNm, _pp32); \ + FNBS3TESTDOMODE RT_CONCAT(a_BaseNm, _pp32_16); \ + FNBS3TESTDOMODE RT_CONCAT(a_BaseNm, _ppv86); \ + FNBS3TESTDOMODE RT_CONCAT(a_BaseNm, _pae16); \ + FNBS3TESTDOMODE RT_CONCAT(a_BaseNm, _pae16_32); \ + FNBS3TESTDOMODE RT_CONCAT(a_BaseNm, _pae16_v86); \ + FNBS3TESTDOMODE RT_CONCAT(a_BaseNm, _pae32); \ + FNBS3TESTDOMODE RT_CONCAT(a_BaseNm, _pae32_16); \ + FNBS3TESTDOMODE RT_CONCAT(a_BaseNm, _paev86); \ + FNBS3TESTDOMODE RT_CONCAT(a_BaseNm, _lm16); \ + FNBS3TESTDOMODE RT_CONCAT(a_BaseNm, _lm32); \ + FNBS3TESTDOMODE RT_CONCAT(a_BaseNm, _lm64) + + +/** + * Mode sub-test entry, max bit-count driven + * + * This is an alternative to BS3TESTMODEENTRY where a few workers (test drivers) + * does all the work, using faster 32-bit and 64-bit code where possible. This + * avoids executing workers in V8086 mode. It allows for modifying and checking + * 64-bit register content when testing LM16 and LM32. + * + * The 16-bit workers are only used for real mode and 16-bit protected mode. + * So, the 16-bit version of the code template can be stripped of anything + * related to paging and/or v8086, saving code space. + */ +typedef struct BS3TESTMODEBYMAXENTRY +{ + /** The sub-test name to be passed to Bs3TestSub if not NULL. */ + const char * BS3_FAR pszSubTest; + + PFNBS3TESTDOMODE pfnDoRM; + PFNBS3TESTDOMODE pfnDoPE16; + PFNBS3TESTDOMODE pfnDoPE16_32; + PFNBS3TESTDOMODE pfnDoPE32; + PFNBS3TESTDOMODE pfnDoPP16_32; + PFNBS3TESTDOMODE pfnDoPP32; + PFNBS3TESTDOMODE pfnDoPAE16_32; + PFNBS3TESTDOMODE pfnDoPAE32; + PFNBS3TESTDOMODE pfnDoLM64; + + bool fDoRM : 1; + + bool fDoPE16 : 1; + bool fDoPE16_32 : 1; + bool fDoPE16_V86 : 1; + bool fDoPE32 : 1; + bool fDoPE32_16 : 1; + bool fDoPEV86 : 1; + + bool fDoPP16 : 1; + bool fDoPP16_32 : 1; + bool fDoPP16_V86 : 1; + bool fDoPP32 : 1; + bool fDoPP32_16 : 1; + bool fDoPPV86 : 1; + + bool fDoPAE16 : 1; + bool fDoPAE16_32 : 1; + bool fDoPAE16_V86 : 1; + bool fDoPAE32 : 1; + bool fDoPAE32_16 : 1; + bool fDoPAEV86 : 1; + + bool fDoLM16 : 1; + bool fDoLM32 : 1; + bool fDoLM64 : 1; + +} BS3TESTMODEBYMAXENTRY; +/** Pointer to a mode-by-max sub-test entry. */ +typedef BS3TESTMODEBYMAXENTRY const *PCBS3TESTMODEBYMAXENTRY; + +/** @def BS3TESTMODEBYMAXENTRY_CMN + * Produces a BS3TESTMODEBYMAXENTRY initializer for common (c16,c32,c64) test + * functions. */ +#define BS3TESTMODEBYMAXENTRY_CMN(a_szTest, a_BaseNm) \ + { /*pszSubTest =*/ a_szTest, \ + /*RM*/ RT_CONCAT(a_BaseNm, _c16), \ + /*PE16*/ RT_CONCAT(a_BaseNm, _c16), \ + /*PE16_32*/ RT_CONCAT(a_BaseNm, _c32), \ + /*PE32*/ RT_CONCAT(a_BaseNm, _c32), \ + /*PP16_32*/ RT_CONCAT(a_BaseNm, _c32), \ + /*PP32*/ RT_CONCAT(a_BaseNm, _c32), \ + /*PAE16_32*/ RT_CONCAT(a_BaseNm, _c32), \ + /*PAE32*/ RT_CONCAT(a_BaseNm, _c32), \ + /*LM64*/ RT_CONCAT(a_BaseNm, _c64), \ + /*fDoRM*/ true, \ + /*fDoPE16*/ true, \ + /*fDoPE16_32*/ true, \ + /*fDoPE16_V86*/ true, \ + /*fDoPE32*/ true, \ + /*fDoPE32_16*/ true, \ + /*fDoPEV86*/ true, \ + /*fDoPP16*/ true, \ + /*fDoPP16_32*/ true, \ + /*fDoPP16_V86*/ true, \ + /*fDoPP32*/ true, \ + /*fDoPP32_16*/ true, \ + /*fDoPPV86*/ true, \ + /*fDoPAE16*/ true, \ + /*fDoPAE16_32*/ true, \ + /*fDoPAE16_V86*/ true, \ + /*fDoPAE32*/ true, \ + /*fDoPAE32_16*/ true, \ + /*fDoPAEV86*/ true, \ + /*fDoLM16*/ true, \ + /*fDoLM32*/ true, \ + /*fDoLM64*/ true, \ + } + +/** @def BS3TESTMODEBYMAX_PROTOTYPES_CMN + * A set of standard protypes to go with #BS3TESTMODEBYMAXENTRY_CMN. */ +#define BS3TESTMODEBYMAX_PROTOTYPES_CMN(a_BaseNm) \ + FNBS3TESTDOMODE /*BS3_FAR_CODE*/ RT_CONCAT(a_BaseNm, _c16); \ + FNBS3TESTDOMODE /*BS3_FAR_CODE*/ RT_CONCAT(a_BaseNm, _c32); \ + FNBS3TESTDOMODE /*BS3_FAR_CODE*/ RT_CONCAT(a_BaseNm, _c64) + + +/** @def BS3TESTMODEBYMAXENTRY_MODE + * Produces a BS3TESTMODEBYMAXENTRY initializer for a full set of mode test + * functions. */ +#define BS3TESTMODEBYMAXENTRY_MODE(a_szTest, a_BaseNm) \ + { /*pszSubTest =*/ a_szTest, \ + /*RM*/ RT_CONCAT(a_BaseNm, _rm), \ + /*PE16*/ RT_CONCAT(a_BaseNm, _pe16), \ + /*PE16_32*/ RT_CONCAT(a_BaseNm, _pe16_32), \ + /*PE32*/ RT_CONCAT(a_BaseNm, _pe32), \ + /*PP16_32*/ RT_CONCAT(a_BaseNm, _pp16_32), \ + /*PP32*/ RT_CONCAT(a_BaseNm, _pp32), \ + /*PAE16_32*/ RT_CONCAT(a_BaseNm, _pae16_32), \ + /*PAE32*/ RT_CONCAT(a_BaseNm, _pae32), \ + /*LM64*/ RT_CONCAT(a_BaseNm, _lm64), \ + /*fDoRM*/ true, \ + /*fDoPE16*/ true, \ + /*fDoPE16_32*/ true, \ + /*fDoPE16_V86*/ true, \ + /*fDoPE32*/ true, \ + /*fDoPE32_16*/ true, \ + /*fDoPEV86*/ true, \ + /*fDoPP16*/ true, \ + /*fDoPP16_32*/ true, \ + /*fDoPP16_V86*/ true, \ + /*fDoPP32*/ true, \ + /*fDoPP32_16*/ true, \ + /*fDoPPV86*/ true, \ + /*fDoPAE16*/ true, \ + /*fDoPAE16_32*/ true, \ + /*fDoPAE16_V86*/ true, \ + /*fDoPAE32*/ true, \ + /*fDoPAE32_16*/ true, \ + /*fDoPAEV86*/ true, \ + /*fDoLM16*/ true, \ + /*fDoLM32*/ true, \ + /*fDoLM64*/ true, \ + } + +/** @def BS3TESTMODEBYMAX_PROTOTYPES_MODE + * A set of standard protypes to go with #BS3TESTMODEBYMAXENTRY_MODE. */ +#define BS3TESTMODEBYMAX_PROTOTYPES_MODE(a_BaseNm) \ + FNBS3TESTDOMODE RT_CONCAT(a_BaseNm, _rm); \ + FNBS3TESTDOMODE RT_CONCAT(a_BaseNm, _pe16); \ + FNBS3TESTDOMODE RT_CONCAT(a_BaseNm, _pe16_32); \ + FNBS3TESTDOMODE RT_CONCAT(a_BaseNm, _pe32); \ + FNBS3TESTDOMODE RT_CONCAT(a_BaseNm, _pp16_32); \ + FNBS3TESTDOMODE RT_CONCAT(a_BaseNm, _pp32); \ + FNBS3TESTDOMODE RT_CONCAT(a_BaseNm, _pae16_32); \ + FNBS3TESTDOMODE RT_CONCAT(a_BaseNm, _pae32); \ + FNBS3TESTDOMODE RT_CONCAT(a_BaseNm, _lm64) + + +/** + * One worker drives all modes. + * + * This is an alternative to BS3TESTMODEENTRY where one worker, typically + * 16-bit, does all the test driver work. It's called repeatedly from all + * the modes being tested. + */ +typedef struct BS3TESTMODEBYONEENTRY +{ + const char * BS3_FAR pszSubTest; + PFNBS3TESTDOMODE pfnWorker; + /** BS3TESTMODEBYONEENTRY_F_XXX. */ + uint32_t fFlags; +} BS3TESTMODEBYONEENTRY; +/** Pointer to a mode-by-one sub-test entry. */ +typedef BS3TESTMODEBYONEENTRY const *PCBS3TESTMODEBYONEENTRY; + +/** @name BS3TESTMODEBYONEENTRY_F_XXX - flags. + * @{ */ +/** Only test modes that has paging enabled. */ +#define BS3TESTMODEBYONEENTRY_F_ONLY_PAGING RT_BIT_32(0) +/** @} */ + + +/** + * Sets the full GDTR register. + * + * @param cbLimit The limit. + * @param uBase The base address - 24, 32 or 64 bit depending on the + * CPU mode. + */ +BS3_CMN_PROTO_NOSB(void, Bs3UtilSetFullGdtr,(uint16_t cbLimit, uint64_t uBase)); + +/** + * Sets the full IDTR register. + * + * @param cbLimit The limit. + * @param uBase The base address - 24, 32 or 64 bit depending on the + * CPU mode. + */ +BS3_CMN_PROTO_NOSB(void, Bs3UtilSetFullIdtr,(uint16_t cbLimit, uint64_t uBase)); + + +/** @} */ + + +/** + * Initializes all of boot sector kit \#3. + */ +BS3_DECL(void) Bs3InitAll_rm(void); + +/** + * Initializes the REAL and TILED memory pools. + * + * For proper operation on OLDer CPUs, call #Bs3CpuDetect_mmm first. + */ +BS3_DECL_FAR(void) Bs3InitMemory_rm_far(void); + +/** + * Initialized the X0TEXT16 and X1TEXT16 GDT entries. + */ +BS3_DECL_FAR(void) Bs3InitGdt_rm_far(void); + + + +/** @defgroup grp_bs3kit_mode Mode Specific Functions and Data + * + * The mode specific functions come in bit count variations and CPU mode + * variations. The bs3kit-template-header.h/mac defines the BS3_NM macro to + * mangle a function or variable name according to the target CPU mode. In + * non-templated code, it's common to spell the name out in full. + * + * @{ + */ + + +/** @def BS3_MODE_PROTO_INT + * Internal macro for emitting prototypes for mode functions. + * + * @param a_RetType The return type. + * @param a_Name The function basename. + * @param a_Params The parameter list (in parentheses). + * @sa BS3_MODE_PROTO_STUB, BS3_MODE_PROTO_NOSB + */ +#define BS3_MODE_PROTO_INT(a_RetType, a_Name, a_Params) \ + BS3_DECL_NEAR(a_RetType) RT_CONCAT(a_Name,_rm) a_Params; \ + BS3_DECL_NEAR(a_RetType) RT_CONCAT(a_Name,_pe16) a_Params; \ + BS3_DECL_NEAR(a_RetType) RT_CONCAT(a_Name,_pe16_32) a_Params; \ + BS3_DECL_NEAR(a_RetType) RT_CONCAT(a_Name,_pe16_v86) a_Params; \ + BS3_DECL_NEAR(a_RetType) RT_CONCAT(a_Name,_pe32) a_Params; \ + BS3_DECL_NEAR(a_RetType) RT_CONCAT(a_Name,_pe32_16) a_Params; \ + BS3_DECL_NEAR(a_RetType) RT_CONCAT(a_Name,_pev86) a_Params; \ + BS3_DECL_NEAR(a_RetType) RT_CONCAT(a_Name,_pp16) a_Params; \ + BS3_DECL_NEAR(a_RetType) RT_CONCAT(a_Name,_pp16_32) a_Params; \ + BS3_DECL_NEAR(a_RetType) RT_CONCAT(a_Name,_pp16_v86) a_Params; \ + BS3_DECL_NEAR(a_RetType) RT_CONCAT(a_Name,_pp32) a_Params; \ + BS3_DECL_NEAR(a_RetType) RT_CONCAT(a_Name,_pp32_16) a_Params; \ + BS3_DECL_NEAR(a_RetType) RT_CONCAT(a_Name,_ppv86) a_Params; \ + BS3_DECL_NEAR(a_RetType) RT_CONCAT(a_Name,_pae16) a_Params; \ + BS3_DECL_NEAR(a_RetType) RT_CONCAT(a_Name,_pae16_32) a_Params; \ + BS3_DECL_NEAR(a_RetType) RT_CONCAT(a_Name,_pae16_v86) a_Params; \ + BS3_DECL_NEAR(a_RetType) RT_CONCAT(a_Name,_pae32) a_Params; \ + BS3_DECL_NEAR(a_RetType) RT_CONCAT(a_Name,_pae32_16) a_Params; \ + BS3_DECL_NEAR(a_RetType) RT_CONCAT(a_Name,_paev86) a_Params; \ + BS3_DECL_NEAR(a_RetType) RT_CONCAT(a_Name,_lm16) a_Params; \ + BS3_DECL_NEAR(a_RetType) RT_CONCAT(a_Name,_lm32) a_Params; \ + BS3_DECL_NEAR(a_RetType) RT_CONCAT(a_Name,_lm64) a_Params; \ + BS3_DECL_FAR(a_RetType) RT_CONCAT(a_Name,_rm_far) a_Params; \ + BS3_DECL_FAR(a_RetType) RT_CONCAT(a_Name,_pe16_far) a_Params; \ + BS3_DECL_FAR(a_RetType) RT_CONCAT(a_Name,_pe16_v86_far) a_Params; \ + BS3_DECL_FAR(a_RetType) RT_CONCAT(a_Name,_pe32_16_far) a_Params; \ + BS3_DECL_FAR(a_RetType) RT_CONCAT(a_Name,_pev86_far) a_Params; \ + BS3_DECL_FAR(a_RetType) RT_CONCAT(a_Name,_pp16_far) a_Params; \ + BS3_DECL_FAR(a_RetType) RT_CONCAT(a_Name,_pp16_v86_far) a_Params; \ + BS3_DECL_FAR(a_RetType) RT_CONCAT(a_Name,_pp32_16_far) a_Params; \ + BS3_DECL_FAR(a_RetType) RT_CONCAT(a_Name,_ppv86_far) a_Params; \ + BS3_DECL_FAR(a_RetType) RT_CONCAT(a_Name,_pae16_far) a_Params; \ + BS3_DECL_FAR(a_RetType) RT_CONCAT(a_Name,_pae16_v86_far)a_Params; \ + BS3_DECL_FAR(a_RetType) RT_CONCAT(a_Name,_pae32_16_far) a_Params; \ + BS3_DECL_FAR(a_RetType) RT_CONCAT(a_Name,_paev86_far) a_Params; \ + BS3_DECL_FAR(a_RetType) RT_CONCAT(a_Name,_lm16_far) a_Params + +/** @def BS3_MODE_PROTO_STUB + * Macro for prototyping all the variations of a mod function with automatic + * near -> far stub. + * + * @param a_RetType The return type. + * @param a_Name The function basename. + * @param a_Params The parameter list (in parentheses). + * @sa BS3_MODE_PROTO_STUB, BS3_MODE_PROTO_NOSB + */ +#define BS3_MODE_PROTO_STUB(a_RetType, a_Name, a_Params) BS3_MODE_PROTO_INT(a_RetType, a_Name, a_Params) + +/** @def BS3_MODE_PROTO_STUB + * Macro for prototyping all the variations of a mod function without any + * near -> far stub. + * + * @param a_RetType The return type. + * @param a_Name The function basename. + * @param a_Params The parameter list (in parentheses). + * @sa BS3_MODE_PROTO_STUB, BS3_MODE_PROTO_NOSB + */ +#define BS3_MODE_PROTO_NOSB(a_RetType, a_Name, a_Params) BS3_MODE_PROTO_INT(a_RetType, a_Name, a_Params) + + +/** + * Macro for reducing typing. + * + * Doxygen knows how to expand this, well, kind of. + * + * @remarks Variables instantiated in assembly code should define two labels, + * with and without leading underscore. Variables instantiated from + * C/C++ code doesn't need to as the object file convert does this for + * 64-bit object files. + */ +#define BS3_MODE_EXPAND_EXTERN_DATA16(a_VarType, a_VarName, a_Suffix) \ + extern a_VarType BS3_FAR_DATA RT_CONCAT(a_VarName,_rm) a_Suffix; \ + extern a_VarType BS3_FAR_DATA RT_CONCAT(a_VarName,_pe16) a_Suffix; \ + extern a_VarType BS3_FAR_DATA RT_CONCAT(a_VarName,_pe16_32) a_Suffix; \ + extern a_VarType BS3_FAR_DATA RT_CONCAT(a_VarName,_pe16_v86) a_Suffix; \ + extern a_VarType BS3_FAR_DATA RT_CONCAT(a_VarName,_pe32) a_Suffix; \ + extern a_VarType BS3_FAR_DATA RT_CONCAT(a_VarName,_pe32_16) a_Suffix; \ + extern a_VarType BS3_FAR_DATA RT_CONCAT(a_VarName,_pev86) a_Suffix; \ + extern a_VarType BS3_FAR_DATA RT_CONCAT(a_VarName,_pp16) a_Suffix; \ + extern a_VarType BS3_FAR_DATA RT_CONCAT(a_VarName,_pp16_32) a_Suffix; \ + extern a_VarType BS3_FAR_DATA RT_CONCAT(a_VarName,_pp16_v86) a_Suffix; \ + extern a_VarType BS3_FAR_DATA RT_CONCAT(a_VarName,_pp32) a_Suffix; \ + extern a_VarType BS3_FAR_DATA RT_CONCAT(a_VarName,_pp32_16) a_Suffix; \ + extern a_VarType BS3_FAR_DATA RT_CONCAT(a_VarName,_ppv86) a_Suffix; \ + extern a_VarType BS3_FAR_DATA RT_CONCAT(a_VarName,_pae16) a_Suffix; \ + extern a_VarType BS3_FAR_DATA RT_CONCAT(a_VarName,_pae16_32) a_Suffix; \ + extern a_VarType BS3_FAR_DATA RT_CONCAT(a_VarName,_pae16_v86)a_Suffix; \ + extern a_VarType BS3_FAR_DATA RT_CONCAT(a_VarName,_pae32) a_Suffix; \ + extern a_VarType BS3_FAR_DATA RT_CONCAT(a_VarName,_pae32_16) a_Suffix; \ + extern a_VarType BS3_FAR_DATA RT_CONCAT(a_VarName,_paev86) a_Suffix; \ + extern a_VarType BS3_FAR_DATA RT_CONCAT(a_VarName,_lm16) a_Suffix; \ + extern a_VarType BS3_FAR_DATA RT_CONCAT(a_VarName,_lm32) a_Suffix; \ + extern a_VarType BS3_FAR_DATA RT_CONCAT(a_VarName,_lm64) a_Suffix + + +/** The TMPL_MODE_STR value for each mode. + * These are all in DATA16 so they can be accessed from any code. */ +BS3_MODE_EXPAND_EXTERN_DATA16(const char, g_szBs3ModeName, []); +/** The TMPL_MODE_LNAME value for each mode. + * These are all in DATA16 so they can be accessed from any code. */ +BS3_MODE_EXPAND_EXTERN_DATA16(const char, g_szBs3ModeNameShortLower, []); + + +/** + * Basic CPU detection. + * + * This sets the #g_uBs3CpuDetected global variable to the return value. + * + * @returns BS3CPU_XXX value with the BS3CPU_F_CPUID flag set depending on + * capabilities. + */ +BS3_MODE_PROTO_NOSB(uint8_t, Bs3CpuDetect,(void)); + +/** @name BS3CPU_XXX - CPU detected by BS3CpuDetect_c16() and friends. + * @{ */ +#define BS3CPU_8086 UINT16_C(0x0001) /**< Both 8086 and 8088. */ +#define BS3CPU_V20 UINT16_C(0x0002) /**< Both NEC V20, V30 and relatives. */ +#define BS3CPU_80186 UINT16_C(0x0003) /**< Both 80186 and 80188. */ +#define BS3CPU_80286 UINT16_C(0x0004) +#define BS3CPU_80386 UINT16_C(0x0005) +#define BS3CPU_80486 UINT16_C(0x0006) +#define BS3CPU_Pentium UINT16_C(0x0007) +#define BS3CPU_PPro UINT16_C(0x0008) +#define BS3CPU_PProOrNewer UINT16_C(0x0009) +/** CPU type mask. This is a full byte so it's possible to use byte access + * without and AND'ing to get the type value. */ +#define BS3CPU_TYPE_MASK UINT16_C(0x00ff) +/** Flag indicating that the CPUID instruction is supported by the CPU. */ +#define BS3CPU_F_CPUID UINT16_C(0x0100) +/** Flag indicating that extend CPUID leaves are available (at least two). */ +#define BS3CPU_F_CPUID_EXT_LEAVES UINT16_C(0x0200) +/** Flag indicating that the CPU supports PAE. */ +#define BS3CPU_F_PAE UINT16_C(0x0400) +/** Flag indicating that the CPU supports the page size extension (4MB pages). */ +#define BS3CPU_F_PSE UINT16_C(0x0800) +/** Flag indicating that the CPU supports long mode. */ +#define BS3CPU_F_LONG_MODE UINT16_C(0x1000) +/** Flag indicating that the CPU supports NX. */ +#define BS3CPU_F_NX UINT16_C(0x2000) +/** @} */ + +/** The return value of #Bs3CpuDetect_mmm. (Initial value is BS3CPU_TYPE_MASK.) */ +extern uint16_t g_uBs3CpuDetected; + +/** + * Call 32-bit prot mode C function. + * + * This switches to 32-bit mode and calls the 32-bit @a fpfnCall C code with @a + * cbParams on the stack, then returns in the original mode. When called in + * real mode, this will switch to PE32. + * + * @returns 32-bit status code if the function returned anything. + * @param fpfnCall Address of the 32-bit C function to call. When + * called from 16-bit code, this is a far real mode + * function pointer, i.e. as fixed up by the linker. + * In 32-bit and 64-bit code, this is a flat address. + * @param cbParams The size of the parameter list, in bytes. + * @param ... The parameters. + * @sa Bs3SwitchFromV86To16BitAndCallC + * + * @remarks WARNING! This probably doesn't work in 64-bit mode yet. + * Only tested for 16-bit real mode. + */ +BS3_MODE_PROTO_STUB(int32_t, Bs3SwitchTo32BitAndCallC,(FPFNBS3FAR fpfnCall, unsigned cbParams, ...)); + +/** + * Initializes trap handling for the current system. + * + * Calls the appropriate Bs3Trap16Init, Bs3Trap32Init or Bs3Trap64Init function. + */ +BS3_MODE_PROTO_STUB(void, Bs3TrapInit,(void)); + +/** + * Executes the array of tests in every possibly mode. + * + * @param paEntries The mode sub-test entries. + * @param cEntries The number of sub-test entries. + */ +BS3_MODE_PROTO_NOSB(void, Bs3TestDoModes,(PCBS3TESTMODEENTRY paEntries, size_t cEntries)); + +/** + * Executes the array of tests in every possibly mode, unified driver. + * + * This requires much less code space than Bs3TestDoModes as there is only one + * instace of each sub-test driver code, instead of 3 (cmn) or 22 (per-mode) + * copies. + * + * @param paEntries The mode sub-test-by-one entries. + * @param cEntries The number of sub-test-by-one entries. + * @param fFlags Reserved for the future, MBZ. + */ +BS3_MODE_PROTO_NOSB(void, Bs3TestDoModesByOne,(PCBS3TESTMODEBYONEENTRY paEntries, size_t cEntries, uint32_t fFlags)); + +/** + * Executes the array of tests in every possibly mode, using the max bit-count + * worker for each. + * + * @param paEntries The mode sub-test entries. + * @param cEntries The number of sub-test entries. + */ +BS3_MODE_PROTO_NOSB(void, Bs3TestDoModesByMax,(PCBS3TESTMODEBYMAXENTRY paEntries, size_t cEntries)); + + +/** @} */ + +/** @} */ + +RT_C_DECLS_END + + +/* + * Include default function symbol mangling. + */ +#include "bs3kit-mangling-code.h" + +/* + * Change 16-bit text segment if requested. + */ +#if defined(BS3_USE_ALT_16BIT_TEXT_SEG) && ARCH_BITS == 16 && !defined(BS3_DONT_CHANGE_TEXT_SEG) +# if (defined(BS3_USE_RM_TEXT_SEG) + defined(BS3_USE_X0_TEXT_SEG) + defined(BS3_USE_X1_TEXT_SEG)) != 1 +# error "Cannot set more than one alternative 16-bit text segment!" +# elif defined(BS3_USE_RM_TEXT_SEG) +# pragma code_seg("BS3RMTEXT16", "BS3CLASS16RMCODE") +# elif defined(BS3_USE_X0_TEXT_SEG) +# pragma code_seg("BS3X0TEXT16", "BS3CLASS16X0CODE") +# elif defined(BS3_USE_X1_TEXT_SEG) +# pragma code_seg("BS3X1TEXT16", "BS3CLASS16X1CODE") +# else +# error "Huh? Which alternative text segment did you want again?" +# endif +#endif + +#endif /* !BS3KIT_INCLUDED_bs3kit_h */ + diff --git a/src/VBox/ValidationKit/bootsectors/bs3kit/bs3kit.mac b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3kit.mac new file mode 100644 index 00000000..1d5baeb1 --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/bs3kit/bs3kit.mac @@ -0,0 +1,1750 @@ +; $Id: bs3kit.mac $ +;; @file +; BS3Kit - structures, symbols, macros and stuff. +; + +; +; Copyright (C) 2007-2019 Oracle Corporation +; +; This file is part of VirtualBox Open Source Edition (OSE), as +; available from http://www.virtualbox.org. This file is free software; +; you can redistribute it and/or modify it under the terms of the GNU +; General Public License (GPL) as published by the Free Software +; Foundation, in version 2 as it comes in the "COPYING" file of the +; VirtualBox OSE distribution. VirtualBox OSE is distributed in the +; hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL) only, as it comes in the "COPYING.CDDL" file of the +; VirtualBox OSE distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; + +%ifndef ___bs3kit_mac___ +%define ___bs3kit_mac___ + +; +; Before we can include anything, we need to override NAME and switch section. +; If we don't do the latter we end up with an unused 'text' section. +; + +; Drop the asmdefs-first.mac header for native bs3kit files. +%undef RT_ASMDEFS_INC_FIRST_FILE + +;; +; Macro for setting register aliases according to the bit count given by %1. +; +%macro BS3_SET_REG_ALIASES 1 + ; + ; Register aliases. + ; + %if %1 == 64 + %define xCB 8 + %define xDEF dq + %define xRES resq + %define xPRE qword + %define xSP rsp + %define xBP rbp + %define xAX rax + %define xBX rbx + %define xCX rcx + %define xDX rdx + %define xDI rdi + %define xSI rsi + %define xWrtRIP wrt rip + %define xPUSHF pushfq + %define xPOPF popfq + %define xRETF o64 retf + %elif %1 == 32 + %define xCB 4 + %define xDEF dd + %define xRES resd + %define xPRE dword + %define xSP esp + %define xBP ebp + %define xAX eax + %define xBX ebx + %define xCX ecx + %define xDX edx + %define xDI edi + %define xSI esi + %define xWrtRIP + %define xPUSHF pushfd + %define xPOPF popfd + %define xRETF retf + %elif %1 == 16 + %define xCB 2 + %define xDEF dw + %define xRES resw + %define xPRE word + %define xSP sp + %define xBP bp + %define xAX ax + %define xBX bx + %define xCX cx + %define xDX dx + %define xDI di + %define xSI si + %define xWrtRIP + %define xPUSHF pushf + %define xPOPF popf + %define xRETF retf + %else + %error "Invalid BS3_SET_REG_ALIASES argument:" %1 + %endif + + + ; + ; Register names corresponding to the max size for pop/push <reg>. + ; + ; 16-bit can push both 32-bit and 16-bit registers. This 's' prefixed variant + ; is used when 16-bit should use the 32-bit register. + ; + %if %1 == 64 + %define sCB 8 + %define sDEF dq + %define sRES resq + %define sPRE qword + %define sSP rsp + %define sBP rbp + %define sAX rax + %define sBX rbx + %define sCX rcx + %define sDX rdx + %define sDI rdi + %define sSI rsi + %define sPUSHF pushfq + %define sPOPF popfq + %else + %define sCB 4 + %define sDEF dd + %define sRES resd + %define sPRE dword + %define sSP esp + %define sBP ebp + %define sAX eax + %define sBX ebx + %define sCX ecx + %define sDX edx + %define sDI edi + %define sSI esi + %define sPUSHF pushfd + %define sPOPF popfd + %endif +%endmacro + +;; +; Redefines macros that follows __BITS__. +%macro BS3_SET_BITS_MACROS 1 + ;; Emulate the __BITS__ macro in NASM 2.0+. Follows BS3_SET_BITS. + %ifdef __YASM__ + %undef __BITS__ + %define __BITS__ %1 + %endif + + ;; Mostly internal macro. Follows BS3_SET_BITS. + %undef BS3_NAME_UNDERSCORE + %define BS3_NAME_UNDERSCORE _ + + ;; For segment overrides and stuff. Follows BS3_SET_BITS. + %undef BS3_ONLY_16BIT + %if %1 == 16 + %define BS3_ONLY_16BIT(a_Expr) a_Expr + %else + %define BS3_ONLY_16BIT(a_Expr) + %endif + + ;; For odd 64-bit stuff. Follows BS3_SET_BITS. + %undef BS3_ONLY_64BIT + %if %1 == 64 + %define BS3_ONLY_64BIT(a_Expr) a_Expr + %else + %define BS3_ONLY_64BIT(a_Expr) + %endif + + ;; For segment overrides and stuff. Follows BS3_SET_BITS. + %undef BS3_NOT_64BIT + %if %1 == 64 + %define BS3_NOT_64BIT(a_Expr) + %else + %define BS3_NOT_64BIT(a_Expr) a_Expr + %endif + + ;; For stack cleanups and similar where each bit mode is different. Follows BS3_SET_BITS. + %undef BS3_IF_16_32_64BIT + %if %1 == 16 + %define BS3_IF_16_32_64BIT(a_16BitExpr, a_32BitExpr, a_64BitExpr) a_16BitExpr + %elif %1 == 32 + %define BS3_IF_16_32_64BIT(a_16BitExpr, a_32BitExpr, a_64BitExpr) a_32BitExpr + %else + %define BS3_IF_16_32_64BIT(a_16BitExpr, a_32BitExpr, a_64BitExpr) a_64BitExpr + %endif + + ;; For RIP relative addressing in 64-bit mode and absolute addressing in + ; other modes. Follows BS3_SET_BITS. + %undef BS3_WRT_RIP + %if %1 == 64 + %define BS3_WRT_RIP(a_Sym) rel a_Sym + %else + %define BS3_WRT_RIP(a_Sym) a_Sym + %endif + + %undef BS3_LEA_MOV_WRT_RIP + %if %1 == 64 + %define BS3_LEA_MOV_WRT_RIP(a_DstReg, a_Sym) lea a_DstReg, [BS3_WRT_RIP(a_Sym)] + %else + %define BS3_LEA_MOV_WRT_RIP(a_DstReg, a_Sym) mov a_DstReg, a_Sym + %endif + + ;; @def BS3_DATA16_WRT + ; For accessing BS3DATA16 correctly. + ; @param a_Var The BS3DATA16 variable. + %undef BS3_DATA16_WRT + %if %1 == 16 + %define BS3_DATA16_WRT(a_Var) a_Var wrt BS3KIT_GRPNM_DATA16 + %elif %1 == 32 + %define BS3_DATA16_WRT(a_Var) a_Var wrt FLAT + %else + %define BS3_DATA16_WRT(a_Var) BS3_WRT_RIP(a_Var) wrt FLAT + %endif + + ;; @def BS3_TEXT16_WRT + ; For accessing BS3DATA16 correctly. + ; @param a_Label The BS3TEXT16 label. + %undef BS3_TEXT16_WRT + %if %1 == 16 + %define BS3_TEXT16_WRT(a_Label) a_Label wrt CGROUP16 + %elif %1 == 32 + %define BS3_TEXT16_WRT(a_Label) a_Label wrt FLAT + %else + %define BS3_TEXT16_WRT(a_Label) BS3_WRT_RIP(a_Label) wrt FLAT + %endif + + %undef BS3_IF_16BIT_OTHERWISE + %if %1 == 16 + %define BS3_IF_16BIT_OTHERWISE(a_16BitExpr, a_OtherwiseExpr) a_16BitExpr + %else + %define BS3_IF_16BIT_OTHERWISE(a_16BitExpr, a_OtherwiseExpr) a_OtherwiseExpr + %endif + + %undef BS3_IF_32BIT_OTHERWISE + %if %1 == 32 + %define BS3_IF_32BIT_OTHERWISE(a_32BitExpr, a_OtherwiseExpr) a_32BitExpr + %else + %define BS3_IF_32BIT_OTHERWISE(a_32BitExpr, a_OtherwiseExpr) a_OtherwiseExpr + %endif + + %undef BS3_IF_64BIT_OTHERWISE + %if %1 == 64 + %define BS3_IF_64BIT_OTHERWISE(a_64BitExpr, a_OtherwiseExpr) a_64BitExpr + %else + %define BS3_IF_64BIT_OTHERWISE(a_64BitExpr, a_OtherwiseExpr) a_OtherwiseExpr + %endif + + ;; + ; Same as BS3_CMN_NM except in 16-bit mode, it will generate the far name. + ; (16-bit code generally have both near and far callable symbols, so we won't + ; be restricted to 64KB test code.) + %if %1 == 16 + %define BS3_CMN_NM_FAR(a_Name) BS3_NAME_UNDERSCORE %+ a_Name %+ _f %+ __BITS__ + %else + %define BS3_CMN_NM_FAR(a_Name) BS3_CMN_NM(a_Name) + %endif + +%endmacro + +; Default to register aliases for ARCH_BITS. +BS3_SET_REG_ALIASES ARCH_BITS + +; Define macros for ARCH_BITS. +BS3_SET_BITS_MACROS ARCH_BITS + + +;; Wrapper around BITS. +; Updates __BITS__ (built-in variable in nasm, we work it for yasm) as well +; a number of convenient macros and register aliases. +; +; @param %1 The CPU bit count: 16, 32 or 64 +; @remarks ARCH_BITS is not modified and will remain what it was on the +; assembler command line. +%macro BS3_SET_BITS 1 + BITS %1 + BS3_SET_BITS_MACROS %1 + BS3_SET_REG_ALIASES %1 +%endmacro + +;; +; For instruction that should only be emitted in 16-bit mode. Follows BS3_SET_BITS. +; BONLY16 normally goes in column 1. +%macro BONLY16 1+ + %if __BITS__ == 16 + %1 + %endif +%endmacro + +;; +; For instruction that should only be emitted in 32-bit mode. Follows BS3_SET_BITS. +; BONLY32 normally goes in column 1. +%macro BONLY32 1+ + %if __BITS__ == 32 + %1 + %endif +%endmacro + +;; +; For instruction that should only be emitted in 64-bit mode. Follows BS3_SET_BITS. +; BONLY64 normally goes in column 1. +%macro BONLY64 1+ + %if __BITS__ == 64 + %1 + %endif +%endmacro + + + +;; @name Segment definitions. +;; @{ + +%ifndef ASM_FORMAT_BIN +; !!HACK ALERT!! +; +; To make FLAT actually be flat, i.e. have a base of 0 rather than the same as +; the target (?) segment, we tweak it a little bit here. We associate a segment +; with it so that we can get at it in the class/segment ordering directives +; we pass to the linker. The segment does not contain any data or anything, it +; is just an empty one which we assign the address of zero. +; +; Look for 'clname BS3FLAT segaddr=0x0000' and 'segment BS3FLAT segaddr=0x0000' +; in the makefile. +; +; !!HACK ALERT!! +segment BS3FLAT use32 class=BS3FLAT +GROUP FLAT BS3FLAT +%endif + + +%macro BS3_BEGIN_TEXT16 0-1 2 + %ifndef BS3_BEGIN_TEXT16_NOT_FIRST + %define BS3_BEGIN_TEXT16_NOT_FIRST + section BS3TEXT16 align=%1 CLASS=BS3CLASS16CODE PUBLIC USE16 + %ifndef BS3_BEGIN_TEXT16_WITHOUT_GROUP ; bs3-first-common.mac trick. + %ifndef BS3_BEGIN_TEXT16_NEARSTUBS_NOT_FIRST + %define BS3_BEGIN_TEXT16_NEARSTUBS_NOT_FIRST + section BS3TEXT16_NEARSTUBS align=1 CLASS=BS3CLASS16CODE PUBLIC USE16 + %endif + %ifndef BS3_BEGIN_TEXT16_FARSTUBS_NOT_FIRST + %define BS3_BEGIN_TEXT16_FARSTUBS_NOT_FIRST + section BS3TEXT16_FARSTUBS align=1 CLASS=BS3CLASS16CODE PUBLIC USE16 + %endif + GROUP CGROUP16 BS3TEXT16 BS3TEXT16_NEARSTUBS BS3TEXT16_FARSTUBS + section BS3TEXT16 + %endif + %else + section BS3TEXT16 + %endif + %undef BS3_CUR_SEG_BEGIN_MACRO + %xdefine BS3_CUR_SEG_BEGIN_MACRO BS3_BEGIN_TEXT16 + BS3_SET_BITS 16 +%endmacro + +%macro BS3_BEGIN_TEXT16_NEARSTUBS 0 + %ifndef BS3_BEGIN_TEXT16_NEARSTUBS_NOT_FIRST + %define BS3_BEGIN_TEXT16_NEARSTUBS_NOT_FIRST + section BS3TEXT16_NEARSTUBS align=1 CLASS=BS3CLASS16CODE PUBLIC USE16 + %else + section BS3TEXT16_NEARSTUBS + %endif + %undef BS3_CUR_SEG_BEGIN_MACRO + %xdefine BS3_CUR_SEG_BEGIN_MACRO BS3_BEGIN_TEXT16_NEARSTUBS + BS3_SET_BITS 16 +%endmacro + +%macro BS3_BEGIN_TEXT16_FARSTUBS 0 + %ifndef BS3_BEGIN_TEXT16_FARSTUBS_NOT_FIRST + %define BS3_BEGIN_TEXT16_FARSTUBS_NOT_FIRST + section BS3TEXT16_FARSTUBS align=1 CLASS=BS3CLASS16CODE PUBLIC USE16 + %else + section BS3TEXT16_FARSTUBS + %endif + %undef BS3_CUR_SEG_BEGIN_MACRO + %xdefine BS3_CUR_SEG_BEGIN_MACRO BS3_BEGIN_TEXT16_FARSTUBS + BS3_SET_BITS 16 +%endmacro + +%macro BS3_BEGIN_RMTEXT16 0-1 2 + %ifndef BS3_BEGIN_RMTEXT16_NOT_FIRST + %define BS3_BEGIN_RMTEXT16_NOT_FIRST + section BS3RMTEXT16 align=%1 CLASS=BS3CLASS16RMCODE PUBLIC USE16 + %ifndef BS3_BEGIN_RMTEXT16_WITHOUT_GROUP ; bs3-first-common.mac trick. + GROUP BS3GROUPRMTEXT16 BS3RMTEXT16 + %endif + %else + section BS3RMTEXT16 + %endif + %undef BS3_CUR_SEG_BEGIN_MACRO + %xdefine BS3_CUR_SEG_BEGIN_MACRO BS3_BEGIN_RMTEXT16 + BS3_SET_BITS 16 +%endmacro + +%macro BS3_BEGIN_X0TEXT16 0-1 2 + %ifndef BS3_BEGIN_X0TEXT16_NOT_FIRST + %define BS3_BEGIN_X0TEXT16_NOT_FIRST + section BS3X0TEXT16 align=%1 CLASS=BS3CLASS16X0CODE PUBLIC USE16 + %ifndef BS3_BEGIN_X0TEXT16_WITHOUT_GROUP ; bs3-first-common.mac trick. + GROUP BS3GROUPX0TEXT16 BS3X0TEXT16 + %endif + %else + section BS3X0TEXT16 + %endif + %undef BS3_CUR_SEG_BEGIN_MACRO + %xdefine BS3_CUR_SEG_BEGIN_MACRO BS3_BEGIN_X0TEXT16 + BS3_SET_BITS 16 +%endmacro + +%macro BS3_BEGIN_X1TEXT16 0-1 2 + %ifndef BS3_BEGIN_X1TEXT16_NOT_FIRST + %define BS3_BEGIN_X1TEXT16_NOT_FIRST + section BS3X1TEXT16 align=%1 CLASS=BS3CLASS16X1CODE PUBLIC USE16 + %ifndef BS3_BEGIN_X1TEXT16_WITHOUT_GROUP ; bs3-first-common.mac trick. + GROUP BS3GROUPX1TEXT16 BS3X1TEXT16 + %endif + %else + section BS3X1TEXT16 + %endif + %undef BS3_CUR_SEG_BEGIN_MACRO + %xdefine BS3_CUR_SEG_BEGIN_MACRO BS3_BEGIN_X1TEXT16 + BS3_SET_BITS 16 +%endmacro + + +%macro BS3_BEGIN_DATA16 0-1 2 + %ifndef BS3_BEGIN_DATA16_NOT_FIRST + %define BS3_BEGIN_DATA16_NOT_FIRST + section BS3DATA16 align=%1 CLASS=BS3KIT_CLASS_DATA16 PUBLIC USE16 + %ifndef BS3_BEGIN_DATA16_WITHOUT_GROUP ; bs3-first-common.mac trick. + GROUP BS3KIT_GRPNM_DATA16 BS3DATA16 + %endif + %else + section BS3DATA16 + %endif + %undef BS3_CUR_SEG_BEGIN_MACRO + %xdefine BS3_CUR_SEG_BEGIN_MACRO BS3_BEGIN_DATA16 + BS3_SET_BITS 16 +%endmacro + +%macro BS3_BEGIN_TEXT32 0-1 2 + %ifndef BS3_BEGIN_TEXT32_NOT_FIRST + %define BS3_BEGIN_TEXT32_NOT_FIRST + section BS3TEXT32 align=%1 CLASS=BS3CLASS32CODE PUBLIC USE32 FLAT + %else + section BS3TEXT32 + %endif + %undef BS3_CUR_SEG_BEGIN_MACRO + %xdefine BS3_CUR_SEG_BEGIN_MACRO BS3_BEGIN_TEXT32 + BS3_SET_BITS 32 +%endmacro + +%macro BS3_BEGIN_DATA32 0-1 16 + %ifndef BS3_BEGIN_DATA32_NOT_FIRST + %define BS3_BEGIN_DATA32_NOT_FIRST + section BS3DATA32 align=%1 CLASS=FAR_DATA PUBLIC USE32 ;FLAT - compiler doesn't make data flat. + %else + section BS3DATA32 + %endif + %undef BS3_CUR_SEG_BEGIN_MACRO + %xdefine BS3_CUR_SEG_BEGIN_MACRO BS3_BEGIN_DATA32 + BS3_SET_BITS 32 +%endmacro + +%macro BS3_BEGIN_TEXT64 0-1 2 + %ifndef BS3_BEGIN_TEXT64_NOT_FIRST + %define BS3_BEGIN_TEXT64_NOT_FIRST + section BS3TEXT64 align=%1 CLASS=BS3CLASS64CODE PUBLIC USE32 FLAT + %else + section BS3TEXT64 + %endif + %undef BS3_CUR_SEG_BEGIN_MACRO + %xdefine BS3_CUR_SEG_BEGIN_MACRO BS3_BEGIN_TEXT64 + BS3_SET_BITS 64 +%endmacro + +%macro BS3_BEGIN_DATA64 0-1 16 + %ifndef BS3_BEGIN_DATA64_NOT_FIRST + %define BS3_BEGIN_DATA64_NOT_FIRST + section BS3DATA64 align=%1 CLASS=FAR_DATA PUBLIC USE32 ;FLAT (see DATA32) + %else + section BS3DATA64 + %endif + %undef BS3_CUR_SEG_BEGIN_MACRO + %xdefine BS3_CUR_SEG_BEGIN_MACRO BS3_BEGIN_DATA64 + BS3_SET_BITS 64 +%endmacro + +;; The system data segment containing the GDT, TSSes and IDTs. +%macro BS3_BEGIN_SYSTEM16 0-1 16 + %ifndef BS3_BEGIN_SYSTEM16_NOT_FIRST + %define BS3_BEGIN_SYSTEM16_NOT_FIRST + section BS3SYSTEM16 align=%1 CLASS=BS3SYSTEM16 PUBLIC USE16 + %else + section BS3SYSTEM16 + %endif + %undef BS3_CUR_SEG_BEGIN_MACRO + %xdefine BS3_CUR_SEG_BEGIN_MACRO BS3_BEGIN_SYSTEM16 + BS3_SET_BITS 16 +%endmacro + +;; Default text section. +%macro BS3_BEGIN_DEFAULT_TEXT 0 + %if ARCH_BITS == 16 + BS3_BEGIN_TEXT16 + %elif ARCH_BITS == 32 + BS3_BEGIN_TEXT32 + %elif ARCH_BITS == 64 + BS3_BEGIN_TEXT64 + %else + %error "ARCH_BITS must be defined as either 16, 32, or 64!" + INVALID_ARCH_BITS + %endif +%endmacro + +;; @} + + +; +; Now, ditch the default 'text' section and define our own NAME macro. +; +%ifndef ASM_FORMAT_BIN + BS3_BEGIN_DEFAULT_TEXT + BS3_BEGIN_DEFAULT_TEXT ; stupid nasm automagically repeats the segment attributes. +%endif + +;; When using watcom + OMF, we're using __cdecl by default, which +; get an underscore added in front. +%define NAME(name) _ %+ NAME_OVERLOAD(name) + + +; +; Include the standard headers from iprt. +; + + +%include "iprt/asmdefs.mac" +%include "iprt/x86.mac" + + +;; +; Extern macro which mangles the name using NAME(). +%macro EXTERN 1 + extern NAME(%1) +%endmacro + +;; +; Mangles a common name according to the current cpu bit count. +; @remarks Requires the use of the BS3_SET_BITS macro instead of the BITS directive. +%define BS3_CMN_NM(a_Name) BS3_NAME_UNDERSCORE %+ a_Name %+ _c %+ __BITS__ + +;; +; Extern macro which mangles the common name correctly, redefining the unmangled +; name to the mangled one for ease of use. +; +; @param %1 The unmangled common name. +; +; @remarks Must enter the segment in which this name is defined. +; +%macro BS3_EXTERN_CMN 1 + extern BS3_CMN_NM(%1) + %undef %1 + %define %1 BS3_CMN_NM(%1) +%endmacro + +;; +; Same as BS3_EXTERN_CMN except it picks the far variant in 16-bit code. +; +; @param %1 The unmangled common name. +; +; @remarks Must enter the segment in which this name is defined. +; +%macro BS3_EXTERN_CMN_FAR 1 + extern BS3_CMN_NM_FAR(%1) + %undef %1 + %define %1 BS3_CMN_NM_FAR(%1) +%endmacro + +;; @def BS3_EXTERN_TMPL +; Mangles the given name into a template specific one. For ease of use, the +; name is redefined to the mangled one, just like BS3_EXTERN_CMN does. +; @note Segment does not change. +%macro BS3_EXTERN_TMPL 1 + extern TMPL_NM(%1) + %undef %1 + %define %1 TMPL_NM(%1) +%endmacro + + +;; +; Mangles a 16-bit and 32-bit accessible data name. +; @remarks Requires the use of the BS3_SET_BITS macro instead of the BITS directive. +%define BS3_DATA_NM(a_Name) _ %+ a_Name + +;; +; Extern macro which mangles a DATA16 symbol correctly, redefining the +; unmangled name to the mangled one for ease of use. +; +; @param %1 The unmangled common name. +; +; @remarks Will change to the DATA16 segment, use must switch back afterwards! +; +%macro BS3_EXTERN_DATA16 1 + BS3_BEGIN_DATA16 + extern _ %+ %1 + %undef %1 + %define %1 _ %+ %1 +%endmacro + +;; +; Extern macro which mangles a BS3SYSTEM16 symbol correctly, redefining the +; unmangled name to the mangled one for ease of use. +; +; @param %1 The unmangled common name. +; +; @remarks Will change to the SYSTEM16 segment, use must switch back afterwards! +; +%macro BS3_EXTERN_SYSTEM16 1 + BS3_BEGIN_SYSTEM16 + extern _ %+ %1 + %undef %1 + %define %1 _ %+ %1 +%endmacro + + +;; +; Global name with ELF attributes and size. +; +; This differs from GLOBALNAME_EX in that it expects a mangled symbol name, +; and allows for nasm style symbol size expressions. +; +; @param %1 The mangled name. +; @param %2 Symbol attributes. +; @param %3 The size expression. +; +%macro BS3_GLOBAL_NAME_EX 3 +global %1 +%1: +%undef BS3_LAST_LABEL +%xdefine BS3_LAST_LABEL %1 +%endmacro + +;; +; Global local label. +; +; This should be used when switching segments and jumping to it via a local lable. +; It makes the lable visible to the debugger and map file. +; +%macro BS3_GLOBAL_LOCAL_LABEL 1 +global RT_CONCAT(BS3_LAST_LABEL,%1) +%1: +%endmacro + +;; +; Global data unmangled label. +; +; @param %1 The unmangled name. +; @param %2 The size (0 is fine). +; +%macro BS3_GLOBAL_DATA 2 +BS3_GLOBAL_NAME_EX BS3_DATA_NM(%1), , %2 +%endmacro + +;; +; Starts a procedure. +; +; This differs from BEGINPROC in that it expects a mangled symbol name and +; does the NASM symbol size stuff. +; +; @param %1 The mangled name. +; +%macro BS3_PROC_BEGIN 1 +BS3_GLOBAL_NAME_EX %1, function, (%1 %+ _EndProc - %1) +%endmacro + +;; +; Ends a procedure. +; +; Counter part to BS3_PROC_BEGIN. +; +; @param %1 The mangled name. +; +%macro BS3_PROC_END 1 +BS3_GLOBAL_NAME_EX %1 %+ _EndProc, function hidden, (%1 %+ _EndProc - %1) + int3 ; handy and avoids overlapping labels. +%endmacro + + +;; @name BS3_PBC_XXX - For use as the 2nd parameter to BS3_PROC_BEGIN_CMN and BS3_PROC_BEGIN_MODE. +;; @{ +%define BS3_PBC_NEAR 1 ;;< Only near. +%define BS3_PBC_FAR 2 ;;< Only far. +%define BS3_PBC_HYBRID 3 ;;< Hybrid near/far procedure, trashing AX +%define BS3_PBC_HYBRID_SAFE 4 ;;< Hybrid near/far procedure, no trashing but slower. +%define BS3_PBC_HYBRID_0_ARGS 5 ;;< Hybrid near/far procedure, no parameters so separate far stub, no trashing, fast near calls. +;; @} + +;; Internal begin procedure macro. +; +; @param 1 The near name. +; @param 2 The far name +; @param 3 BS3_PBC_XXX. +%macro BS3_PROC_BEGIN_INT 3 + ;%warning "BS3_PROC_BEGIN_INT:" 1=%1 2=%2 3=%3 + %undef BS3_CUR_PROC_FLAGS + %if __BITS__ == 16 + %if %3 == BS3_PBC_NEAR + %xdefine BS3_CUR_PROC_FLAGS BS3_PBC_NEAR + %xdefine cbCurRetAddr 2 + BS3_PROC_BEGIN %1 + + %elif %3 == BS3_PBC_FAR + %xdefine BS3_CUR_PROC_FLAGS BS3_PBC_FAR + %xdefine cbCurRetAddr 4 + BS3_PROC_BEGIN %2 + + %elif %3 == BS3_PBC_HYBRID + %xdefine BS3_CUR_PROC_FLAGS BS3_PBC_HYBRID + %xdefine cbCurRetAddr 4 + BS3_GLOBAL_NAME_EX %1, function, 3 + pop ax + push cs + push ax + BS3_PROC_BEGIN %2 + + %elif %3 == BS3_PBC_HYBRID_SAFE + %xdefine BS3_CUR_PROC_FLAGS BS3_PBC_HYBRID_SAFE + %xdefine cbCurRetAddr 4 + BS3_GLOBAL_NAME_EX %1, function, 3 + extern Bs3CreateHybridFarRet_c16 + call Bs3CreateHybridFarRet_c16 + BS3_PROC_BEGIN %2 + + %elif %3 == BS3_PBC_HYBRID_0_ARGS + %xdefine BS3_CUR_PROC_FLAGS BS3_PBC_NEAR + %xdefine cbCurRetAddr 2 + %xdefine TMP_BEGIN_PREV_SEG BS3_CUR_SEG_BEGIN_MACRO + + BS3_BEGIN_TEXT16_FARSTUBS + BS3_PROC_BEGIN %2 + call %1 + retf + BS3_PROC_END %2 + + TMP_BEGIN_PREV_SEG + BS3_PROC_BEGIN %1 + %undef TMP_BEGIN_PREV_SEG + + %else + %error BS3_PROC_BEGIN_CMN parameter 2 value %3 is not recognized. + + %xdefine BS3_CUR_PROC_FLAGS BS3_PBC_NEAR + %xdefine cbCurRetAddr 4 + BS3_PROC_BEGIN %1 + %endif + %else + %xdefine BS3_CUR_PROC_FLAGS BS3_PBC_NEAR + %xdefine cbCurRetAddr xCB + BS3_PROC_BEGIN %1 + %endif +%endmacro + +;; Internal end procedure macro +; +; @param 1 The near name. +; @param 2 The far name +; +%macro BS3_PROC_END_INT 2 + %if __BITS__ == 16 + %if BS3_CUR_PROC_FLAGS == BS3_PBC_NEAR + BS3_PROC_END %1 + %else + BS3_PROC_END %2 + %endif + %else + BS3_PROC_END %1 + %endif + %undef BS3_CUR_PROC_FLAGS + %undef cbCurRetAddr +%endmacro + + +;; Convenience macro for defining common procedures. +; This will emit both near and far 16-bit symbols according to parameter %2 (BS3_PBC_XXX). +%macro BS3_PROC_BEGIN_CMN 2 + BS3_PROC_BEGIN_INT BS3_CMN_NM(%1), BS3_CMN_NM_FAR(%1), %2 +%endmacro + +;; Convenience macro for defining common procedures. +%macro BS3_PROC_END_CMN 1 + BS3_PROC_END_INT BS3_CMN_NM(%1), BS3_CMN_NM_FAR(%1) +%endmacro + +;; +; Generate a safe 16-bit far stub for function %1, shuffling %2 bytes of parameters. +; +; This does absolutely nothing in 32-bit and 64-bit mode. +; +; @param 1 The function basename. +; @param 2 The number of bytes of parameters on the stack, must be a multiple of 2. +; @remarks Changes the segment to TEXT16. +; +%macro BS3_CMN_FAR_STUB 2 + %if %2 <= 1 || (%2 & 1) + %error Invalid parameter frame size passed to BS3_CMN_FAR_STUB: %2 + %endif + %if __BITS__ == 16 +BS3_BEGIN_TEXT16_FARSTUBS +BS3_PROC_BEGIN_CMN %1, BS3_PBC_FAR + CPU 8086 + inc bp ; Odd bp is far call indicator. + push bp + mov bp, sp + %assign offParam %2 + %rep %2/2 + push word [bp + xCB + cbCurRetAddr + offParam - 2] + %assign offParam offParam - 2 + %endrep + call BS3_CMN_NM(%1) + add sp, %2 + pop bp + dec bp + retf +BS3_PROC_END_CMN %1 +BS3_BEGIN_TEXT16 + %endif +%endmacro + + +;; Convenience macro for defining mode specific procedures. +%macro BS3_PROC_BEGIN_MODE 2 + ;%warning "BS3_PROC_BEGIN_MODE: 1=" %1 "2=" %2 + BS3_PROC_BEGIN_INT TMPL_NM(%1), TMPL_FAR_NM(%1), %2 +%endmacro + +;; Convenience macro for defining mode specific procedures. +%macro BS3_PROC_END_MODE 1 + BS3_PROC_END_INT TMPL_NM(%1), TMPL_FAR_NM(%1) +%endmacro + +;; Does a far return in 16-bit code, near return in 32-bit and 64-bit. +; This is for use with BS3_PBC_XXX +%macro BS3_HYBRID_RET 0-1 + %if __BITS__ == 16 + %if %0 > 0 + %if BS3_CUR_PROC_FLAGS == BS3_PBC_NEAR || BS3_CUR_PROC_FLAGS == BS3_PBC_HYBRID_0_ARGS + ret %1 + %else + retf %1 + %endif + %else + %if BS3_CUR_PROC_FLAGS == BS3_PBC_NEAR || BS3_CUR_PROC_FLAGS == BS3_PBC_HYBRID_0_ARGS + ret + %else + retf + %endif + %endif + %else + %if BS3_CUR_PROC_FLAGS != BS3_PBC_NEAR + %error Expected BS3_CUR_PROC_FLAGS to be BS3_PBC_NEAR in non-16-bit code. + %endif + %if %0 > 0 + ret %1 + %else + ret + %endif + %endif +%endmacro + + +;; +; Prologue hacks for 64-bit code. +; +; This saves the four register parameters onto the stack so we can pretend +; the calling convention is stack based. The 64-bit calling convension is +; the microsoft one, so this is straight forward. +; +; Pairs with BS3_CALL_CONV_EPILOG. +; +; @param %1 The number of parameters. +; +; @remarks Must be invoked before any stack changing instructions are emitted. +; +%macro BS3_CALL_CONV_PROLOG 1 + %undef BS3_CALL_CONV_PROLOG_PARAMS + %define BS3_CALL_CONV_PROLOG_PARAMS %1 + %if __BITS__ == 64 + %if %1 >= 1 + mov [rsp + 008h], rcx + %elifdef BS3_STRICT + and qword [rsp + 008h], 1 + %endif + %if %1 >= 2 + mov [rsp + 010h], rdx + %elifdef BS3_STRICT + and qword [rsp + 010h], 2 + %endif + %if %1 >= 3 + mov [rsp + 018h], r8 + %elifdef BS3_STRICT + and qword [rsp + 018h], 3 + %endif + %if %1 >= 4 + mov [rsp + 020h], r9 + %elifdef BS3_STRICT + and qword [rsp + 020h], 4 + %endif + %endif +%endmacro + +;; +; Epilogue hacks for 64-bit code. +; +; Counter part to BS3_CALL_CONV_PROLOG. +; +; @param %1 The number of parameters. +; +; @remarks Must be invoked right before the return instruction as it uses RSP. +; +%macro BS3_CALL_CONV_EPILOG 1 + %if BS3_CALL_CONV_PROLOG_PARAMS != %1 + %error "BS3_CALL_CONV_EPILOG argument differs from BS3_CALL_CONV_PROLOG." + %endif + %if __BITS__ == 64 + %ifdef BS3_STRICT + mov dword [rsp + 008h], 31h + mov dword [rsp + 010h], 32h + mov dword [rsp + 018h], 33h + mov dword [rsp + 020h], 34h + %endif + %endif +%endmacro + +;; +; Wrapper for the call instruction that hides calling convension differences. +; +; This always calls %1. +; In 64-bit code, it will load up to 4 parameters into register. +; +; @param %1 The function to call (mangled). +; @param %2 The number of parameters. +; +%macro BS3_CALL 2 + %if __BITS__ == 64 + %if %2 >= 1 + mov rcx, [rsp] + %ifdef BS3_STRICT + and qword [rsp], 11h + %endif + %endif + %if %2 >= 2 + mov rdx, [rsp + 008h] + %ifdef BS3_STRICT + and qword [rsp + 008h], 12h + %endif + %endif + %if %2 >= 3 + mov r8, [rsp + 010h] + %ifdef BS3_STRICT + and qword [rsp + 010h], 13h + %endif + %endif + %if %2 >= 4 + mov r9, [rsp + 018h] + %ifdef BS3_STRICT + and qword [rsp + 018h], 14h + %endif + %endif + %endif + call %1 +%endmacro + + +;; @name Execution Modes +; @{ +%define BS3_MODE_INVALID 000h +%define BS3_MODE_RM 001h ;;< real mode. +%define BS3_MODE_PE16 011h ;;< 16-bit protected mode kernel+tss, running 16-bit code, unpaged. +%define BS3_MODE_PE16_32 012h ;;< 16-bit protected mode kernel+tss, running 32-bit code, unpaged. +%define BS3_MODE_PE16_V86 018h ;;< 16-bit protected mode kernel+tss, running virtual 8086 mode code, unpaged. +%define BS3_MODE_PE32 022h ;;< 32-bit protected mode kernel+tss, running 32-bit code, unpaged. +%define BS3_MODE_PE32_16 021h ;;< 32-bit protected mode kernel+tss, running 16-bit code, unpaged. +%define BS3_MODE_PEV86 028h ;;< 32-bit protected mode kernel+tss, running virtual 8086 mode code, unpaged. +%define BS3_MODE_PP16 031h ;;< 16-bit protected mode kernel+tss, running 16-bit code, paged. +%define BS3_MODE_PP16_32 032h ;;< 16-bit protected mode kernel+tss, running 32-bit code, paged. +%define BS3_MODE_PP16_V86 038h ;;< 16-bit protected mode kernel+tss, running virtual 8086 mode code, paged. +%define BS3_MODE_PP32 042h ;;< 32-bit protected mode kernel+tss, running 32-bit code, paged. +%define BS3_MODE_PP32_16 041h ;;< 32-bit protected mode kernel+tss, running 16-bit code, paged. +%define BS3_MODE_PPV86 048h ;;< 32-bit protected mode kernel+tss, running virtual 8086 mode code, paged. +%define BS3_MODE_PAE16 051h ;;< 16-bit protected mode kernel+tss, running 16-bit code, PAE paging. +%define BS3_MODE_PAE16_32 052h ;;< 16-bit protected mode kernel+tss, running 32-bit code, PAE paging. +%define BS3_MODE_PAE16_V86 058h ;;< 16-bit protected mode kernel+tss, running virtual 8086 mode, PAE paging. +%define BS3_MODE_PAE32 062h ;;< 32-bit protected mode kernel+tss, running 32-bit code, PAE paging. +%define BS3_MODE_PAE32_16 061h ;;< 32-bit protected mode kernel+tss, running 16-bit code, PAE paging. +%define BS3_MODE_PAEV86 068h ;;< 32-bit protected mode kernel+tss, running virtual 8086 mode, PAE paging. +%define BS3_MODE_LM16 071h ;;< 16-bit long mode (paged), kernel+tss always 64-bit. +%define BS3_MODE_LM32 072h ;;< 32-bit long mode (paged), kernel+tss always 64-bit. +%define BS3_MODE_LM64 074h ;;< 64-bit long mode (paged), kernel+tss always 64-bit. + +%define BS3_MODE_CODE_MASK 00fh ;;< Running code mask. +%define BS3_MODE_CODE_16 001h ;;< Running 16-bit code. +%define BS3_MODE_CODE_32 002h ;;< Running 32-bit code. +%define BS3_MODE_CODE_64 004h ;;< Running 64-bit code. +%define BS3_MODE_CODE_V86 008h ;;< Running 16-bit virtual 8086 code. + +%define BS3_MODE_SYS_MASK 0f0h ;;< kernel+tss mask. +%define BS3_MODE_SYS_RM 000h ;;< Real mode kernel+tss. +%define BS3_MODE_SYS_PE16 010h ;;< 16-bit protected mode kernel+tss. +%define BS3_MODE_SYS_PE32 020h ;;< 32-bit protected mode kernel+tss. +%define BS3_MODE_SYS_PP16 030h ;;< 16-bit paged protected mode kernel+tss. +%define BS3_MODE_SYS_PP32 040h ;;< 32-bit paged protected mode kernel+tss. +%define BS3_MODE_SYS_PAE16 050h ;;< 16-bit PAE paged protected mode kernel+tss. +%define BS3_MODE_SYS_PAE32 060h ;;< 32-bit PAE paged protected mode kernel+tss. +%define BS3_MODE_SYS_LM 070h ;;< 64-bit (paged) long mode protected mode kernel+tss. + +;; Whether the mode has paging enabled. +%define BS3_MODE_IS_PAGED(a_fMode) ((a_fMode) >= BS3_MODE_PP16) + +;; Whether the mode is running v8086 code. +%define BS3_MODE_IS_V86(a_fMode) (((a_fMode) & BS3_MODE_CODE_MASK) == BS3_MODE_CODE_V86) +;; Whether the we're executing in real mode or v8086 mode. +%define BS3_MODE_IS_RM_OR_V86(a_fMode) ((a_fMode) == BS3_MODE_RM || BS3_MODE_IS_V86(a_fMode)) +;; Whether the mode is running 16-bit code, except v8086. +%define BS3_MODE_IS_16BIT_CODE_NO_V86(a_fMode) (((a_fMode) & BS3_MODE_CODE_MASK) == BS3_MODE_CODE_16) +;; Whether the mode is running 16-bit code (includes v8086). +%define BS3_MODE_IS_16BIT_CODE(a_fMode) (BS3_MODE_IS_16BIT_CODE_NO_V86(a_fMode) || BS3_MODE_IS_V86(a_fMode)) +;; Whether the mode is running 32-bit code. +%define BS3_MODE_IS_32BIT_CODE(a_fMode) (((a_fMode) & BS3_MODE_CODE_MASK) == BS3_MODE_CODE_32) +;; Whether the mode is running 64-bit code. +%define BS3_MODE_IS_64BIT_CODE(a_fMode) (((a_fMode) & BS3_MODE_CODE_MASK) == BS3_MODE_CODE_64) + +;; Whether the system is in real mode. +%define BS3_MODE_IS_RM_SYS(a_fMode) (((a_fMode) & BS3_MODE_SYS_MASK) == BS3_MODE_SYS_RM) +;; Whether the system is some 16-bit mode that isn't real mode. +%define BS3_MODE_IS_16BIT_SYS_NO_RM(a_fMode) ( ((a_fMode) & BS3_MODE_SYS_MASK) == BS3_MODE_SYS_PE16 \ + || ((a_fMode) & BS3_MODE_SYS_MASK) == BS3_MODE_SYS_PP16 \ + || ((a_fMode) & BS3_MODE_SYS_MASK) == BS3_MODE_SYS_PAE16) +;; Whether the system is some 16-bit mode (includes real mode). +%define BS3_MODE_IS_16BIT_SYS(a_fMode) (BS3_MODE_IS_16BIT_SYS_NO_RM(a_fMode) || BS3_MODE_IS_RM_SYS(a_fMode)) +;; Whether the system is some 32-bit mode. +%define BS3_MODE_IS_32BIT_SYS(a_fMode) ( ((a_fMode) & BS3_MODE_SYS_MASK) == BS3_MODE_SYS_PE32 \ + || ((a_fMode) & BS3_MODE_SYS_MASK) == BS3_MODE_SYS_PP32 \ + || ((a_fMode) & BS3_MODE_SYS_MASK) == BS3_MODE_SYS_PAE32) +;; Whether the system is long mode. +%define BS3_MODE_IS_64BIT_SYS(a_fMode) (((a_fMode) & BS3_MODE_SYS_MASK) == BS3_MODE_SYS_LM) + +;; @} + +;; @name For mode specfic lookups: +;; %[BS3_MODE_NM %+ BS3_MODE_PE32](SomeBaseName) +;; %[BS3_MODE_LNAME_ %+ TMPL_MODE] +;; @{ +%define BS3_MODE_NM_001h(a_Name) _ %+ a_Name %+ _rm +%define BS3_MODE_NM_011h(a_Name) _ %+ a_Name %+ _pe16 +%define BS3_MODE_NM_012h(a_Name) _ %+ a_Name %+ _pe16_32 +%define BS3_MODE_NM_018h(a_Name) _ %+ a_Name %+ _pe16_v86 +%define BS3_MODE_NM_022h(a_Name) _ %+ a_Name %+ _pe32 +%define BS3_MODE_NM_021h(a_Name) _ %+ a_Name %+ _pe32_16 +%define BS3_MODE_NM_028h(a_Name) _ %+ a_Name %+ _pev86 +%define BS3_MODE_NM_031h(a_Name) _ %+ a_Name %+ _pp16 +%define BS3_MODE_NM_032h(a_Name) _ %+ a_Name %+ _pp16_32 +%define BS3_MODE_NM_038h(a_Name) _ %+ a_Name %+ _pp16_v86 +%define BS3_MODE_NM_042h(a_Name) _ %+ a_Name %+ _pp32 +%define BS3_MODE_NM_041h(a_Name) _ %+ a_Name %+ _pp32_16 +%define BS3_MODE_NM_048h(a_Name) _ %+ a_Name %+ _ppv86 +%define BS3_MODE_NM_051h(a_Name) _ %+ a_Name %+ _pae16 +%define BS3_MODE_NM_052h(a_Name) _ %+ a_Name %+ _pae16_32 +%define BS3_MODE_NM_058h(a_Name) _ %+ a_Name %+ _pae16_v86 +%define BS3_MODE_NM_062h(a_Name) _ %+ a_Name %+ _pae32 +%define BS3_MODE_NM_061h(a_Name) _ %+ a_Name %+ _pae32_16 +%define BS3_MODE_NM_068h(a_Name) _ %+ a_Name %+ _paev86 +%define BS3_MODE_NM_071h(a_Name) _ %+ a_Name %+ _lm16 +%define BS3_MODE_NM_072h(a_Name) _ %+ a_Name %+ _lm32 +%define BS3_MODE_NM_074h(a_Name) _ %+ a_Name %+ _lm64 + +%define BS3_MODE_LNAME_001h rm +%define BS3_MODE_LNAME_011h pe16 +%define BS3_MODE_LNAME_012h pe16_32 +%define BS3_MODE_LNAME_018h pe16_v86 +%define BS3_MODE_LNAME_022h pe32 +%define BS3_MODE_LNAME_021h pe32_16 +%define BS3_MODE_LNAME_028h pev86 +%define BS3_MODE_LNAME_031h pp16 +%define BS3_MODE_LNAME_032h pp16_32 +%define BS3_MODE_LNAME_038h pp16_v86 +%define BS3_MODE_LNAME_042h pp32 +%define BS3_MODE_LNAME_041h pp32_16 +%define BS3_MODE_LNAME_048h ppv86 +%define BS3_MODE_LNAME_051h pae16 +%define BS3_MODE_LNAME_052h pae16_32 +%define BS3_MODE_LNAME_058h pae16_v86 +%define BS3_MODE_LNAME_062h pae32 +%define BS3_MODE_LNAME_061h pae32_16 +%define BS3_MODE_LNAME_068h paev86 +%define BS3_MODE_LNAME_071h lm16 +%define BS3_MODE_LNAME_072h lm32 +%define BS3_MODE_LNAME_074h lm64 + +%define BS3_MODE_UNAME_001h RM +%define BS3_MODE_UNAME_011h PE16 +%define BS3_MODE_UNAME_012h PE16_32 +%define BS3_MODE_UNAME_018h PE16_V86 +%define BS3_MODE_UNAME_022h PE32 +%define BS3_MODE_UNAME_021h PE32_16 +%define BS3_MODE_UNAME_028h PEV86 +%define BS3_MODE_UNAME_031h PP16 +%define BS3_MODE_UNAME_032h PP16_32 +%define BS3_MODE_UNAME_038h PP16_V86 +%define BS3_MODE_UNAME_042h PP32 +%define BS3_MODE_UNAME_041h PP32_16 +%define BS3_MODE_UNAME_048h PPV86 +%define BS3_MODE_UNAME_051h PAE16 +%define BS3_MODE_UNAME_052h PAE16_32 +%define BS3_MODE_UNAME_058h PAE16_V86 +%define BS3_MODE_UNAME_062h PAE32 +%define BS3_MODE_UNAME_061h PAE32_16 +%define BS3_MODE_UNAME_068h PAEV86 +%define BS3_MODE_UNAME_071h LM16 +%define BS3_MODE_UNAME_072h LM32 +%define BS3_MODE_UNAME_074h LM64 + +%define BS3_MODE_UNDERSCORE_001h _ +%define BS3_MODE_UNDERSCORE_011h _ +%define BS3_MODE_UNDERSCORE_012h _ +%define BS3_MODE_UNDERSCORE_018h _ +%define BS3_MODE_UNDERSCORE_022h _ +%define BS3_MODE_UNDERSCORE_021h _ +%define BS3_MODE_UNDERSCORE_028h _ +%define BS3_MODE_UNDERSCORE_031h _ +%define BS3_MODE_UNDERSCORE_032h _ +%define BS3_MODE_UNDERSCORE_038h _ +%define BS3_MODE_UNDERSCORE_042h _ +%define BS3_MODE_UNDERSCORE_041h _ +%define BS3_MODE_UNDERSCORE_048h _ +%define BS3_MODE_UNDERSCORE_051h _ +%define BS3_MODE_UNDERSCORE_052h _ +%define BS3_MODE_UNDERSCORE_058h _ +%define BS3_MODE_UNDERSCORE_062h _ +%define BS3_MODE_UNDERSCORE_061h _ +%define BS3_MODE_UNDERSCORE_068h _ +%define BS3_MODE_UNDERSCORE_071h _ +%define BS3_MODE_UNDERSCORE_072h _ +%define BS3_MODE_UNDERSCORE_074h _ + +%define BS3_MODE_CNAME_001h c16 +%define BS3_MODE_CNAME_011h c16 +%define BS3_MODE_CNAME_012h c32 +%define BS3_MODE_CNAME_018h c16 +%define BS3_MODE_CNAME_022h c32 +%define BS3_MODE_CNAME_021h c16 +%define BS3_MODE_CNAME_028h c16 +%define BS3_MODE_CNAME_031h c16 +%define BS3_MODE_CNAME_032h c32 +%define BS3_MODE_CNAME_038h c16 +%define BS3_MODE_CNAME_042h c32 +%define BS3_MODE_CNAME_041h c16 +%define BS3_MODE_CNAME_048h c16 +%define BS3_MODE_CNAME_051h c16 +%define BS3_MODE_CNAME_052h c32 +%define BS3_MODE_CNAME_058h c16 +%define BS3_MODE_CNAME_062h c32 +%define BS3_MODE_CNAME_061h c16 +%define BS3_MODE_CNAME_068h c16 +%define BS3_MODE_CNAME_071h c16 +%define BS3_MODE_CNAME_072h c32 +%define BS3_MODE_CNAME_074h c64 +;; @} + +;; @name For getting the ring-0 mode for v86 modes: %[BS3_MODE_R0_NM_001h %+ TMPL_MODE](Bs3SwitchToRM) +;; @{ +%define BS3_MODE_R0_NM_001h(a_Name) _ %+ a_Name %+ _rm +%define BS3_MODE_R0_NM_011h(a_Name) _ %+ a_Name %+ _pe16 +%define BS3_MODE_R0_NM_012h(a_Name) _ %+ a_Name %+ _pe16_32 +%define BS3_MODE_R0_NM_018h(a_Name) _ %+ a_Name %+ _pe16 +%define BS3_MODE_R0_NM_022h(a_Name) _ %+ a_Name %+ _pe32 +%define BS3_MODE_R0_NM_021h(a_Name) _ %+ a_Name %+ _pe32_16 +%define BS3_MODE_R0_NM_028h(a_Name) _ %+ a_Name %+ _pe32_16 +%define BS3_MODE_R0_NM_031h(a_Name) _ %+ a_Name %+ _pp16 +%define BS3_MODE_R0_NM_032h(a_Name) _ %+ a_Name %+ _pp16_32 +%define BS3_MODE_R0_NM_038h(a_Name) _ %+ a_Name %+ _pp16 +%define BS3_MODE_R0_NM_042h(a_Name) _ %+ a_Name %+ _pp32 +%define BS3_MODE_R0_NM_041h(a_Name) _ %+ a_Name %+ _pp32_16 +%define BS3_MODE_R0_NM_048h(a_Name) _ %+ a_Name %+ _pp32_16 +%define BS3_MODE_R0_NM_051h(a_Name) _ %+ a_Name %+ _pae16 +%define BS3_MODE_R0_NM_052h(a_Name) _ %+ a_Name %+ _pae16_32 +%define BS3_MODE_R0_NM_058h(a_Name) _ %+ a_Name %+ _pae16 +%define BS3_MODE_R0_NM_062h(a_Name) _ %+ a_Name %+ _pae32 +%define BS3_MODE_R0_NM_061h(a_Name) _ %+ a_Name %+ _pae32_16 +%define BS3_MODE_R0_NM_068h(a_Name) _ %+ a_Name %+ _pae32_16 +%define BS3_MODE_R0_NM_071h(a_Name) _ %+ a_Name %+ _lm16 +%define BS3_MODE_R0_NM_072h(a_Name) _ %+ a_Name %+ _lm32 +%define BS3_MODE_R0_NM_074h(a_Name) _ %+ a_Name %+ _lm64 +;; @} + + +;; +; Includes the file %1 with TMPL_MODE set to all possible value. +; @param 1 Double quoted include file name. +%macro BS3_INSTANTIATE_TEMPLATE_WITH_WEIRD_ONES 1 + %define BS3_INSTANTIATING_MODE + %define BS3_INSTANTIATING_ALL_MODES + + %define TMPL_MODE BS3_MODE_RM + %include %1 + + %define TMPL_MODE BS3_MODE_PE16 + %include %1 + %define TMPL_MODE BS3_MODE_PE16_32 + %include %1 + %define TMPL_MODE BS3_MODE_PE16_V86 + %include %1 + + %define TMPL_MODE BS3_MODE_PE32 + %include %1 + %define TMPL_MODE BS3_MODE_PE32_16 + %include %1 + %define TMPL_MODE BS3_MODE_PEV86 + %include %1 + + %define TMPL_MODE BS3_MODE_PP16 + %include %1 + %define TMPL_MODE BS3_MODE_PP16_32 + %include %1 + %define TMPL_MODE BS3_MODE_PP16_V86 + %include %1 + + %define TMPL_MODE BS3_MODE_PP32 + %include %1 + %define TMPL_MODE BS3_MODE_PP32_16 + %include %1 + %define TMPL_MODE BS3_MODE_PPV86 + %include %1 + + %define TMPL_MODE BS3_MODE_PAE16 + %include %1 + %define TMPL_MODE BS3_MODE_PAE16_32 + %include %1 + %define TMPL_MODE BS3_MODE_PAE16_V86 + %include %1 + + %define TMPL_MODE BS3_MODE_PAE32 + %include %1 + %define TMPL_MODE BS3_MODE_PAE32_16 + %include %1 + %define TMPL_MODE BS3_MODE_PAEV86 + %include %1 + + %define TMPL_MODE BS3_MODE_LM16 + %include %1 + %define TMPL_MODE BS3_MODE_LM32 + %include %1 + %define TMPL_MODE BS3_MODE_LM64 + %include %1 + + %undef BS3_INSTANTIATING_MODE + %undef BS3_INSTANTIATING_ALL_MODES +%endmacro + + +;; +; Includes the file %1 with TMPL_MODE set to all but the "weird" value. +; @param 1 Double quoted include file name. +%macro BS3_INSTANTIATE_TEMPLATE_ESSENTIALS 1 + %define BS3_INSTANTIATING_MODE + %define BS3_INSTANTIATING_ESSENTIAL_MODES + + %define TMPL_MODE BS3_MODE_RM + %include %1 + + %define TMPL_MODE BS3_MODE_PE16 + %include %1 + + %define TMPL_MODE BS3_MODE_PE32 + %include %1 + %define TMPL_MODE BS3_MODE_PEV86 + %include %1 + + %define TMPL_MODE BS3_MODE_PP16 + %include %1 + + %define TMPL_MODE BS3_MODE_PP32 + %include %1 + %define TMPL_MODE BS3_MODE_PPV86 + %include %1 + + %define TMPL_MODE BS3_MODE_PAE16 + %include %1 + + %define TMPL_MODE BS3_MODE_PAE32 + %include %1 + %define TMPL_MODE BS3_MODE_PAEV86 + %include %1 + + %define TMPL_MODE BS3_MODE_LM16 + %include %1 + %define TMPL_MODE BS3_MODE_LM32 + %include %1 + %define TMPL_MODE BS3_MODE_LM64 + %include %1 + + %undef BS3_INSTANTIATING_MODE + %undef BS3_INSTANTIATING_ESSENTIAL_MODES +%endmacro + +;; +; Includes the file %1 with TMPL_MODE set to a 16-bit, a 32-bit and a 64-bit value. +; @param 1 Double quoted include file name. +%macro BS3_INSTANTIATE_COMMON_TEMPLATE 1 + %define BS3_INSTANTIATING_CMN + + %define TMPL_MODE BS3_MODE_RM + %include %1 + %define TMPL_MODE BS3_MODE_PE32 + %include %1 + %define TMPL_MODE BS3_MODE_LM64 + %include %1 + + %undef BS3_INSTANTIATING_CMN +%endmacro + + +;; @name Static Memory Allocation +; @{ +;; The flat load address for the code after the bootsector. +%define BS3_ADDR_LOAD 010000h +;; Where we save the boot registers during init. +; Located right before the code. +%define BS3_ADDR_REG_SAVE (BS3_ADDR_LOAD - BS3REGCTX_size - 8) +;; Where the stack starts (initial RSP value). +; Located 16 bytes (assumed by boot sector) before the saved registers. SS.BASE=0. +%define BS3_ADDR_STACK (BS3_ADDR_REG_SAVE - 16) +;; The ring-0 stack (8KB) for ring transitions. +%define BS3_ADDR_STACK_R0 006000h +;; The ring-1 stack (8KB) for ring transitions. +%define BS3_ADDR_STACK_R1 004000h +;; The ring-2 stack (8KB) for ring transitions. +%define BS3_ADDR_STACK_R2 002000h +;; IST1 ring-0 stack for long mode (4KB), used for double faults elsewhere. +%define BS3_ADDR_STACK_R0_IST1 009000h +;; IST2 ring-0 stack for long mode (3KB), used for spare 0 stack elsewhere. +%define BS3_ADDR_STACK_R0_IST2 008000h +;; IST3 ring-0 stack for long mode (1KB). +%define BS3_ADDR_STACK_R0_IST3 007400h +;; IST4 ring-0 stack for long mode (1KB), used for spare 1 stack elsewhere. +%define BS3_ADDR_STACK_R0_IST4 007000h +;; IST5 ring-0 stack for long mode (1KB). +%define BS3_ADDR_STACK_R0_IST5 006c00h +;; IST6 ring-0 stack for long mode (1KB). +%define BS3_ADDR_STACK_R0_IST6 006800h +;; IST7 ring-0 stack for long mode (1KB). +%define BS3_ADDR_STACK_R0_IST7 006400h + +;; The base address of the BS3TEXT16 segment (same as BS3_LOAD_ADDR). +;; @sa BS3_SEL_TEXT16 +%define BS3_ADDR_BS3TEXT16 010000h +;; The base address of the BS3SYSTEM16 segment. +;; @sa BS3_SEL_SYSTEM16 +%define BS3_ADDR_BS3SYSTEM16 020000h +;; The base address of the BS3DATA16/BS3KIT_GRPNM_DATA16 segment. +;; @sa BS3_SEL_DATA16 +%define BS3_ADDR_BS3DATA16 029000h +;; @} + + +;; +; BS3 register context. Used by traps and such. +; +struc BS3REGCTX + .rax resq 1 ; BS3REG rax; /**< 0x00 */ + .rcx resq 1 ; BS3REG rcx; /**< 0x08 */ + .rdx resq 1 ; BS3REG rdx; /**< 0x10 */ + .rbx resq 1 ; BS3REG rbx; /**< 0x18 */ + .rsp resq 1 ; BS3REG rsp; /**< 0x20 */ + .rbp resq 1 ; BS3REG rbp; /**< 0x28 */ + .rsi resq 1 ; BS3REG rsi; /**< 0x30 */ + .rdi resq 1 ; BS3REG rdi; /**< 0x38 */ + .r8 resq 1 ; BS3REG r8; /**< 0x40 */ + .r9 resq 1 ; BS3REG r9; /**< 0x48 */ + .r10 resq 1 ; BS3REG r10; /**< 0x50 */ + .r11 resq 1 ; BS3REG r11; /**< 0x58 */ + .r12 resq 1 ; BS3REG r12; /**< 0x60 */ + .r13 resq 1 ; BS3REG r13; /**< 0x68 */ + .r14 resq 1 ; BS3REG r14; /**< 0x70 */ + .r15 resq 1 ; BS3REG r15; /**< 0x78 */ + .rflags resq 1 ; BS3REG rflags; /**< 0x80 */ + .rip resq 1 ; BS3REG rip; /**< 0x88 */ + .cs resw 1 ; uint16_t cs; /**< 0x90 */ + .ds resw 1 ; uint16_t ds; /**< 0x92 */ + .es resw 1 ; uint16_t es; /**< 0x94 */ + .fs resw 1 ; uint16_t fs; /**< 0x96 */ + .gs resw 1 ; uint16_t gs; /**< 0x98 */ + .ss resw 1 ; uint16_t ss; /**< 0x9a */ + .tr resw 1 ; uint16_t tr; /**< 0x9c */ + .ldtr resw 1 ; uint16_t ldtr; /**< 0x9e */ + .bMode resb 1 ; uint8_t bMode; /**< 0xa0: BS3_MODE_XXX. */ + .bCpl resb 1 ; uint8_t bCpl; /**< 0xa1: 0-3, 0 is used for real mode. */ + .fbFlags resb 1 ; uint8_t fbFlags; /**< 0xa2: BS3REG_CTX_F_XXX */ + .abPadding resb 5 ; uint8_t abPadding[5]; /**< 0xa4 */ + .cr0 resq 1 ; BS3REG cr0; /**< 0xa8 */ + .cr2 resq 1 ; BS3REG cr2; /**< 0xb0 */ + .cr3 resq 1 ; BS3REG cr3; /**< 0xb8 */ + .cr4 resq 1 ; BS3REG cr4; /**< 0xc0 */ + .uUnused resq 1 ; BS3REG uUnused; /**< 0xc8 */ +endstruc +AssertCompileSize(BS3REGCTX, 0xd0) + +;; @name BS3REG_CTX_F_XXX - BS3REGCTX::fbFlags masks. +; @{ +;; The CR0 is MSW (only low 16-bit). */ +%define BS3REG_CTX_F_NO_CR0_IS_MSW 0x01 +;; No CR2 and CR3 values. Not in CPL 0 or CPU too old for CR2 & CR3. +%define BS3REG_CTX_F_NO_CR2_CR3 0x02 +;; No CR4 value. The CPU is too old for CR4. +%define BS3REG_CTX_F_NO_CR4 0x04 +;; No TR and LDTR values. Context gathered in real mode or v8086 mode. +%define BS3REG_CTX_F_NO_TR_LDTR 0x08 +;; The context doesn't have valid values for AMD64 GPR extensions. +%define BS3REG_CTX_F_NO_AMD64 0x10 +;; @} + + +;; @name Flags for Bs3RegCtxRestore +; @{ +;; Skip restoring the CRx registers. +%define BS3REGCTXRESTORE_F_SKIP_CRX 1 +;; Sets g_fBs3TrapNoV86Assist. +%define BS3REGCTXRESTORE_F_NO_V86_ASSIST 2 +;; @} + + +;; +; BS3 extended register context (FPU, SSE, AVX, ++) +; +struc BS3EXTCTX + .u16Magic resw 1 ; uint16_t u16Magic; + .cb resw 1 ; uint16_t cb; + .enmMethod resb 1 ; uint8_t enmMethod; + alignb 8 + .fXcr0Nominal resq 1 ; uint64_t fXcr0Nominal; + .fXcr0Saved resq 1 ; uint64_t fXcr0Saved; + alignb 64 + .Ctx resb 512 +endstruc +%define BS3EXTCTXMETHOD_ANCIENT 1 +%define BS3EXTCTXMETHOD_FXSAVE 2 +%define BS3EXTCTXMETHOD_XSAVE 3 + +;; +; BS3 Trap Frame. +; +struc BS3TRAPFRAME + .bXcpt resb 1 + .cbIretFrame resb 1 + .uHandlerCs resw 1 + .uHandlerSs resw 1 + .usAlignment resw 1 + .uHandlerRsp resq 1 + .fHandlerRfl resq 1 + .uErrCd resq 1 + .Ctx resb BS3REGCTX_size +endstruc +AssertCompileSize(BS3TRAPFRAME, 0x20 + 0xd0) + +;; +; Trap record. +; +struc BS3TRAPREC + ;; The trap location relative to the base address given at + ; registration time. + .offWhere resd 1 + ;; What to add to .offWhere to calculate the resume address. + .offResumeAddend resb 1 + ;; The trap number. + .u8TrapNo resb 1 + ;; The error code if the trap takes one. + .u16ErrCd resw 1 +endstruc + +;; The size shift. +%define BS3TRAPREC_SIZE_SHIFT 3 + + +;; The system call vector. +%define BS3_TRAP_SYSCALL 20h + +;; @name System call numbers (ax) +;; @note Pointers are always passed in cx:xDI. +;; @{ +;; Print char (cl). +%define BS3_SYSCALL_PRINT_CHR 0001h +;; Print string (pointer in cx:xDI, length in xDX). +%define BS3_SYSCALL_PRINT_STR 0002h +;; Switch to ring-0. +%define BS3_SYSCALL_TO_RING0 0003h +;; Switch to ring-1. +%define BS3_SYSCALL_TO_RING1 0004h +;; Switch to ring-2. +%define BS3_SYSCALL_TO_RING2 0005h +;; Switch to ring-3. +%define BS3_SYSCALL_TO_RING3 0006h +;; Restore context (pointer in cx:xDI, flags in dx). +%define BS3_SYSCALL_RESTORE_CTX 0007h +;; Set DRx register (value in ESI, register number in dl). +%define BS3_SYSCALL_SET_DRX 0008h +;; GET DRx register (register number in dl, value returned in ax:dx). +%define BS3_SYSCALL_GET_DRX 0009h +;; Set CRx register (value in ESI, register number in dl). +%define BS3_SYSCALL_SET_CRX 000ah +;; Get CRx register (register number in dl, value returned in ax:dx). +%define BS3_SYSCALL_GET_CRX 000bh +;; Set the task register (value in dx). */ +%define BS3_SYSCALL_SET_TR 000ch +;; Get the task register (value returned in ax). +%define BS3_SYSCALL_GET_TR 000dh +;; Set the LDT register (value in dx). +%define BS3_SYSCALL_SET_LDTR 000eh +;; Get the LDT register (value returned in ax). +%define BS3_SYSCALL_GET_LDTR 000fh +;; The last system call value. +%define BS3_SYSCALL_LAST BS3_SYSCALL_GET_LDTR +;; @} + + + +;; @name BS3_SEL_XXX - GDT selectors +;; @{ + +%define BS3_SEL_LDT 0010h ;;< The LDT selector (requires setting up). +%define BS3_SEL_TSS16 0020h ;;< The 16-bit TSS selector. +%define BS3_SEL_TSS16_DF 0028h ;;< The 16-bit TSS selector for double faults. +%define BS3_SEL_TSS16_SPARE0 0030h ;;< The 16-bit TSS selector for testing. +%define BS3_SEL_TSS16_SPARE1 0038h ;;< The 16-bit TSS selector for testing. +%define BS3_SEL_TSS32 0040h ;;< The 32-bit TSS selector. +%define BS3_SEL_TSS32_DF 0048h ;;< The 32-bit TSS selector for double faults. +%define BS3_SEL_TSS32_SPARE0 0050h ;;< The 32-bit TSS selector for testing. +%define BS3_SEL_TSS32_SPARE1 0058h ;;< The 32-bit TSS selector for testing. +%define BS3_SEL_TSS32_IOBP_IRB 0060h ;;< The 32-bit TSS selector with I/O permission and interrupt redirection bitmaps. +%define BS3_SEL_TSS32_IRB 0068h ;;< The 32-bit TSS selector with only interrupt redirection bitmap (IOPB stripped by limit). +%define BS3_SEL_TSS64 0070h ;;< The 64-bit TSS selector. +%define BS3_SEL_TSS64_SPARE0 0080h ;;< The 64-bit TSS selector. +%define BS3_SEL_TSS64_SPARE1 0090h ;;< The 64-bit TSS selector. +%define BS3_SEL_TSS64_IOBP 00a0h ;;< The 64-bit TSS selector. + +%define BS3_SEL_RMTEXT16_CS 00e0h ;;< Conforming code selector for accessing the BS3RMTEXT16 segment. Runtime config. +%define BS3_SEL_X0TEXT16_CS 00e8h ;;< Conforming code selector for accessing the BS3X0TEXT16 segment. Runtime config. +%define BS3_SEL_X1TEXT16_CS 00f0h ;;< Conforming code selector for accessing the BS3X1TEXT16 segment. Runtime config. +%define BS3_SEL_VMMDEV_MMIO16 00f8h ;;< Selector for accessing the VMMDev MMIO segment at 0100000h from 16-bit code. + +%define BS3_SEL_RING_SHIFT 8 ;;< For the formula: BS3_SEL_R0_XXX + ((cs & 3) << BS3_SEL_RING_SHIFT) + +%define BS3_SEL_R0_FIRST 0100h ;;< The first selector in the ring-0 block. +%define BS3_SEL_R0_CS16 0100h ;;< ring-0: 16-bit code selector, base 0x10000. +%define BS3_SEL_R0_DS16 0108h ;;< ring-0: 16-bit data selector, base 0x23000. +%define BS3_SEL_R0_SS16 0110h ;;< ring-0: 16-bit stack selector, base 0x00000. +%define BS3_SEL_R0_CS32 0118h ;;< ring-0: 32-bit flat code selector. +%define BS3_SEL_R0_DS32 0120h ;;< ring-0: 32-bit flat data selector. +%define BS3_SEL_R0_SS32 0128h ;;< ring-0: 32-bit flat stack selector. +%define BS3_SEL_R0_CS64 0130h ;;< ring-0: 64-bit flat code selector. +%define BS3_SEL_R0_DS64 0138h ;;< ring-0: 64-bit flat data & stack selector. +%define BS3_SEL_R0_CS16_EO 0140h ;;< ring-0: 16-bit execute-only code selector, not accessed, 0xfffe limit, CS16 base. +%define BS3_SEL_R0_CS16_CNF 0148h ;;< ring-0: 16-bit conforming code selector, not accessed, 0xfffe limit, CS16 base. +%define BS3_SEL_R0_CS16_CNF_EO 0150h ;;< ring-0: 16-bit execute-only conforming code selector, not accessed, 0xfffe limit, CS16 base. +%define BS3_SEL_R0_CS32_EO 0158h ;;< ring-0: 32-bit execute-only code selector, not accessed, flat. +%define BS3_SEL_R0_CS32_CNF 0160h ;;< ring-0: 32-bit conforming code selector, not accessed, flat. +%define BS3_SEL_R0_CS32_CNF_EO 0168h ;;< ring-0: 32-bit execute-only conforming code selector, not accessed, flat. +%define BS3_SEL_R0_CS64_EO 0170h ;;< ring-0: 64-bit execute-only code selector, not accessed, flat. +%define BS3_SEL_R0_CS64_CNF 0178h ;;< ring-0: 64-bit conforming code selector, not accessed, flat. +%define BS3_SEL_R0_CS64_CNF_EO 0180h ;;< ring-0: 64-bit execute-only conforming code selector, not accessed, flat. + +%define BS3_SEL_R1_FIRST 0200h ;;< The first selector in the ring-1 block. +%define BS3_SEL_R1_CS16 0200h ;;< ring-1: 16-bit code selector, base 0x10000. +%define BS3_SEL_R1_DS16 0208h ;;< ring-1: 16-bit data selector, base 0x23000. +%define BS3_SEL_R1_SS16 0210h ;;< ring-1: 16-bit stack selector, base 0x00000. +%define BS3_SEL_R1_CS32 0218h ;;< ring-1: 32-bit flat code selector. +%define BS3_SEL_R1_DS32 0220h ;;< ring-1: 32-bit flat data selector. +%define BS3_SEL_R1_SS32 0228h ;;< ring-1: 32-bit flat stack selector. +%define BS3_SEL_R1_CS64 0230h ;;< ring-1: 64-bit flat code selector. +%define BS3_SEL_R1_DS64 0238h ;;< ring-1: 64-bit flat data & stack selector. +%define BS3_SEL_R1_CS16_EO 0240h ;;< ring-1: 16-bit execute-only code selector, not accessed, 0xfffe limit, CS16 base. +%define BS3_SEL_R1_CS16_CNF 0248h ;;< ring-1: 16-bit conforming code selector, not accessed, 0xfffe limit, CS16 base. +%define BS3_SEL_R1_CS16_CNF_EO 0250h ;;< ring-1: 16-bit execute-only conforming code selector, not accessed, 0xfffe limit, CS16 base. +%define BS3_SEL_R1_CS32_EO 0258h ;;< ring-1: 32-bit execute-only code selector, not accessed, flat. +%define BS3_SEL_R1_CS32_CNF 0260h ;;< ring-1: 32-bit conforming code selector, not accessed, flat. +%define BS3_SEL_R1_CS32_CNF_EO 0268h ;;< ring-1: 32-bit execute-only conforming code selector, not accessed, flat. +%define BS3_SEL_R1_CS64_EO 0270h ;;< ring-1: 64-bit execute-only code selector, not accessed, flat. +%define BS3_SEL_R1_CS64_CNF 0278h ;;< ring-1: 64-bit conforming code selector, not accessed, flat. +%define BS3_SEL_R1_CS64_CNF_EO 0280h ;;< ring-1: 64-bit execute-only conforming code selector, not accessed, flat. + +%define BS3_SEL_R2_FIRST 0300h ;;< The first selector in the ring-2 block. +%define BS3_SEL_R2_CS16 0300h ;;< ring-2: 16-bit code selector, base 0x10000. +%define BS3_SEL_R2_DS16 0308h ;;< ring-2: 16-bit data selector, base 0x23000. +%define BS3_SEL_R2_SS16 0310h ;;< ring-2: 16-bit stack selector, base 0x00000. +%define BS3_SEL_R2_CS32 0318h ;;< ring-2: 32-bit flat code selector. +%define BS3_SEL_R2_DS32 0320h ;;< ring-2: 32-bit flat data selector. +%define BS3_SEL_R2_SS32 0328h ;;< ring-2: 32-bit flat stack selector. +%define BS3_SEL_R2_CS64 0330h ;;< ring-2: 64-bit flat code selector. +%define BS3_SEL_R2_DS64 0338h ;;< ring-2: 64-bit flat data & stack selector. +%define BS3_SEL_R2_CS16_EO 0340h ;;< ring-2: 16-bit execute-only code selector, not accessed, 0xfffe limit, CS16 base. +%define BS3_SEL_R2_CS16_CNF 0348h ;;< ring-2: 16-bit conforming code selector, not accessed, 0xfffe limit, CS16 base. +%define BS3_SEL_R2_CS16_CNF_EO 0350h ;;< ring-2: 16-bit execute-only conforming code selector, not accessed, 0xfffe limit, CS16 base. +%define BS3_SEL_R2_CS32_EO 0358h ;;< ring-2: 32-bit execute-only code selector, not accessed, flat. +%define BS3_SEL_R2_CS32_CNF 0360h ;;< ring-2: 32-bit conforming code selector, not accessed, flat. +%define BS3_SEL_R2_CS32_CNF_EO 0368h ;;< ring-2: 32-bit execute-only conforming code selector, not accessed, flat. +%define BS3_SEL_R2_CS64_EO 0370h ;;< ring-2: 64-bit execute-only code selector, not accessed, flat. +%define BS3_SEL_R2_CS64_CNF 0378h ;;< ring-2: 64-bit conforming code selector, not accessed, flat. +%define BS3_SEL_R2_CS64_CNF_EO 0380h ;;< ring-2: 64-bit execute-only conforming code selector, not accessed, flat. + +%define BS3_SEL_R3_FIRST 0400h ;;< The first selector in the ring-3 block. +%define BS3_SEL_R3_CS16 0400h ;;< ring-3: 16-bit code selector, base 0x10000. +%define BS3_SEL_R3_DS16 0408h ;;< ring-3: 16-bit data selector, base 0x23000. +%define BS3_SEL_R3_SS16 0410h ;;< ring-3: 16-bit stack selector, base 0x00000. +%define BS3_SEL_R3_CS32 0418h ;;< ring-3: 32-bit flat code selector. +%define BS3_SEL_R3_DS32 0420h ;;< ring-3: 32-bit flat data selector. +%define BS3_SEL_R3_SS32 0428h ;;< ring-3: 32-bit flat stack selector. +%define BS3_SEL_R3_CS64 0430h ;;< ring-3: 64-bit flat code selector. +%define BS3_SEL_R3_DS64 0438h ;;< ring-3: 64-bit flat data & stack selector. +%define BS3_SEL_R3_CS16_EO 0440h ;;< ring-3: 16-bit execute-only code selector, not accessed, 0xfffe limit, CS16 base. +%define BS3_SEL_R3_CS16_CNF 0448h ;;< ring-3: 16-bit conforming code selector, not accessed, 0xfffe limit, CS16 base. +%define BS3_SEL_R3_CS16_CNF_EO 0450h ;;< ring-3: 16-bit execute-only conforming code selector, not accessed, 0xfffe limit, CS16 base. +%define BS3_SEL_R3_CS32_EO 0458h ;;< ring-3: 32-bit execute-only code selector, not accessed, flat. +%define BS3_SEL_R3_CS32_CNF 0460h ;;< ring-3: 32-bit conforming code selector, not accessed, flat. +%define BS3_SEL_R3_CS32_CNF_EO 0468h ;;< ring-3: 32-bit execute-only conforming code selector, not accessed, flat. +%define BS3_SEL_R3_CS64_EO 0470h ;;< ring-3: 64-bit execute-only code selector, not accessed, flat. +%define BS3_SEL_R3_CS64_CNF 0478h ;;< ring-3: 64-bit conforming code selector, not accessed, flat. +%define BS3_SEL_R3_CS64_CNF_EO 0480h ;;< ring-3: 64-bit execute-only conforming code selector, not accessed, flat. + +%define BS3_SEL_SPARE_FIRST 0500h ;;< The first selector in the spare block +%define BS3_SEL_SPARE_00 0500h ;;< Spare selector number 00h. +%define BS3_SEL_SPARE_01 0508h ;;< Spare selector number 01h. +%define BS3_SEL_SPARE_02 0510h ;;< Spare selector number 02h. +%define BS3_SEL_SPARE_03 0518h ;;< Spare selector number 03h. +%define BS3_SEL_SPARE_04 0520h ;;< Spare selector number 04h. +%define BS3_SEL_SPARE_05 0528h ;;< Spare selector number 05h. +%define BS3_SEL_SPARE_06 0530h ;;< Spare selector number 06h. +%define BS3_SEL_SPARE_07 0538h ;;< Spare selector number 07h. +%define BS3_SEL_SPARE_08 0540h ;;< Spare selector number 08h. +%define BS3_SEL_SPARE_09 0548h ;;< Spare selector number 09h. +%define BS3_SEL_SPARE_0a 0550h ;;< Spare selector number 0ah. +%define BS3_SEL_SPARE_0b 0558h ;;< Spare selector number 0bh. +%define BS3_SEL_SPARE_0c 0560h ;;< Spare selector number 0ch. +%define BS3_SEL_SPARE_0d 0568h ;;< Spare selector number 0dh. +%define BS3_SEL_SPARE_0e 0570h ;;< Spare selector number 0eh. +%define BS3_SEL_SPARE_0f 0578h ;;< Spare selector number 0fh. +%define BS3_SEL_SPARE_10 0580h ;;< Spare selector number 10h. +%define BS3_SEL_SPARE_11 0588h ;;< Spare selector number 11h. +%define BS3_SEL_SPARE_12 0590h ;;< Spare selector number 12h. +%define BS3_SEL_SPARE_13 0598h ;;< Spare selector number 13h. +%define BS3_SEL_SPARE_14 05a0h ;;< Spare selector number 14h. +%define BS3_SEL_SPARE_15 05a8h ;;< Spare selector number 15h. +%define BS3_SEL_SPARE_16 05b0h ;;< Spare selector number 16h. +%define BS3_SEL_SPARE_17 05b8h ;;< Spare selector number 17h. +%define BS3_SEL_SPARE_18 05c0h ;;< Spare selector number 18h. +%define BS3_SEL_SPARE_19 05c8h ;;< Spare selector number 19h. +%define BS3_SEL_SPARE_1a 05d0h ;;< Spare selector number 1ah. +%define BS3_SEL_SPARE_1b 05d8h ;;< Spare selector number 1bh. +%define BS3_SEL_SPARE_1c 05e0h ;;< Spare selector number 1ch. +%define BS3_SEL_SPARE_1d 05e8h ;;< Spare selector number 1dh. +%define BS3_SEL_SPARE_1e 05f0h ;;< Spare selector number 1eh. +%define BS3_SEL_SPARE_1f 05f8h ;;< Spare selector number 1fh. + +%define BS3_SEL_TILED 0600h ;;< 16-bit data tiling: First - base=0x00000000, limit=64KB, DPL=3. +%define BS3_SEL_TILED_LAST 0df8h ;;< 16-bit data tiling: Last - base=0x00ff0000, limit=64KB, DPL=3. +%define BS3_SEL_TILED_AREA_SIZE 001000000h ;;< 16-bit data tiling: Size of addressable area, in bytes. (16 MB) + +%define BS3_SEL_FREE_PART1 0e00h ;;< Free selector space - part \%1. +%define BS3_SEL_FREE_PART1_LAST 0ff8h ;;< Free selector space - part \%1, last entry. + +%define BS3_SEL_TEXT16 1000h ;;< The BS3TEXT16 selector. + +%define BS3_SEL_FREE_PART2 1008h ;;< Free selector space - part \#2. +%define BS3_SEL_FREE_PART2_LAST 17f8h ;;< Free selector space - part \#2, last entry. + +%define BS3_SEL_TILED_R0 1800h ;;< 16-bit data/stack tiling: First - base=0x00000000, limit=64KB, DPL=0. +%define BS3_SEL_TILED_R0_LAST 1ff8h ;;< 16-bit data/stack tiling: Last - base=0x00ff0000, limit=64KB, DPL=0. + +%define BS3_SEL_SYSTEM16 2000h ;;< The BS3SYSTEM16 selector. + +%define BS3_SEL_FREE_PART3 2008h ;;< Free selector space - part \%3. +%define BS3_SEL_FREE_PART3_LAST 28f8h ;;< Free selector space - part \%3, last entry. + +%define BS3_SEL_DATA16 2900h ;;< The BS3DATA16/BS3KIT_GRPNM_DATA16 selector. + +%define BS3_SEL_FREE_PART4 2908h ;;< Free selector space - part \#4. +%define BS3_SEL_FREE_PART4_LAST 2f98h ;;< Free selector space - part \#4, last entry. + +%define BS3_SEL_PRE_TEST_PAGE_08 2fa0h ;;< Selector located 8 selectors before the test page. +%define BS3_SEL_PRE_TEST_PAGE_07 2fa8h ;;< Selector located 7 selectors before the test page. +%define BS3_SEL_PRE_TEST_PAGE_06 2fb0h ;;< Selector located 6 selectors before the test page. +%define BS3_SEL_PRE_TEST_PAGE_05 2fb8h ;;< Selector located 5 selectors before the test page. +%define BS3_SEL_PRE_TEST_PAGE_04 2fc0h ;;< Selector located 4 selectors before the test page. +%define BS3_SEL_PRE_TEST_PAGE_03 2fc8h ;;< Selector located 3 selectors before the test page. +%define BS3_SEL_PRE_TEST_PAGE_02 2fd0h ;;< Selector located 2 selectors before the test page. +%define BS3_SEL_PRE_TEST_PAGE_01 2fd8h ;;< Selector located 1 selector before the test page. +%define BS3_SEL_TEST_PAGE 2fe0h ;;< Start of the test page intended for playing around with paging and GDT. +%define BS3_SEL_TEST_PAGE_00 2fe0h ;;< Test page selector number 00h (convenience). +%define BS3_SEL_TEST_PAGE_01 2fe8h ;;< Test page selector number 01h (convenience). +%define BS3_SEL_TEST_PAGE_02 2ff0h ;;< Test page selector number 02h (convenience). +%define BS3_SEL_TEST_PAGE_03 2ff8h ;;< Test page selector number 03h (convenience). +%define BS3_SEL_TEST_PAGE_04 3000h ;;< Test page selector number 04h (convenience). +%define BS3_SEL_TEST_PAGE_05 3008h ;;< Test page selector number 05h (convenience). +%define BS3_SEL_TEST_PAGE_06 3010h ;;< Test page selector number 06h (convenience). +%define BS3_SEL_TEST_PAGE_07 3018h ;;< Test page selector number 07h (convenience). +%define BS3_SEL_TEST_PAGE_LAST 3fd0h ;;< The last selector in the spare page. + +%define BS3_SEL_GDT_LIMIT 3fd8h ;;< The GDT limit. + +;; @} + + +; +; Sanity checks. +; +%if BS3_ADDR_BS3TEXT16 != BS3_ADDR_LOAD + %error "BS3_ADDR_BS3TEXT16 and BS3_ADDR_LOAD are out of sync" +%endif +%if (BS3_ADDR_BS3TEXT16 / 16) != BS3_SEL_TEXT16 + %error "BS3_ADDR_BS3TEXT16 and BS3_SEL_TEXT16 are out of sync" +%endif +%if (BS3_ADDR_BS3DATA16 / 16) != BS3_SEL_DATA16 + %error "BS3_ADDR_BS3DATA16 and BS3_SEL_DATA16 are out of sync" +%endif +%if (BS3_ADDR_BS3SYSTEM16 / 16) != BS3_SEL_SYSTEM16 + %error "BS3_ADDR_BS3SYSTEM16 and BS3_SEL_SYSTEM16 are out of sync" +%endif + + +;; @name BS3CPU_XXX - Bs3CpuDetect_mmm return value and g_bBs3CpuDetected. +;; @{ +%define BS3CPU_8086 0x0001 +%define BS3CPU_V20 0x0002 +%define BS3CPU_80186 0x0003 +%define BS3CPU_80286 0x0004 +%define BS3CPU_80386 0x0005 +%define BS3CPU_80486 0x0006 +%define BS3CPU_Pentium 0x0007 +%define BS3CPU_PPro 0x0008 +%define BS3CPU_PProOrNewer 0x0009 +%define BS3CPU_TYPE_MASK 0x00ff +%define BS3CPU_F_CPUID 0x0100 +%define BS3CPU_F_CPUID_EXT_LEAVES 0x0200 +%define BS3CPU_F_PAE 0x0400 +%define BS3CPU_F_PAE_BIT 10 +%define BS3CPU_F_PSE 0x0800 +%define BS3CPU_F_PSE_BIT 11 +%define BS3CPU_F_LONG_MODE 0x1000 +%define BS3CPU_F_LONG_MODE_BIT 12 +%define BS3CPU_F_NX 0x2000 +%define BS3CPU_F_NX_BIT 13 +;; @} + +%endif + diff --git a/src/VBox/ValidationKit/bootsectors/todo.txt b/src/VBox/ValidationKit/bootsectors/todo.txt new file mode 100644 index 00000000..0d8d407d --- /dev/null +++ b/src/VBox/ValidationKit/bootsectors/todo.txt @@ -0,0 +1,10 @@ +$Id: todo.txt $ + +Tripple fault variations: + - VT-x + NP: #PF w/ bad 32-bit IDT (set u1DescType=1). Injection causes #GP(73) loop. (r63775 cpu-pf-1) + - HWACCM (?): Enable PAE with bad PDPE for the next instr/jmp. Loops in at least one setup. + +Special General Protection Faults: + - Bad IDT entry. For instance X86DESCGATE::u1DescType = 1 (!system) of the #PF + entry and trigger a page fault. VT-x then tries to raise #GP(0x73). + |