summaryrefslogtreecommitdiffstats
path: root/src/VBox/ValidationKit/bootsectors
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-06 03:01:46 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-06 03:01:46 +0000
commitf8fe689a81f906d1b91bb3220acde2a4ecb14c5b (patch)
tree26484e9d7e2c67806c2d1760196ff01aaa858e8c /src/VBox/ValidationKit/bootsectors
parentInitial commit. (diff)
downloadvirtualbox-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')
-rw-r--r--src/VBox/ValidationKit/bootsectors/Config.kmk940
-rw-r--r--src/VBox/ValidationKit/bootsectors/Makefile.kmk364
-rw-r--r--src/VBox/ValidationKit/bootsectors/VBoxBs2Linker.cpp219
-rw-r--r--src/VBox/ValidationKit/bootsectors/bootsector-empty.asm60
-rw-r--r--src/VBox/ValidationKit/bootsectors/bootsector-pae.asm165
-rw-r--r--src/VBox/ValidationKit/bootsectors/bootsector-shutdown.asm80
-rw-r--r--src/VBox/ValidationKit/bootsectors/bootsector2-api.mac152
-rw-r--r--src/VBox/ValidationKit/bootsectors/bootsector2-boot-registers-1.asm76
-rw-r--r--src/VBox/ValidationKit/bootsectors/bootsector2-common-end.mac42
-rw-r--r--src/VBox/ValidationKit/bootsectors/bootsector2-common-init-code.mac2303
-rw-r--r--src/VBox/ValidationKit/bootsectors/bootsector2-common-init-traps.mac1609
-rw-r--r--src/VBox/ValidationKit/bootsectors/bootsector2-common-macros-1.mac50
-rw-r--r--src/VBox/ValidationKit/bootsectors/bootsector2-common-routines-template-1.mac2645
-rw-r--r--src/VBox/ValidationKit/bootsectors/bootsector2-common-routines-template-2.mac214
-rw-r--r--src/VBox/ValidationKit/bootsectors/bootsector2-common-routines.mac222
-rw-r--r--src/VBox/ValidationKit/bootsectors/bootsector2-common-traprec-template.mac105
-rw-r--r--src/VBox/ValidationKit/bootsectors/bootsector2-common-traprec.mac199
-rw-r--r--src/VBox/ValidationKit/bootsectors/bootsector2-cpu-a20-1-template.mac375
-rw-r--r--src/VBox/ValidationKit/bootsectors/bootsector2-cpu-a20-1.asm376
-rw-r--r--src/VBox/ValidationKit/bootsectors/bootsector2-cpu-ac-loop.asm115
-rw-r--r--src/VBox/ValidationKit/bootsectors/bootsector2-cpu-basic-1-template.mac74
-rw-r--r--src/VBox/ValidationKit/bootsectors/bootsector2-cpu-basic-1.asm119
-rw-r--r--src/VBox/ValidationKit/bootsectors/bootsector2-cpu-db-loop.asm151
-rw-r--r--src/VBox/ValidationKit/bootsectors/bootsector2-cpu-hidden-regs-1-template.mac342
-rw-r--r--src/VBox/ValidationKit/bootsectors/bootsector2-cpu-hidden-regs-1.asm275
-rw-r--r--src/VBox/ValidationKit/bootsectors/bootsector2-cpu-instr-1-template.mac314
-rw-r--r--src/VBox/ValidationKit/bootsectors/bootsector2-cpu-instr-1.asm110
-rw-r--r--src/VBox/ValidationKit/bootsectors/bootsector2-cpu-pf-1-template.mac1051
-rw-r--r--src/VBox/ValidationKit/bootsectors/bootsector2-cpu-pf-1.asm154
-rw-r--r--src/VBox/ValidationKit/bootsectors/bootsector2-cpu-xcpt-1-template.mac1963
-rw-r--r--src/VBox/ValidationKit/bootsectors/bootsector2-cpu-xcpt-1.asm128
-rw-r--r--src/VBox/ValidationKit/bootsectors/bootsector2-cpu-xcpt-2-template.mac501
-rw-r--r--src/VBox/ValidationKit/bootsectors/bootsector2-cpu-xcpt-2.asm119
-rw-r--r--src/VBox/ValidationKit/bootsectors/bootsector2-first.mac74
-rw-r--r--src/VBox/ValidationKit/bootsectors/bootsector2-structures.mac91
-rw-r--r--src/VBox/ValidationKit/bootsectors/bootsector2-template-footer.mac106
-rw-r--r--src/VBox/ValidationKit/bootsectors/bootsector2-template-header.mac793
-rw-r--r--src/VBox/ValidationKit/bootsectors/bootsector2-test1-template.mac756
-rw-r--r--src/VBox/ValidationKit/bootsectors/bootsector2-test1.asm187
-rw-r--r--src/VBox/ValidationKit/bootsectors/bootsector2-triple-fault-1.asm380
-rw-r--r--src/VBox/ValidationKit/bootsectors/bootsector2-vbinstst-64-1.asm111
-rw-r--r--src/VBox/ValidationKit/bootsectors/bootsector2-vbinstst-big-template.asm81
-rw-r--r--src/VBox/ValidationKit/bootsectors/bootsector2-vbinstst-kernel.asm517
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3-cpu-basic-2-32.c3256
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3-cpu-basic-2-asm.asm159
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3-cpu-basic-2-pf.c321880
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3-cpu-basic-2-template.c1538
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3-cpu-basic-2-template.mac405
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3-cpu-basic-2-x0.c3225
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3-cpu-basic-2.c92
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3-cpu-decoding-1-asm.asm39
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3-cpu-decoding-1-template.c58
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3-cpu-decoding-1-template.mac114
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3-cpu-decoding-1.c321726
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3-cpu-generated-1-asm.asm34
-rwxr-xr-xsrc/VBox/ValidationKit/bootsectors/bs3-cpu-generated-1-data.py644
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3-cpu-generated-1-template.c6141
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3-cpu-generated-1.c59
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3-cpu-generated-1.h805
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3-cpu-instr-2-asm.asm62
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3-cpu-instr-2-template.c1038
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3-cpu-instr-2-template.mac286
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3-cpu-instr-2.c74
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3-cpu-weird-1-asm.asm59
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3-cpu-weird-1-template.mac111
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3-cpu-weird-1-x0.c521
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3-cpu-weird-1.c64
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3-fpustate-1-asm.asm162
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3-fpustate-1-template.c302
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3-fpustate-1-template.mac330
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3-fpustate-1.c84
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/Makefile.kmk679
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/VBoxBs3Linker.cpp328
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/VBoxBs3ObjConverter.cpp5499
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/asmdefs-first.mac52
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-bootsector.asm396
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-c16-CreateHybridFarRet.asm53
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-c16-SwitchFromV86To16BitAndCallC.asm99
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-c16-Trap16Generic.asm710
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-c16-TrapRmV86Data.c43
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-c16-TrapRmV86Generic.asm391
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-c32-Trap32Generic.asm536
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-c64-Trap64Generic.asm327
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-A20Disable.asm105
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-A20Enable.asm112
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-ConvertRMStackToP16UsingCxReturnToAx.asm78
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-CpuDetectData.c44
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-ExtCtxAlloc.c44
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-ExtCtxCopy.c43
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-ExtCtxFree.c46
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-ExtCtxGetSize.c59
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-ExtCtxInit.c62
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-ExtCtxRestore.asm124
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-ExtCtxSave.asm130
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-GetCpuVendor.c51
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-GetModeName.c62
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-GetModeNameShortLower.c62
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-KbdRead.asm65
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-KbdWait.asm54
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-KbdWrite.asm72
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-MemAlloc.c101
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-MemAllocZ.c43
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-MemChr.asm78
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-MemCmp.asm89
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-MemCpy.c75
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-MemFree.c63
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-MemGuardedTestPage.c99
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-MemMove.c78
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-MemPCpy.c48
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-MemPrintInfo.c85
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-MemSet.asm92
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-MemZero.asm93
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-PagingAlias.c183
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-PagingData.c49
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-PagingInitRootForLM.c105
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-PagingInitRootForPAE.c92
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-PagingInitRootForPP.c153
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-PagingProtect.c382
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-PagingQueryAddressInfo.c149
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-PagingSetupCanonicalTraps.c113
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-Panic.asm38
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-PerCpuData.c64
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-PicMaskAll.c41
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-PicSetup.c80
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-PicUpdateMask.c45
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-PitIrqHandler.c67
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-PrintChr.asm105
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-PrintStr.c34
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-PrintStrN.asm194
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-PrintU32.asm83
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-PrintX32.asm87
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-Printf.c85
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-RegCtxConvertToRingX.c169
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-RegCtxPrint.c67
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-RegCtxRestore.asm596
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-RegCtxSave.asm261
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-RegCtxSaveEx.asm450
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-RegCtxSetGrpSegFromCurPtr.c50
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-RegCtxSetGrpSegFromFlat.c65
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-RegCtxSetRipCsFromCurPtr.c43
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-RegCtxSetRipCsFromFlat.c65
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-RegCtxSetRipCsFromLnkPtr.c77
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-RegGetCr0.asm79
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-RegGetCr2.asm79
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-RegGetCr3.asm79
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-RegGetCr4.asm79
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-RegGetDr0.asm79
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-RegGetDr1.asm79
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-RegGetDr2.asm79
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-RegGetDr3.asm79
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-RegGetDr6.asm79
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-RegGetDr7.asm79
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-RegGetDrX.asm125
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-RegGetLdtr.asm70
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-RegGetTr.asm70
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-RegSetCr0.asm86
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-RegSetCr2.asm86
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-RegSetCr3.asm86
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-RegSetCr4.asm86
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-RegSetDr0.asm86
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-RegSetDr1.asm86
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-RegSetDr2.asm86
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-RegSetDr3.asm86
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-RegSetDr6.asm86
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-RegSetDr7.asm86
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-RegSetDrX.asm132
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-RegSetLdtr.asm81
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-RegSetTr.asm96
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-SelFar32ToFlat32.c37
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-SelFar32ToFlat32NoClobber.asm104
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-SelFlatCodeToProtFar16.asm118
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-SelFlatCodeToRealMode.asm153
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-SelFlatDataToProtFar16.asm132
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-SelFlatDataToRealMode.asm94
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-SelProtFar16DataToFlat.asm90
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-SelProtFar16DataToRealMode.asm147
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-SelProtFar32ToFlat32.c45
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-SelProtModeCodeToRealMode.asm112
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-SelRealModeCodeToProtMode.asm84
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-SelRealModeDataToFlat.asm91
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-SelRealModeDataToProtFar16.asm141
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-SelSetup16BitCode.c51
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-SelSetup16BitData.c51
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-Shutdown.asm53
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-SlabAlloc.c54
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-SlabAllocEx.c101
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-SlabFree.c59
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-SlabInit.c62
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-SlabListAdd.c43
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-SlabListAlloc.c57
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-SlabListAllocEx.c58
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-SlabListFree.c54
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-SlabListInit.c40
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-StrCpy.c41
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-StrFormatV.c779
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-StrLen.c37
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-StrNLen.c37
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-StrPrintf.c95
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-SwitchHlpConvFlatRetToRetfProtMode.asm68
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-SwitchHlpConvProtModeRetfPopBpDecBpAndReturn.asm116
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-SwitchHlpConvRealModeRetfPopBpDecBpAndReturn.asm99
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-SwitchTo16Bit.asm120
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-SwitchTo16BitV86.asm123
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-SwitchTo32Bit.asm152
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-SwitchTo64Bit.asm110
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-SwitchToRing0.asm63
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-SwitchToRing1.asm63
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-SwitchToRing2.asm63
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-SwitchToRing3.asm63
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-SwitchToRingX.asm93
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-Syscall.asm84
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-TestCheckRegCtxEx.c97
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-TestData.c111
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-TestDoModesByOneHlp.asm243
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-TestFailed.c141
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-TestHostPrintf.c104
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-TestInit.c67
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-TestIsVmmDevTestingPresent.asm68
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-TestPrintf.c136
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-TestSendCmdWithStr.asm80
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-TestSendCmdWithU32.asm78
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-TestSkipped.c90
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-TestSub.c95
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-TestSubDone.c44
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-TestSubErrorCount.c44
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-TestTerm.c107
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-Trap16Init.c119
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-Trap16SetGate.c52
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-Trap32Init.c91
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-Trap32SetGate.c52
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-Trap64Init.c67
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-Trap64SetGate.c55
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-TrapDefaultHandler.c313
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-TrapHandlersData.asm40
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-TrapPrintFrame.c79
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-TrapReInit.c55
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-TrapRmV86Init.c110
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-TrapRmV86SetGate.c41
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-TrapSetDpl.c47
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-TrapSetHandler.c47
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-TrapSetHandlerEx.c61
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-TrapSetJmp.asm133
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-TrapSetJmpAndRestore.c46
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-TrapUnsetJmp.c48
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-UInt32Div.c40
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-UInt64Div.c40
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-UtilSetFullGdtr.asm185
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-UtilSetFullIdtr.asm185
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-hexdigits.c32
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-instantiate-common.h204
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-instantiate-x0.c1629
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-instantiate-x1.c1629
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-instantiate.c1629
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-instantiate.c3229
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-instantiate.c6429
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-memory.h99
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-paging.h59
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-pic-data.c42
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-pic.h60
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-pit.c156
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-test.h169
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-first-common.mac271
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-first-dosexe.asm33
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-first-init-all-pe32.asm59
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-first-init-all-pp32.asm59
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-first-pe16.asm95
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-first-rm.asm49
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-CpuDetect.asm337
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-EnteredMode.asm269
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-Name.asm34
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-NameShortLower.asm36
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-PagingGetRootForLM64.asm131
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-PagingGetRootForPAE16.asm45
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-PagingGetRootForPAE32.asm117
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-PagingGetRootForPP16.asm45
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-PagingGetRootForPP32.asm132
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-SwitchTo32BitAndCallC.asm154
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-SwitchToLM16.asm126
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-SwitchToLM32.asm193
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-SwitchToLM64.asm104
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-SwitchToPAE16.asm233
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-SwitchToPAE16_32.asm104
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-SwitchToPAE16_V86.asm114
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-SwitchToPAE32.asm192
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-SwitchToPAE32_16.asm122
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-SwitchToPAEV86.asm108
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-SwitchToPE16.asm188
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-SwitchToPE16_32.asm104
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-SwitchToPE16_V86.asm114
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-SwitchToPE32.asm169
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-SwitchToPE32_16.asm122
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-SwitchToPEV86.asm108
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-SwitchToPP16.asm248
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-SwitchToPP16_32.asm104
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-SwitchToPP16_V86.asm114
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-SwitchToPP32.asm199
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-SwitchToPP32_16.asm122
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-SwitchToPPV86.asm108
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-SwitchToRM.asm398
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-TestDoModes.c370
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-TestDoModes.h89
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-TestDoModesByMax.c370
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-TestDoModesByMaxStub.asm53
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-TestDoModesByOne.c404
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-TestDoModesByOneStub.asm53
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-TestDoModesHlp.asm1129
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-TestDoModesStub.asm53
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-TrapInit.c51
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-TrapSystemCallHandler.asm879
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-rm-InitAll.c90
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-rm-InitGdt.c61
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-rm-InitMemory.c372
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-shutdown.c77
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-system-data.asm1046
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-wc16-I4D.asm70
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-wc16-I8DQ.asm111
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-wc16-I8DR.asm111
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-wc16-I8RS.asm68
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-wc16-U4D.asm114
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-wc16-U8DQ.asm114
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-wc16-U8DR.asm114
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-wc16-U8LS.asm70
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-wc16-U8RS.asm72
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-wc32-I8D.asm71
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-wc32-I8RS.asm60
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-wc32-U8D.asm71
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-wc32-U8LS.asm62
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3-wc32-U8RS.asm60
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3cpudt.c61
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3kit-autostubs.kmk143
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3kit-docs.c160
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3kit-mangling-code-define.h203
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3kit-mangling-code-undef.h203
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3kit-mangling-code.h42
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3kit-mangling-data.h285
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3kit-template-footer.h83
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3kit-template-footer.mac132
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3kit-template-header.h522
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3kit-template-header.mac522
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3kit.h3957
-rw-r--r--src/VBox/ValidationKit/bootsectors/bs3kit/bs3kit.mac1750
-rw-r--r--src/VBox/ValidationKit/bootsectors/todo.txt10
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).
+