Index: trunk/src/VBox/ValidationKit/bootsectors/bs3kit/Makefile.kmk
===================================================================
--- trunk/src/VBox/ValidationKit/bootsectors/bs3kit/Makefile.kmk	(revision 102150)
+++ trunk/src/VBox/ValidationKit/bootsectors/bs3kit/Makefile.kmk	(revision 102157)
@@ -42,5 +42,5 @@
 # Boot Sector post-link tool (used via the parent Config.kmk).
 BLDPROGS += VBoxBs3Linker
-VBoxBs3Linker_TEMPLATE = VBoxBldProg
+VBoxBs3Linker_TEMPLATE = VBoxAdvBldProg
 VBoxBs3Linker_SOURCES  = $(VBOX_PATH_BS3KIT_SRC)/VBoxBs3Linker.cpp
 
@@ -204,4 +204,5 @@
 	bs3-cmn-SlabAlloc.c \
 	bs3-cmn-SlabAllocEx.c \
+	bs3-cmn-SlabAllocFixed.c \
 	bs3-cmn-SlabFree.c \
 	bs3-cmn-SlabListInit.c \
@@ -299,6 +300,8 @@
 	bs3-system-data.asm \
 	bs3-rm-InitAll.c \
+	bs3-rm-InitAllWithHighDlls.c \
 	bs3-rm-InitMemory.c \
 	bs3-rm-InitGdt.c \
+	bs3-rm-InitHighDlls.c \
 	bs3-cmn-hexdigits.c \
 	bs3-cmn-CpuDetectData.c \
@@ -370,4 +373,5 @@
 #
 VBOX_BS3KIT_MODE_SOURCES = \
+	bs3-mode-MemCopyFlat.asm \
 	bs3-mode-Name.asm \
 	bs3-mode-NameShortLower.asm \
@@ -408,5 +412,7 @@
 	bs3-mode-TestDoModesByMax.c \
 	bs3-mode-TestDoModesHlp.asm \
-	bs3-mode-BiosInt15hE820.asm
+	bs3-mode-BiosInt15hE820.asm \
+	bs3-mode-DiskQueryGeometry.asm \
+	bs3-mode-DiskRead.asm
 
 # The 16-bit real mode BS3Kit library.
Index: trunk/src/VBox/ValidationKit/bootsectors/bs3kit/VBoxBs3Linker.cpp
===================================================================
--- trunk/src/VBox/ValidationKit/bootsectors/bs3kit/VBoxBs3Linker.cpp	(revision 102150)
+++ trunk/src/VBox/ValidationKit/bootsectors/bs3kit/VBoxBs3Linker.cpp	(revision 102157)
@@ -40,8 +40,18 @@
 *********************************************************************************************************************************/
 #include <stdio.h>
-#include <string.h>
 #include <stdlib.h>
-#include <iprt/types.h>
+
 #include <iprt/assert.h>
+#include <iprt/err.h>
+#include <iprt/file.h>
+#include <iprt/getopt.h>
+#include <iprt/initterm.h>
+#include <iprt/ldr.h>
+#include <iprt/mem.h>
+#include <iprt/message.h>
+#include <iprt/path.h>
+#include <iprt/string.h>
+
+#include "bs3kit-linker.h"
 
 
@@ -49,292 +59,437 @@
 *   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;
-
+typedef struct BS3LNKINPUT
+{
+    const char     *pszFile;
+    FILE           *pFile;
+    uint32_t        cbFile;
+    uint32_t        cbBits;
+    uint32_t        uLoadAddr;
+    uint32_t        offInImage;
+    void           *pvBits;
+    RTLDRMOD        hLdrMod;
+} BS3LNKINPUT;
+
+
+typedef struct BS3LNKIMPORTSTATE
+{
+    FILE           *pOutput;
+    RTSTRSPACE      hImportNames;
+    unsigned        cImports;
+    unsigned        cExports;
+    size_t          cbStrings;
+} BS3LNKIMPORTSTATE;
+
+typedef struct BS3LNKIMPORTNAME
+{
+    RTSTRSPACECORE  Core;
+    size_t          offString;
+    RT_FLEXIBLE_ARRAY_EXTENSION
+    char            szName[RT_FLEXIBLE_ARRAY];
+} BS3LNKIMPORTNAME;
+
+
+
+/**
+ * @callback_method_impl{FNRTLDRENUMSYMS}
+ */
+static DECLCALLBACK(int) GenerateHighDllAsmOutputExportTable(RTLDRMOD hLdrMod, const char *pszSymbol, unsigned uSymbol,
+                                                             RTLDRADDR Value, void *pvUser)
+{
+    BS3LNKIMPORTSTATE * const pState = (BS3LNKIMPORTSTATE *)pvUser;
+    if (!pszSymbol || !*pszSymbol)
+        return RTMsgErrorRc(VERR_LDR_BAD_FIXUP, "All exports must be by name. uSymbol=%#x Value=%RX64", uSymbol, (uint64_t)Value);
+
+    // BS3HIGHDLLEXPORTENTRY
+    fprintf(pState->pOutput,
+            "g_pfn%s:\n"
+            "        dd      0\n"
+            "        dd      %#08x\n",
+            pszSymbol, (unsigned)pState->cbStrings);
+    pState->cbStrings += strlen(pszSymbol) + 1;
+    pState->cExports  += 1;
+
+    RT_NOREF(hLdrMod);
+    return VINF_SUCCESS;
+}
+
+/**
+ * @callback_method_impl{FNRTSTRSPACECALLBACK}
+ */
+static DECLCALLBACK(int) GenerateHighDllAsmOutputImportTable(PRTSTRSPACECORE pStr, void *pvUser)
+{
+    FILE             *pOutput = (FILE *)pvUser;
+    BS3LNKIMPORTNAME *pName   = (BS3LNKIMPORTNAME *)pStr;
+
+    // BS3HIGHDLLIMPORTENTRY
+    fprintf(pOutput,
+            "        dw      %#06x\n"
+            "        dw      seg %s\n"
+            "        dd      %s wrt BS3FLAT\n"
+            , (unsigned)pName->offString, pName->szName, pName->szName);
+
+    return VINF_SUCCESS;
+}
+
+
+/**
+ * @callback_method_impl{FNRTLDRENUMSYMS}
+ */
+static DECLCALLBACK(int) GenerateHighDllAsmOutputExportStrings(RTLDRMOD hLdrMod, const char *pszSymbol, unsigned uSymbol,
+                                                               RTLDRADDR Value, void *pvUser)
+{
+    BS3LNKIMPORTSTATE * const pState = (BS3LNKIMPORTSTATE *)pvUser;
+    if (!pszSymbol || !*pszSymbol)
+        return RTMsgErrorRc(VERR_LDR_BAD_FIXUP, "All exports must be by name. uSymbol=%#x Value=%RX64", uSymbol, (uint64_t)Value);
+
+    fprintf(pState->pOutput, "        db      '%s', 0\n", pszSymbol);
+    pState->cbStrings += strlen(pszSymbol) + 1;
+
+    RT_NOREF(hLdrMod);
+    return VINF_SUCCESS;
+}
+
+
+/**
+ * @callback_method_impl{FNRTSTRSPACECALLBACK}
+ */
+static DECLCALLBACK(int) GenerateHighDllAsmOutputImportStrings(PRTSTRSPACECORE pStr, void *pvUser)
+{
+    BS3LNKIMPORTSTATE * const pState = (BS3LNKIMPORTSTATE *)pvUser;
+    BS3LNKIMPORTNAME  * const pName   = (BS3LNKIMPORTNAME *)pStr;
+
+    pName->offString = pState->cbStrings;
+    fprintf(pState->pOutput, "        db      '%s', 0\n", pName->szName);
+    pState->cbStrings += pName->Core.cchString + 1;
+
+    return VINF_SUCCESS;
+}
+
+
+/**
+ * @callback_method_impl{FNRTLDRIMPORT}
+ */
+static DECLCALLBACK(int) GenerateHighDllAsmImportCallback(RTLDRMOD hLdrMod, const char *pszModule, const char *pszSymbol,
+                                                          unsigned uSymbol, PRTLDRADDR pValue, void *pvUser)
+{
+    BS3LNKIMPORTSTATE *pState = (BS3LNKIMPORTSTATE *)pvUser;
+    if (!pszSymbol)
+        return RTMsgErrorRc(VERR_LDR_BAD_FIXUP, "All imports must be by name. pszModule=%s uSymbol=%#x", pszModule, uSymbol);
+    if (!RTStrSpaceGet(&pState->hImportNames, pszSymbol))
+    {
+        size_t const           cchSymbol = strlen(pszSymbol);
+        BS3LNKIMPORTNAME * const pName   = (BS3LNKIMPORTNAME *)RTMemAlloc(RT_UOFFSETOF_DYN(BS3LNKIMPORTNAME,
+                                                                                           szName[cchSymbol + 1]));
+        AssertReturn(pName, VERR_NO_MEMORY);
+
+        pName->Core.cchString = cchSymbol;
+        pName->Core.pszString = (char *)memcpy(pName->szName, pszSymbol, cchSymbol + 1);
+        pName->offString      = UINT16_MAX;
+
+        AssertReturnStmt(RTStrSpaceInsert(&pState->hImportNames, &pName->Core), RTMemFree(pName),
+                         RTMsgErrorRc(VERR_INTERNAL_ERROR, "IPE #1"));
+        pState->cImports++;
+    }
+    *pValue = 0x10042;
+    RT_NOREF(hLdrMod);
+    return VINF_SUCCESS;
+}
+
+
+static RTEXITCODE GenerateHighDllImportTableAssembly(FILE *pOutput, const char *pszGenAsmFor)
+{
+    RTERRINFOSTATIC ErrInfo;
+    RTLDRMOD        hLdrMod;
+    int rc = RTLdrOpenEx(pszGenAsmFor, 0, RTLDRARCH_X86_32, &hLdrMod, RTErrInfoInitStatic(&ErrInfo));
+    if (RT_FAILURE(rc))
+        return RTMsgErrorExitFailure("RTLdrOpenEx failed to open '%s': %Rrc%#RTeim", pszGenAsmFor, rc, &ErrInfo.Core);
+
+    RTEXITCODE rcExit;
+    size_t cbImage = RTLdrSize(hLdrMod);
+    if (cbImage != ~(size_t)0)
+    {
+        void *pvBits = RTMemAlloc(cbImage);
+        if (pvBits)
+        {
+            BS3LNKIMPORTSTATE State = { pOutput, NULL, 0, 0, 0 };
+            rc = RTLdrGetBits(hLdrMod, pvBits, BS3HIGHDLL_LOAD_ADDRESS, GenerateHighDllAsmImportCallback, pOutput);
+            if (RT_SUCCESS(rc))
+            {
+                /** @todo move more of this to bs3kit*.h?    */
+                fprintf(pOutput,
+                        ";\n"
+                        "; Automatically generated - DO NOT MODIFY!\n"
+                        ";\n"
+                        "%%include \"bs3kit.mac\"\n"
+                        "\n"
+                        "section BS3HIGHDLLEXPORTS   align=4 CLASS=BS3HIGHDLLCLASS PUBLIC USE32 FLAT\n"
+                        "section BS3HIGHDLLIMPORTS   align=4 CLASS=BS3HIGHDLLCLASS PUBLIC USE32 FLAT\n"
+                        "section BS3HIGHDLLSTRINGS   align=4 CLASS=BS3HIGHDLLCLASS PUBLIC USE32 FLAT\n"
+                        "section BS3HIGHDLLTABLE     align=4 CLASS=BS3HIGHDLLCLASS PUBLIC USE32 FLAT\n"
+                        "section BS3HIGHDLLTABLE_END align=4 CLASS=BS3HIGHDLLCLASS PUBLIC USE32 FLAT\n"
+                        "GROUP BS3HIGHDLLGROUP  BS3HIGHDLLIMPORTS BS3HIGHDLLEXPORTS BS3HIGHDLLSTRINGS BS3HIGHDLLTABLE BS3HIGHDLLTABLE_END\n"
+                        "\n");
+
+                /* Populate the string table with imports. */
+                const char *pszFilename = RTPathFilename(pszGenAsmFor);
+                fprintf(pOutput,
+                        "section BS3HIGHDLLSTRINGS\n"
+                        "start_strings:\n"
+                        "        db      0\n"
+                        "        db      '%s', 0    ; module name\n"
+                        "        ; imports\n",
+                        pszFilename);
+                State.cbStrings = 1 + strlen(pszFilename) + 1;
+                rc = RTStrSpaceEnumerate(&State.hImportNames, GenerateHighDllAsmOutputImportStrings, &State);
+                AssertRC(rc);
+                fprintf(pOutput, "        ; exports\n");
+
+                /* Populate the string table with exports. */
+                size_t const offExportStrings = State.cbStrings;
+                rc = RTLdrEnumSymbols(hLdrMod, 0, pvBits, BS3HIGHDLL_LOAD_ADDRESS, GenerateHighDllAsmOutputExportStrings, &State);
+                size_t const cbStrings        = State.cbStrings;
+                if (RT_SUCCESS(rc) && cbStrings < _64K)
+                {
+                    /* Output the import table. */
+                    fprintf(pOutput,
+                            "section BS3HIGHDLLIMPORTS\n"
+                            "start_imports:\n");
+                    rc = RTStrSpaceEnumerate(&State.hImportNames, GenerateHighDllAsmOutputImportTable, &State);
+                    AssertRC(rc);
+                    fprintf(pOutput, "\n");
+
+                    /* Output the export table (ASSUMES stable enumeration order). */
+                    fprintf(pOutput,
+                            "section BS3HIGHDLLEXPORTS\n"
+                            "start_exports:\n");
+                    State.cbStrings = offExportStrings;
+                    rc = RTLdrEnumSymbols(hLdrMod, 0, pvBits, BS3HIGHDLL_LOAD_ADDRESS, GenerateHighDllAsmOutputExportTable, &State);
+                    AssertRC(rc);
+                    fprintf(pOutput, "\n");
+
+                    /* Generate the table entry. */
+                    fprintf(pOutput,
+                            "section BS3HIGHDLLTABLE\n"
+                            "start_entry: ; struct BS3HIGHDLLENTRY \n"
+                            "        db      '%s', 0    ; achMagic[8]\n"
+                            "        dd      0               ; uLoadAddress\n"
+                            "        dd      %#08zx        ; cbLoaded\n"
+                            "        dd      0               ; offInImage\n"
+                            "        dd      %#08zx        ; cbInImage\n"
+                            "        dd      %#04x            ; cImports\n"
+                            "        dd      start_imports - start_entry\n"
+                            "        dd      %#04x            ; cExports\n"
+                            "        dd      start_exports - start_entry\n"
+                            "        dd      %#05x           ; cbStrings\n"
+                            "        dd      start_strings - start_entry\n"
+                            "        dd      1               ; offDllName\n"
+                            , BS3HIGHDLLENTRY_MAGIC, cbImage, cbImage, State.cImports, State.cExports, (unsigned)cbStrings);
+                    rcExit = RTEXITCODE_SUCCESS;
+                }
+                else if (RT_FAILURE(rc))
+                    rcExit = RTMsgErrorExitFailure("RTLdrEnumSymbols failed: %Rrc", rc);
+                else
+                    rcExit = RTMsgErrorExitFailure("Too many import/export strings: %#x bytes, max 64KiB", cbStrings);
+            }
+            else
+                rcExit = RTMsgErrorExitFailure("RTLdrGetBits failed: %Rrc", rc);
+            RTMemFree(pvBits);
+        }
+        else
+            rcExit = RTMsgErrorExitFailure("Out of memory!");
+    }
+    else
+        rcExit = RTMsgErrorExitFailure("RTLdrSize failed on '%s'", pszGenAsmFor);
+
+    RTLdrClose(hLdrMod);
+    return rcExit;
+}
+
+
+static BS3HIGHDLLENTRY *LocateHighDllEntry(uint8_t const *pbBits, uint32_t cbBits, const char *pszFilename)
+{
     /*
-     * Scan the arguments.
+     * We search backwards for up to 4 KB.
      */
-    for (int i = 1; i < argc; i++)
-    {
-        if (argv[i][0] == '-')
+    size_t const offStop = cbBits > _4K ? cbBits - _4K : 0;
+    size_t       off     = cbBits >= sizeof(BS3HIGHDLLENTRY) ? cbBits - sizeof(BS3HIGHDLLENTRY) : 0;
+    while (off > offStop)
+    {
+        BS3HIGHDLLENTRY const *pEntry = (BS3HIGHDLLENTRY const *)&pbBits[off];
+        if (   pEntry->achMagic[0] == BS3HIGHDLLENTRY_MAGIC[0]
+            && memcmp(pEntry->achMagic, BS3HIGHDLLENTRY_MAGIC, sizeof(pEntry->achMagic)) == 0)
         {
-            const char *pszOpt = &argv[i][1];
-            if (*pszOpt == '-')
+            if (pEntry->cbStrings < _64K && pEntry->cbStrings >= 8)
             {
-                /* 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
+                if (off + pEntry->offStrings > 0 && off + pEntry->offStrings + pEntry->cbStrings <= off)
                 {
-                    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':
+                    if (off + pEntry->offExports > 0 && off + pEntry->offExports + pEntry->cExports * 8 <= off)
                     {
-                        const char *pszValue = pszOpt;
-                        pszOpt = strchr(pszOpt, '\0');
-                        if (*pszValue == '=')
-                            pszValue++;
-                        else if (!*pszValue)
+                        if (off + pEntry->offImports > 0 && off + pEntry->offImports + pEntry->cImports * 8 <= off)
                         {
-                            if (i + 1 >= argc)
+                            if (pEntry->offFilename > 0 && pEntry->offFilename < pEntry->cbStrings)
                             {
-                                fprintf(stderr, "syntax error: The --output option expects a filename.\n");
-                                free(paInputs);
-                                return 12;
+                                const char *psz = (const char *)&pbBits[off + pEntry->offStrings + pEntry->offFilename];
+                                if (strcmp(pszFilename, psz) == 0)
+                                    return (BS3HIGHDLLENTRY *)pEntry;
                             }
-                            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$");
-                        free(paInputs);
-                        return 0;
-
-                    case '?':
-                    case 'h':
-                        printf("usage: %s [options] -o <output> <input1> [input2 ... [inputN]]\n",
-                               argv[0]);
-                        free(paInputs);
-                        return 0;
                 }
             }
         }
+        off--;
+    }
+    RTMsgError("Failed to find the BS3HIGHDLLENTRY structure for '%s'!", pszFilename);
+    return NULL;
+}
+
+
+/**
+ * @callback_method_impl{FNRTLDRIMPORT}
+ */
+static DECLCALLBACK(int) ResolveHighDllImportCallback(RTLDRMOD hLdrMod, const char *pszModule, const char *pszSymbol,
+                                                      unsigned uSymbol, PRTLDRADDR pValue, void *pvUser)
+{
+    BS3HIGHDLLENTRY * const pEntry = (BS3HIGHDLLENTRY *)pvUser;
+    if (!pszSymbol)
+        return RTMsgErrorRc(VERR_LDR_BAD_FIXUP, "All imports must be by name. pszModule=%s uSymbol=%#x", pszModule, uSymbol);
+
+    /* Search the import table: */
+    BS3HIGHDLLIMPORTENTRY const *paImports   = (BS3HIGHDLLIMPORTENTRY const *)((uintptr_t)pEntry + pEntry->offImports);
+    const char * const           pszzStrings = (const char *)((uintptr_t)pEntry + pEntry->offStrings);
+    size_t i = pEntry->cImports;
+    while (i-- > 0)
+    {
+        if (strcmp(pszSymbol, &pszzStrings[paImports[i].offName]) == 0)
+        {
+            *pValue = paImports[i].offFlat;
+            return VINF_SUCCESS;
+        }
+    }
+    RT_NOREF(hLdrMod);
+    return RTMsgErrorRc(VERR_SYMBOL_NOT_FOUND, "Unable to locate import %s (in %s)!", pszSymbol, pszModule);
+}
+
+
+static RTEXITCODE DoTheLinking(FILE *pOutput, BS3LNKINPUT *paInputs, unsigned cInputs)
+{
+    if (cInputs < 2)
+        return RTMsgErrorExitFailure("Require at least two input files when linking!");
+
+    /*
+     * Read all the files into memory.
+     *
+     * The first two are binary blobs, i.e. the boot sector and the base image.
+     * Any additional files are DLLs and we need to do linking.
+     */
+    uint32_t uHiLoadAddr = BS3HIGHDLL_LOAD_ADDRESS;
+    uint32_t off         = 0;
+    for (unsigned i = 0; i < cInputs; i++)
+    {
+        paInputs[i].offInImage = off;
+        if (i < 2)
+        {
+            paInputs[i].cbBits = RT_ALIGN_32(paInputs[i].cbFile, 512);
+            paInputs[i].pvBits = RTMemAllocZ(paInputs[i].cbBits);
+            if (!paInputs[i].pvBits)
+                return RTMsgErrorExitFailure("Out of memory (%#x)\n", paInputs[i].cbBits);
+            size_t cbRead = fread(paInputs[i].pvBits, sizeof(uint8_t), paInputs[i].cbFile, paInputs[i].pFile);
+            if (cbRead != paInputs[i].cbFile)
+                return RTMsgErrorExitFailure("Error reading '%s' (got %d bytes, wanted %u).",
+                                             paInputs[i].pszFile, (int)cbRead, (unsigned)paInputs[i].cbFile);
+            paInputs[i].uLoadAddr = i == 90 ? 0x7c00 : 0x10000;
+        }
         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)
+            RTERRINFOSTATIC ErrInfo;
+            int rc = RTLdrOpenEx(paInputs[i].pszFile, 0, RTLDRARCH_X86_32, &paInputs[i].hLdrMod, RTErrInfoInitStatic(&ErrInfo));
+            if (RT_FAILURE(rc))
+                return RTMsgErrorExitFailure("RTLdrOpenEx failed to open '%s': %Rrc%#RTeim",
+                                             paInputs[i].pszFile, rc, &ErrInfo.Core);
+
+            size_t const cbImage = RTLdrSize(paInputs[i].hLdrMod);
+            if (cbImage == ~(size_t)0)
+                return RTMsgErrorExitFailure("RTLdrSize failed on '%s'!", paInputs[i].pszFile);
+            if (cbImage > _64M)
+                return RTMsgErrorExitFailure("Image '%s' is definitely too large: %#zx", paInputs[i].pszFile, cbImage);
+
+            paInputs[i].cbBits = RT_ALIGN_32((uint32_t)cbImage, 4096); /* Bs3InitHighDlls_rm depend on the 4KiB alignment.  */
+            paInputs[i].pvBits = RTMemAllocZ(paInputs[i].cbBits);
+            if (!paInputs[i].pvBits)
+                return RTMsgErrorExitFailure("Out of memory (%#x)\n", paInputs[i].cbBits);
+
+            /* Locate the entry for this high dll in the base image. */
+            BS3HIGHDLLENTRY *pHighDllEntry = LocateHighDllEntry((uint8_t *)paInputs[1].pvBits, paInputs[1].cbFile,
+                                                                RTPathFilename(paInputs[i].pszFile));
+            AssertReturn(pHighDllEntry, RTEXITCODE_FAILURE);
+
+            /* Get the fixed up image bits. */
+            rc = RTLdrGetBits(paInputs[i].hLdrMod, paInputs[i].pvBits, uHiLoadAddr, ResolveHighDllImportCallback, pHighDllEntry);
+            if (RT_FAILURE(rc))
+                return RTMsgErrorExitFailure("RTLdrGetBits failed on '%s': %Rrc", paInputs[i].pszFile, rc);
+
+            /* Update the export addresses. */
+            BS3HIGHDLLEXPORTENTRY *paExports   = (BS3HIGHDLLEXPORTENTRY *)((uintptr_t)pHighDllEntry + pHighDllEntry->offExports);
+            const char * const     pszzStrings = (const char *)((uintptr_t)pHighDllEntry + pHighDllEntry->offStrings);
+            size_t iExport = pHighDllEntry->cExports;
+            while (iExport-- > 0)
             {
-                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);
-                }
+                const char * const pszSymbol = (const char *)&pszzStrings[paExports[iExport].offName];
+                RTLDRADDR          Value     = 0;
+                rc = RTLdrGetSymbolEx(paInputs[i].hLdrMod, paInputs[i].pvBits, uHiLoadAddr, UINT32_MAX, pszSymbol, &Value);
+                if (RT_SUCCESS(rc))
+                    paExports[iExport].offFlat = (uint32_t)Value;
                 else
-                    fprintf(stderr, "error: seeking to end of '%s' failed\n", paInputs[cInputs].pszFile);
+                    return RTMsgErrorExitFailure("Failed to resolve '%s' in '%s': %Rrc", pszSymbol, paInputs[i].pszFile, rc);
             }
-            else
-                fprintf(stderr, "error: Failed to open input file '%s' for reading\n", paInputs[cInputs].pszFile);
-            if (pFile)
-            {
-                free(paInputs);
-                fclose(pFile);
-                return 1;
-            }
-            cInputs++;
+
+            /* Update the DLL entry with the load address and file address: */
+            pHighDllEntry->offInImage = off;
+            pHighDllEntry->uLoadAddr  = uHiLoadAddr;
+            paInputs[i].uLoadAddr     = uHiLoadAddr;
+            uHiLoadAddr += paInputs[i].cbBits;
         }
-    }
-
-    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;
-    }
+        Assert(!(off & 0x1ff));
+        off += paInputs[i].cbBits;
+        Assert(!(off & 0x1ff));
+    }
+
+    /** @todo image size check.   */
 
     /*
-     * Do the job.
+     * Patch the BPB with base image sector count.
      */
-    /* 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);
-
-    /* Avoid output sizes that makes the FDC code think it's a single sided
-       floppy.  The BIOS always report double sided floppies, and even if we
-       the bootsector adjust it's bMaxHeads value when getting a 20h error
-       we end up with a garbaged image (seems somewhere in the BIOS/FDC it is
-       still treated as a double sided floppy and we get half the data we want
-       and with gaps).
-
-       Similarly, if the size is 320KB or 360KB the FDC detects it as a double
-       sided 5.25" floppy with 40 tracks, while the BIOS keeps reporting a
-       1.44MB 3.5" floppy. So, just avoid those sizes too. */
+    PBS3BOOTSECTOR pBs = (PBS3BOOTSECTOR)paInputs[0].pvBits;
+    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 = (paInputs[0].cbBits + paInputs[1].cbBits) / 512;
+    else
+        return RTMsgErrorExitFailure("Didn't find magic strings in the first file (%s).", paInputs[0].pszFile);
+
+    /*
+     * Write out the image.
+     */
+    for (unsigned i = 0; i < cInputs; i++)
+    {
+        Assert(ftell(pOutput) == (int32_t)paInputs[i].offInImage);
+        ssize_t cbWritten = fwrite(paInputs[i].pvBits, sizeof(uint8_t), paInputs[i].cbBits, pOutput);
+        if (cbWritten != (ssize_t)paInputs[i].cbBits)
+            return RTMsgErrorExitFailure("fwrite failed (%zd vs %zu)", cbWritten, paInputs[i].cbBits);
+    }
+
+    /*
+     * Avoid output sizes that makes the FDC code think it's a single sided
+     * floppy.  The BIOS always report double sided floppies, and even if we
+     * the bootsector adjust it's bMaxHeads value when getting a 20h error
+     * we end up with a garbaged image (seems somewhere in the BIOS/FDC it is
+     * still treated as a double sided floppy and we get half the data we want
+     * and with gaps).
+     *
+     * Similarly, if the size is 320KB or 360KB the FDC detects it as a double
+     * sided 5.25" floppy with 40 tracks, while the BIOS keeps reporting a
+     * 1.44MB 3.5" floppy. So, just avoid those sizes too.
+     */
     uint32_t cbOutput = ftell(pOutput);
     if (   cbOutput == 512 * 8 * 40 * 1 /* 160kB 5"1/4 SS */
@@ -345,17 +500,176 @@
         static uint8_t const s_abZeroSector[512] = { 0 };
         if (fwrite(s_abZeroSector, sizeof(uint8_t), sizeof(s_abZeroSector), pOutput) != sizeof(s_abZeroSector))
+            return RTMsgErrorExitFailure("fwrite failed (padding)");
+    }
+
+    return RTEXITCODE_SUCCESS;
+}
+
+int main(int argc, char **argv)
+{
+    int rc = RTR3InitExe(argc, &argv, 0);
+    if (RT_FAILURE(rc))
+        return RTMsgInitFailure(rc);
+
+    /*
+     * Scan the arguments.
+     */
+    static const RTGETOPTDEF s_aOptions[] =
+    {
+        { "--output",                           'o', RTGETOPT_REQ_STRING },
+        { "--generate-high-dll-import-table",   'g', RTGETOPT_REQ_STRING },
+    };
+
+    const char  *pszOutput      = NULL;
+    const char  *pszGenAsmFor   = NULL;
+    BS3LNKINPUT  aInputs[3];                /* 3 = bootsector, low image, high image */
+    unsigned     cInputs        = 0;
+    uint32_t     cSectors       = 0;
+
+    RTGETOPTSTATE   GetState;
+    rc = RTGetOptInit(&GetState, argc, argv, s_aOptions, RT_ELEMENTS(s_aOptions), 1, RTGETOPTINIT_FLAGS_OPTS_FIRST);
+    AssertRCReturn(rc, RTEXITCODE_SYNTAX);
+    RTGETOPTUNION   ValueUnion;
+    int             ch;
+    while ((ch = RTGetOpt(&GetState, &ValueUnion)))
+    {
+        switch (ch)
         {
-            fprintf(stderr, "error: fwrite failed (padding)\n");
-            rcExit = 1;
+            case 'o':
+                if (pszOutput)
+                    return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Only one output file is allowed. You've specified '%s' and '%s'",
+                                          pszOutput, ValueUnion.psz);
+                pszOutput = ValueUnion.psz;
+                break;
+
+            case 'g':
+                if (pszGenAsmFor)
+                    return RTMsgErrorExit(RTEXITCODE_SYNTAX, "--generate-high-dll-import-table can only be used once (first for %s, now for %s)",
+                                          pszGenAsmFor, ValueUnion.psz);
+                pszGenAsmFor = ValueUnion.psz;
+                break;
+
+            case VINF_GETOPT_NOT_OPTION:
+            {
+                if (pszGenAsmFor)
+                    return RTMsgErrorExit(RTEXITCODE_SYNTAX, "--generate-high-dll-import-table don't take any non-option arguments!");
+
+                /*
+                 * Add to input file collection.
+                 */
+                if (cInputs >= RT_ELEMENTS(aInputs))
+                    return RTMsgErrorExitFailure("Too many input files!");
+                aInputs[cInputs].pszFile = ValueUnion.psz;
+#if defined(RT_OS_OS2) || defined(RT_OS_WINDOWS)
+                FILE *pFile = fopen(aInputs[cInputs].pszFile, "rb");
+#else
+                FILE *pFile = fopen(aInputs[cInputs].pszFile, "r");
+#endif
+                if (pFile)
+                {
+                    if (fseek(pFile, 0, SEEK_END) == 0)
+                    {
+                        aInputs[cInputs].cbFile = (uint32_t)ftell(pFile);
+                        if (fseek(pFile, 0, SEEK_SET) == 0)
+                        {
+                            if (cInputs != 0 || aInputs[cInputs].cbFile == 512)
+                            {
+                                cSectors += RT_ALIGN_32(aInputs[cInputs].cbFile, 512) / 512;
+                                if (cSectors <= BS3_MAX_SIZE / 512 || cInputs > 0)
+                                {
+                                    if (cSectors > 0)
+                                    {
+                                        aInputs[cInputs].pvBits  = NULL;
+                                        aInputs[cInputs].cbBits  = 0;
+                                        aInputs[cInputs].hLdrMod = NIL_RTLDRMOD;
+                                        aInputs[cInputs++].pFile = pFile;
+                                        pFile = NULL;
+                                        break;
+                                    }
+                                    RTMsgError("empty input file: '%s'", aInputs[cInputs].pszFile);
+                                }
+                                else
+                                    RTMsgError("input is too big: %u bytes, %u sectors (max %u bytes, %u sectors)\n"
+                                               "detected loading '%s'",
+                                               cSectors * 512, cSectors, BS3_MAX_SIZE, BS3_MAX_SIZE / 512,
+                                               aInputs[cInputs].pszFile);
+                            }
+                            else
+                                RTMsgError("first input file (%s) must be exactly 512 bytes", aInputs[cInputs].pszFile);
+                        }
+                        else
+                            RTMsgError("seeking to start of '%s' failed", aInputs[cInputs].pszFile);
+                    }
+                    else
+                        RTMsgError("seeking to end of '%s' failed", aInputs[cInputs].pszFile);
+                }
+                else
+                    RTMsgError("Failed to open input file '%s' for reading", aInputs[cInputs].pszFile);
+                if (pFile)
+                    fclose(pFile);
+                return RTEXITCODE_FAILURE;
+            }
+
+            case 'V':
+                printf("%s\n", "$Revision$");
+                return RTEXITCODE_SUCCESS;
+
+            case 'h':
+                printf("usage: %s --output <output> <basemod> [high-dll1... [high-dllN]]\n"
+                       "   or: %s --output <high-dll.asm> --generate-high-dll-import-table <some.high-dll>\n"
+                       "   or: %s --help\n"
+                       "   or: %s --version\n"
+                       , argv[0], argv[0], argv[0], argv[0]);
+                return RTEXITCODE_SUCCESS;
+
+            default:
+                return RTGetOptPrintError(ch, &ValueUnion);
         }
     }
+
+    if (!pszOutput)
+        return RTMsgErrorExit(RTEXITCODE_SYNTAX, "No output file was specified (-o or --output).");
+
+    if (cInputs == 0 && !pszGenAsmFor)
+        return RTMsgErrorExit(RTEXITCODE_SYNTAX, "No input files was specified.");
+
+    /*
+     * Do the job.
+     */
+    /* Open the output file */
+#if defined(RT_OS_OS2) || defined(RT_OS_WINDOWS)
+    FILE *pOutput = fopen(pszOutput, !pszGenAsmFor ? "wb" : "w");
+#else
+    FILE *pOutput = fopen(pszOutput, "w");
+#endif
+    if (!pOutput)
+        RTMsgErrorExitFailure("Failed to open output file '%s' for writing!", pszOutput);
+
+    RTEXITCODE rcExit;
+    if (pszGenAsmFor)
+        rcExit = GenerateHighDllImportTableAssembly(pOutput, pszGenAsmFor);
+    else
+        rcExit = DoTheLinking(pOutput, aInputs, cInputs);
 
     /* Finally, close the output file (can fail because of buffered data). */
     if (fclose(pOutput) != 0)
-    {
-        fprintf(stderr, "error: Error closing '%s'.\n", pszOutput);
-        rcExit = 1;
-    }
-
+        rcExit = RTMsgErrorExitFailure("Error closing '%s'!", pszOutput);
+
+    /* Delete the output file on failure. */
+    if (rcExit != RTEXITCODE_SUCCESS)
+        RTFileDelete(pszOutput);
+
+    /* Close the input files and free memory associated with them. */
+    for (unsigned i = 0; i < cInputs && rcExit == 0; i++)
+    {
+        if (aInputs[i].pFile)
+            fclose(aInputs[i].pFile);
+        if (aInputs[i].hLdrMod != NIL_RTLDRMOD)
+            RTLdrClose(aInputs[i].hLdrMod);
+        if (aInputs[i].pvBits)
+            RTMemFree(aInputs[i].pvBits);
+    }
+
+    /* Close stderr to make sure it's flushed properly. */
     fclose(stderr);
     return rcExit;
Index: trunk/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-SlabAllocFixed.c
===================================================================
--- trunk/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-SlabAllocFixed.c	(revision 102157)
+++ trunk/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-cmn-SlabAllocFixed.c	(revision 102157)
@@ -0,0 +1,72 @@
+/* $Id$ */
+/** @file
+ * BS3Kit - Bs3SlabAllocEx
+ */
+
+/*
+ * Copyright (C) 2007-2023 Oracle and/or its affiliates.
+ *
+ * This file is part of VirtualBox base platform packages, as
+ * available from https://www.virtualbox.org.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, in version 3 of the
+ * License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses>.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+ * in the VirtualBox distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+ */
+
+
+/*********************************************************************************************************************************
+*   Header Files                                                                                                                 *
+*********************************************************************************************************************************/
+#include "bs3kit-template-header.h"
+#include <iprt/asm.h>
+
+
+#undef Bs3SlabAllocFixed
+BS3_CMN_DEF(uint16_t, Bs3SlabAllocFixed,(PBS3SLABCTL pSlabCtl, uint32_t uFlatAddr, uint16_t cChunks))
+{
+    uint32_t iBit32 = (uFlatAddr - BS3_XPTR_GET_FLAT(void, pSlabCtl->pbStart)) >> pSlabCtl->cChunkShift;
+    if (iBit32 < pSlabCtl->cChunks)
+    {
+        uint16_t iBit = (uint16_t)iBit32;
+        uint16_t i;
+
+        /* If the slab doesn't cover the entire area requested, reduce it.
+           Caller can then move on to the next slab in the list to get the rest. */
+        if (pSlabCtl->cChunks - iBit < cChunks)
+            cChunks = pSlabCtl->cChunks - iBit;
+
+        /* Check that all the chunks are free. */
+        for (i = 0; i < cChunks; i++)
+            if (ASMBitTest(&pSlabCtl->bmAllocated, iBit + i))
+                return UINT16_MAX;
+
+        /* Complete the allocation. */
+        for (i = 0; i < cChunks; i++)
+            ASMBitSet(&pSlabCtl->bmAllocated, iBit + i);
+        pSlabCtl->cFreeChunks  -= cChunks;
+        return cChunks;
+    }
+    return 0;
+}
+
Index: trunk/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-first-common.mac
===================================================================
--- trunk/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-first-common.mac	(revision 102150)
+++ trunk/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-first-common.mac	(revision 102157)
@@ -52,6 +52,7 @@
 ;
 
-;
-; 16-bit text
+
+;                                                                      0x86a00
+; 16-bit text                                                 442368 = 0x6C000 (442368)
 ;
 %ifndef BS3_IS_DOS_EXE
@@ -111,6 +112,8 @@
 BS3_GLOBAL_DATA Bs3Text16_Size, 2
     dw  BS3_DATA_NM(Bs3Text16_EndOfSegment) wrt CGROUP16
+%ifndef BS3_IS_HIGH_IMAGE
 BS3_GLOBAL_DATA Bs3RmText16_Size, 2
     dw  BS3_DATA_NM(Bs3RmText16_EndOfSegment) wrt BS3GROUPRMTEXT16
+%endif ; !BS3_IS_HIGH_IMAGE
 BS3_GLOBAL_DATA Bs3X0Text16_Size, 2
     dw  BS3_DATA_NM(Bs3X0Text16_EndOfSegment) wrt BS3GROUPX0TEXT16
@@ -118,6 +121,8 @@
     dw  BS3_DATA_NM(Bs3X1Text16_EndOfSegment) wrt BS3GROUPX1TEXT16
 
+%ifndef BS3_IS_HIGH_IMAGE
 BS3_GLOBAL_DATA Bs3RmText16_FlatAddr, 4
     dd  BS3_DATA_NM(Bs3RmText16_StartOfSegment) wrt BS3FLAT
+%endif ; !BS3_IS_HIGH_IMAGE
 BS3_GLOBAL_DATA Bs3X0Text16_FlatAddr, 4
     dd  BS3_DATA_NM(Bs3X0Text16_StartOfSegment) wrt BS3FLAT
@@ -164,4 +169,5 @@
 %endif
 
+%ifndef BS3_IS_HIGH_IMAGE
 ;
 ; 16-bit real-mode text
@@ -174,5 +180,5 @@
 BS3_GLOBAL_DATA Bs3RmText16_EndOfSegment, 0
 GROUP BS3GROUPRMTEXT16 BS3RMTEXT16_START BS3RMTEXT16 BS3RMTEXT16_END
-
+%endif ; !BS3_IS_HIGH_IMAGE
 
 ;
@@ -199,4 +205,5 @@
 GROUP BS3GROUPX1TEXT16 BS3X1TEXT16_START BS3X1TEXT16 BS3X1TEXT16_END
 
+%ifndef BS3_IS_HIGH_IMAGE
 ;
 ; Separate the BS3X1TEXT16_END from BS3_BEGIN_TEXT32 to better help pinpoint
@@ -208,4 +215,5 @@
 BS3_GLOBAL_DATA BS3SEPARATE16AND32BITCODE_EndOfSegment, 0
 GROUP BS3SEPARATE16AND32BITCODEGROUP BS3SEPARATE16AND32BITCODE
+%endif ; !BS3_IS_HIGH_IMAGE
 
 
@@ -220,4 +228,5 @@
 
 
+%ifndef BS3_IS_HIGH_IMAGE
 ;
 ; This is a hack to separate the 32-bit and 64-bit text segments when linking,
@@ -230,4 +239,5 @@
 BS3_GLOBAL_DATA Bs3Separate32And64BitCode_EndOfSegment, 0
 GROUP BS3SEPARATE32AND64BITCODEGROUP BS3SEPARATE32AND64BITCODE
+%endif ; !BS3_IS_HIGH_IMAGE
 
 
@@ -276,4 +286,17 @@
 
 
+%ifndef BS3_IS_HIGH_IMAGE
+;
+; The high dll table segment.
+;
+section BS3HIGHDLLEXPORTS   align=4 CLASS=BS3HIGHDLLCLASS PUBLIC USE32 FLAT ;; @todo Consider moving this to DATA16...
+section BS3HIGHDLLIMPORTS   align=4 CLASS=BS3HIGHDLLCLASS PUBLIC USE32 FLAT
+section BS3HIGHDLLSTRINGS   align=4 CLASS=BS3HIGHDLLCLASS PUBLIC USE32 FLAT
+section BS3HIGHDLLTABLE     align=4 CLASS=BS3HIGHDLLCLASS PUBLIC USE32 FLAT
+BS3_GLOBAL_DATA g_aBs3HighDllTable, 0
+section BS3HIGHDLLTABLE_END align=4 CLASS=BS3HIGHDLLCLASS PUBLIC USE32 FLAT
+BS3_GLOBAL_DATA g_Bs3HighDllTable_End, 0
+GROUP BS3HIGHDLLGROUP  BS3HIGHDLLIMPORTS BS3HIGHDLLEXPORTS BS3HIGHDLLSTRINGS BS3HIGHDLLTABLE BS3HIGHDLLTABLE_END
+
 ;
 ; 16-bit accessible system data.
@@ -288,3 +311,4 @@
 BS3_BEGIN_TEXT16
 BS3_GLOBAL_NAME_EX Bs3KitEntryPoint, function, 0
-
+%endif ; !BS3_IS_HIGH_IMAGE
+
Index: trunk/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-first-high-image.asm
===================================================================
--- trunk/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-first-high-image.asm	(revision 102157)
+++ trunk/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-first-high-image.asm	(revision 102157)
@@ -0,0 +1,47 @@
+; $Id$
+;; @file
+; BS3Kit - First Object, high image.
+;
+; Defines segments and any standard symbols required by the compiler and linkers.
+;
+
+;
+; Copyright (C) 2007-2023 Oracle and/or its affiliates.
+;
+; This file is part of VirtualBox base platform packages, as
+; available from https://www.virtualbox.org.
+;
+; This program is free software; you can redistribute it and/or
+; modify it under the terms of the GNU General Public License
+; as published by the Free Software Foundation, in version 3 of the
+; License.
+;
+; This program is distributed in the hope that it will be useful, but
+; WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+; General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with this program; if not, see <https://www.gnu.org/licenses>.
+;
+; The contents of this file may alternatively be used under the terms
+; of the Common Development and Distribution License Version 1.0
+; (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+; in the VirtualBox distribution, in which case the provisions of the
+; CDDL are applicable instead of those of the GPL.
+;
+; You may elect to license modified versions of this file under the
+; terms and conditions of either the GPL or the CDDL or both.
+;
+; SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+;
+
+%ifndef BS3_IS_HIGH_IMAGE
+ %error "Only for targets with BS3_IS_HIGH_IMAGE defined!"
+%endif
+
+;
+; Segment defs, grouping and related variables.
+;
+%include "bs3-first-common.mac"
+
Index: trunk/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-BiosInt15hE820.asm
===================================================================
--- trunk/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-BiosInt15hE820.asm	(revision 102150)
+++ trunk/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-BiosInt15hE820.asm	(revision 102157)
@@ -172,5 +172,5 @@
         jc      .failed
         cmp     eax, INT15_E820_SIGNATURE
-        jc      .failed
+        jne     .failed
         cmp     ecx, 20
         jb      .failed
Index: trunk/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-DiskQueryGeometry.asm
===================================================================
--- trunk/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-DiskQueryGeometry.asm	(revision 102150)
+++ trunk/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-DiskQueryGeometry.asm	(revision 102157)
@@ -1,5 +1,5 @@
 ; $Id$
 ;; @file
-; BS3Kit - Bs3BiosInt15hE820
+; BS3Kit - Bs3DiskQueryGeometry
 ;
 
@@ -39,11 +39,4 @@
 ;*********************************************************************************************************************************
 %include "bs3kit-template-header.mac"
-
-
-;*********************************************************************************************************************************
-;*  Defined Constants And Macros                                                                                                 *
-;*********************************************************************************************************************************
-;; Signature: 'SMAP'
-%define INT15_E820_SIGNATURE    0534d4150h
 
 
@@ -118,23 +111,11 @@
         BS3_SET_BITS 16
 %endif
-        ; Ralf Brown suggest setting es:di to NULL before the call. This is also helpful
-        ; wrt to IVT manipulation (next step).
+
+        ;
+        ; Ralf Brown suggest setting es:di to NULL before the call.
+        ; Doubt this is really needed in our case, but whatever.
+        ;
         xor     di, di
         mov     es, di
-
-        ;
-        ; Save current and restore the original IVT[13h] entry.
-        ;
-        mov     si, seg g_aBs3RmIvtOriginal
-        mov     ds, si
-        mov     si, g_aBs3RmIvtOriginal
-
-        push    word [es:13h * 4]
-        mov     ax, [si + 13h * 4]
-        mov     [es:13h * 4], ax
-
-        push    word [es:13h * 4 + 2]
-        mov     ax, [si + 13h * 4 + 2]
-        mov     [es:13h * 4 + 2], ax
 
         ;
@@ -145,13 +126,4 @@
         mov     es, di
         int     13h
-
-        ;
-        ; Restore the modified IVT[13h] entry.
-        ; Must not touch EFLAGS.CF!
-        ;
-        push    word 0
-        pop     ds
-        pop     word [ds:13h * 4 + 2]
-        pop     word [ds:13h * 4]
 
         ;
Index: trunk/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-DiskRead.asm
===================================================================
--- trunk/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-DiskRead.asm	(revision 102157)
+++ trunk/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-mode-DiskRead.asm	(revision 102157)
@@ -0,0 +1,223 @@
+; $Id$
+;; @file
+; BS3Kit - Bs3DiskRead
+;
+
+;
+; Copyright (C) 2021-2023 Oracle and/or its affiliates.
+;
+; This file is part of VirtualBox base platform packages, as
+; available from https://www.virtualbox.org.
+;
+; This program is free software; you can redistribute it and/or
+; modify it under the terms of the GNU General Public License
+; as published by the Free Software Foundation, in version 3 of the
+; License.
+;
+; This program is distributed in the hope that it will be useful, but
+; WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+; General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with this program; if not, see <https://www.gnu.org/licenses>.
+;
+; The contents of this file may alternatively be used under the terms
+; of the Common Development and Distribution License Version 1.0
+; (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+; in the VirtualBox distribution, in which case the provisions of the
+; CDDL are applicable instead of those of the GPL.
+;
+; You may elect to license modified versions of this file under the
+; terms and conditions of either the GPL or the CDDL or both.
+;
+; SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+;
+
+;*********************************************************************************************************************************
+;*  Header Files                                                                                                                 *
+;*********************************************************************************************************************************
+%include "bs3kit-template-header.mac"
+
+
+;*********************************************************************************************************************************
+;*  External symbols                                                                                                             *
+;*********************************************************************************************************************************
+TMPL_BEGIN_TEXT
+extern TMPL_NM(Bs3SwitchToRM)
+BS3_BEGIN_TEXT16
+extern RT_CONCAT3(_Bs3SwitchTo,TMPL_MODE_UNAME,_Safe_rm)
+
+BS3_EXTERN_DATA16   g_aBs3RmIvtOriginal
+%ifdef TMPL_16BIT
+BS3_EXTERN_CMN      Bs3SelProtFar16DataToRealMode
+%else
+BS3_EXTERN_CMN      Bs3SelFlatDataToRealMode
+%endif
+
+
+
+;;
+; Performs a int 13h function 2 call.
+;
+; @cproto   BS3_MODE_PROTO_STUB(uint8_t, Bs3DiskRead,(uint8_t bDrive, uint16_t uCylinder, uint8_t uHead, uint8_t uSector,
+;                                                     uint8_t cSectors, void RT_FAR *pvBuf));
+;
+; @returns  Register value (ax/eax). Zero on success, non-zero on failure.
+;
+; @uses     No GPRs (only return full register(s)). In 64-bit mode DS and ES is trashed.
+;
+; @remarks  ASSUMES we're in ring-0 when not in some kind of real mode.
+; @remarks  ASSUMES we're on a 16-bit suitable stack.
+;
+TMPL_BEGIN_TEXT
+BS3_PROC_BEGIN_MODE Bs3DiskRead, BS3_PBC_HYBRID
+        push    xBP
+        mov     xBP, xSP
+;; @todo does not work on 286 and earlier!
+        sPUSHF
+        cli
+        push    sBX
+        push    sCX
+        push    sDX
+        push    sSI
+        push    sDI
+%ifndef TMPL_64BIT
+        push    ds
+        push    es
+%endif
+
+        ; Load/Save parameters.
+%define a_bDrive                [xBP + xCB + cbCurRetAddr + xCB*0]
+%define a_uCylinder             [xBP + xCB + cbCurRetAddr + xCB*1]
+%define a_uCylinderHi           [xBP + xCB + cbCurRetAddr + xCB*1 + 1]
+%define a_uHead                 [xBP + xCB + cbCurRetAddr + xCB*2]
+%define a_uSector               [xBP + xCB + cbCurRetAddr + xCB*3]
+%define a_cSectors              [xBP + xCB + cbCurRetAddr + xCB*4]
+%define a_pvBuf                 [xBP + xCB + cbCurRetAddr + xCB*5]
+%define a_pvBufSel              [xBP + xCB + cbCurRetAddr + xCB*5 + 2]
+
+%ifdef TMPL_64BIT
+        mov     a_bDrive, rcx           ; save bDrive
+        mov     a_uCylinder, rdx        ; save uCylinder
+        mov     a_uHead, r8             ; save uHead
+        mov     a_uSector, r9           ; save uSector
+        movzx   edx, cl                 ; dl = drive
+%else
+        mov     dl, a_bDrive            ; dl = drive
+%endif
+
+        ;
+        ; Convert buffer pointer if not in real mode.
+        ; Note! We clean the stack up in the epilogue.
+        ;
+%ifdef TMPL_64BIT
+        sub     rsp, 20h
+        mov     rcx, a_pvBuf
+        call    Bs3SelFlatDataToRealMode
+        mov     a_pvBuf, rax
+%elifdef TMPL_32BIT
+        mov     ecx, a_pvBuf
+        push    ecx
+        call    Bs3SelFlatDataToRealMode
+        mov     a_pvBuf, eax
+%elif !BS3_MODE_IS_RM_OR_V86(TMPL_MODE)
+        push    word a_pvBufSel
+        push    word a_pvBuf
+        call    Bs3SelProtFar16DataToRealMode
+        mov     a_pvBuf, ax
+        mov     a_pvBufSel, dx
+%endif
+
+        ;
+        ; Set up the BIOS call parameters.
+        ;
+        mov     ah, 02h                     ; read
+        mov     al, a_cSectors
+        mov     cx, a_uCylinder
+        xchg    ch, cl
+        shl     cl, 6
+        or      cl, a_uSector
+        mov     dl, a_bDrive
+        mov     dh, a_uHead
+        mov     bx, a_pvBuf
+        mov     di, a_pvBufSel
+
+        ;
+        ; Switch to real mode, first we just to the 16-bit text segment.
+        ; This preserve all 32-bit register values.
+        ;
+%if TMPL_MODE != BS3_MODE_RM
+ %ifndef TMPL_16BIT
+        jmp     .to_text16
+BS3_BEGIN_TEXT16
+.to_text16:
+        BS3_SET_BITS TMPL_BITS
+ %endif
+        call    TMPL_NM(Bs3SwitchToRM)
+        BS3_SET_BITS 16
+%endif
+
+        ;
+        ; Make the call.
+        ;
+        mov     es, di
+;        pushf
+;        sti
+        int     13h
+;        popf
+
+        ;
+        ; Switch back.
+        ;
+%if TMPL_MODE != BS3_MODE_RM
+        call    RT_CONCAT3(_Bs3SwitchTo,TMPL_MODE_UNAME,_Safe_rm)
+        BS3_SET_BITS TMPL_BITS
+ %ifndef TMPL_16BIT
+        jmp     .from_text16
+TMPL_BEGIN_TEXT
+.from_text16:
+ %endif
+%endif
+hlt
+
+        ;
+        ; Check that we didn't failed.
+        ;
+        jc      .failed_return_ah
+        test    ah, ah
+        jnz     .failed_return_ah
+
+        ;
+        ; Return success
+        ;
+        mov     al, 0
+
+.return:
+%ifndef TMPL_64BIT
+        lea     xSP, [xBP - sCB * 6 - xCB*2]
+        pop     es
+        pop     ds
+%else
+        lea     xSP, [xBP - sCB * 6]
+%endif
+        pop     sDI
+        pop     sSI
+        pop     sDX
+        pop     sCX
+        pop     sBX
+        sPOPF
+        leave
+        BS3_HYBRID_RET
+
+        ;
+        ; Failed.
+        ;
+.failed_return_ah:
+        mov     al, ah
+        cmp     al, 0
+        jne     .return
+        dec     al
+        jmp     .return
+BS3_PROC_END_MODE   Bs3DiskRead
+
Index: trunk/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-rm-InitAll.c
===================================================================
--- trunk/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-rm-InitAll.c	(revision 102150)
+++ trunk/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-rm-InitAll.c	(revision 102157)
@@ -59,4 +59,12 @@
     Bs3InitGdt_rm_far();
 
+#ifdef BS3_INIT_ALL_WITH_HIGH_DLLS
+    /*
+     * Load the high DLLs (if any) now, before we bugger up the PIC and
+     * replace the IVT.
+     */
+    Bs3InitHighDlls_rm_far();
+#endif
+
     /*
      * Before we disable all interrupts, try convince the BIOS to stop the
Index: trunk/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-rm-InitAllWithHighDlls.c
===================================================================
--- trunk/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-rm-InitAllWithHighDlls.c	(revision 102157)
+++ trunk/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-rm-InitAllWithHighDlls.c	(revision 102157)
@@ -0,0 +1,44 @@
+/* $Id$ */
+/** @file
+ * BS3Kit - Initialize all components and high DLLs, real mode.
+ */
+
+/*
+ * Copyright (C) 2007-2023 Oracle and/or its affiliates.
+ *
+ * This file is part of VirtualBox base platform packages, as
+ * available from https://www.virtualbox.org.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, in version 3 of the
+ * License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses>.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+ * in the VirtualBox distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+ */
+
+
+/*********************************************************************************************************************************
+*   Header Files                                                                                                                 *
+*********************************************************************************************************************************/
+#define BS3_INIT_ALL_WITH_HIGH_DLLS
+#define Bs3InitAll_rm Bs3InitAllWithHighDlls_rm
+#include "bs3-rm-InitAll.c"
+
Index: trunk/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-rm-InitHighDlls.c
===================================================================
--- trunk/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-rm-InitHighDlls.c	(revision 102157)
+++ trunk/src/VBox/ValidationKit/bootsectors/bs3kit/bs3-rm-InitHighDlls.c	(revision 102157)
@@ -0,0 +1,157 @@
+/* $Id$ */
+/** @file
+ * BS3Kit - Initialize any high DLLs, real mode.
+ */
+
+/*
+ * Copyright (C) 2007-2023 Oracle and/or its affiliates.
+ *
+ * This file is part of VirtualBox base platform packages, as
+ * available from https://www.virtualbox.org.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, in version 3 of the
+ * License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses>.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+ * in the VirtualBox distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+ */
+
+
+/*********************************************************************************************************************************
+*   Header Files                                                                                                                 *
+*********************************************************************************************************************************/
+//#define BS3_USE_RM_TEXT_SEG 1
+#include "bs3kit-template-header.h"
+#include "bs3kit-linker.h"
+#include "bs3-cmn-memory.h"
+
+extern BS3HIGHDLLENTRY BS3_FAR_DATA BS3_DATA_NM(g_aBs3HighDllTable)[];
+extern BS3HIGHDLLENTRY BS3_FAR_DATA BS3_DATA_NM(g_Bs3HighDllTable_End);
+
+
+BS3_DECL_FAR(void) Bs3InitHighDlls_rm_far(void)
+{
+    unsigned const cHighDlls = (unsigned)(&g_Bs3HighDllTable_End - &g_aBs3HighDllTable[0]);
+    if (   cHighDlls > 0
+        && (g_uBs3CpuDetected & BS3CPU_TYPE_MASK) >= BS3CPU_80386)
+    {
+        unsigned            i;
+
+        /*
+         * We need a buffer first of all. Using a 4K / PAGE_SIZE buffer let us
+         * share calculations and variables with the allocation code.
+         */
+        void BS3_FAR * const pvBuf    = Bs3MemAlloc(BS3MEMKIND_REAL, _4K);
+        uint32_t const       uFlatBuf = BS3_FP_REAL_TO_FLAT(pvBuf);
+        if (!pvBuf)
+        {
+            Bs3TestPrintf("Failed to allocate 4 KiB memory buffer for loading high DLL(s)!\n");
+            Bs3Shutdown();
+        }
+
+        /*
+         * Iterate the high DLL table and load it all into memory.
+         */
+        for (i = 0; i < cHighDlls; i++)
+        {
+            const char RT_FAR * const pszzStrings  = (char RT_FAR *)&g_aBs3HighDllTable[i] + g_aBs3HighDllTable[i].offStrings;
+            const char RT_FAR * const pszFilename  = &pszzStrings[g_aBs3HighDllTable[i].offFilename];
+            uint16_t                  cPagesToLoad = (uint16_t)(g_aBs3HighDllTable[i].cbLoaded / _4K);
+            uint16_t                  iPage;
+            Bs3Printf("Loading dll '%s' at %#RX32 ...", pszFilename, g_aBs3HighDllTable[i].uLoadAddr);
+
+            /* Allocate the memory taken by the DLL. */
+            iPage = Bs3SlabAllocFixed(&g_Bs3Mem4KUpperTiled.Core, g_aBs3HighDllTable[i].uLoadAddr, cPagesToLoad);
+            if (iPage == 0 || iPage == UINT16_MAX)
+            {
+                Bs3TestPrintf("Bs3SlabAllocFixed(,%#RX32, %#RX16) failed: %#RX16 (%s)\n",
+                              g_aBs3HighDllTable[i].uLoadAddr, cPagesToLoad, iPage, pszFilename);
+                Bs3Shutdown();
+            }
+            /* We don't have any memory management above 16MB... */
+
+            /*
+             * Load the DLL. This is where we ASSUME real-mode as we need to
+             * use int13 for the actual reading.  We temporarily restores the
+             * int13 entry in the interrupt table and loads the next chunk.
+             * Then we switch to 32-bit protected mode and copies the chunk
+             * from pvBuf and to the actual load address.
+             */
+            {
+                uint32_t      uCurFlatLoadAddr;
+                uint32_t      uCurSectorInImage;
+                uint16_t      cSectorsPerCylinder;
+
+                /* Get the drive geometry. ASSUMES the bootsector hasn't been trashed yet! */
+                uint8_t const bDrive       = ((BS3BOOTSECTOR RT_FAR *)BS3_FP_MAKE(0,0x7c00))->bBootDrv;
+                uint16_t      uMaxCylinder = 0;
+                uint8_t       uMaxHead     = 0;
+                uint8_t       uMaxSector   = 0;
+                int           rc;
+                rc = Bs3DiskQueryGeometry_rm(bDrive, &uMaxCylinder, &uMaxHead, &uMaxSector);
+                if (rc != 0)
+                {
+                    Bs3TestPrintf("Bs3DiskQueryGeometry(%#x) failed: %#x\n", bDrive, rc);
+                    Bs3Shutdown();
+                }
+                cSectorsPerCylinder = uMaxSector * ((uint16_t)uMaxHead + 1);
+                //Bs3TestPrintf("Bs3DiskQueryGeometry(%#x)-> C=%#x H=%#x S=%#x cSectorsPerCylinder=%#x\n",
+                //              bDrive, uMaxCylinder, uMaxHead, uMaxSector, cSectorsPerCylinder);
+
+                /* Load the image. */
+                if (g_aBs3HighDllTable[i].cbInImage < g_aBs3HighDllTable[i].cbLoaded)
+                    cPagesToLoad = (uint16_t)(g_aBs3HighDllTable[i].cbInImage / _4K);
+                uCurFlatLoadAddr  = g_aBs3HighDllTable[i].uLoadAddr;
+                uCurSectorInImage = g_aBs3HighDllTable[i].offInImage / 512;
+                iPage             = 0;
+                while (iPage < cPagesToLoad)
+                {
+                    /* Read the next page. */
+                    uint16_t const uCylinder  = uCurSectorInImage / cSectorsPerCylinder;
+                    uint16_t const uRemainder = uCurSectorInImage % cSectorsPerCylinder;
+                    uint8_t  const uHead      = uRemainder / uMaxSector;
+                    uint8_t  const uSector    = (uRemainder % uMaxSector) + 1;
+                    //Bs3TestPrintf("Calling Bs3DiskRead(%#x,%#x,%#x,%#x,%#x,%p) [uCurSectorInImage=%RX32]\n",
+                    //              bDrive, uCylinder, uHead, uSector, (uint8_t)(_4K / 512), pvBuf, uCurSectorInImage);
+                    rc = Bs3DiskRead_rm(bDrive, uCylinder, uHead, uSector, _4K / 512, pvBuf);
+                    if (rc != 0)
+                    {
+                        Bs3TestPrintf("Bs3DiskRead(%#x,%#x,%#x,%#x,,) failed: %#x\n", bDrive, uCylinder, uHead, uSector, rc);
+                        Bs3Shutdown();
+                    }
+
+                    /* Copy the page to where the DLL is being loaded.  */
+                    Bs3MemCopyFlat_rm_far(uCurFlatLoadAddr, uFlatBuf, _4K);
+                    Bs3PrintChr('.');
+
+                    /* Advance */
+                    iPage             += 1;
+                    uCurFlatLoadAddr  += _4K;
+                    uCurSectorInImage += _4K / 512;
+                }
+            }
+        }
+
+        Bs3Printf("\n");
+        Bs3MemFree(pvBuf, _4K);
+    }
+}
+
Index: trunk/src/VBox/ValidationKit/bootsectors/bs3kit/bs3kit-autostubs.kmk
===================================================================
--- trunk/src/VBox/ValidationKit/bootsectors/bs3kit/bs3kit-autostubs.kmk	(revision 102150)
+++ trunk/src/VBox/ValidationKit/bootsectors/bs3kit/bs3kit-autostubs.kmk	(revision 102157)
@@ -97,4 +97,5 @@
 $(call BS3KIT_FN_GEN_CMN_NEARSTUB,bs3kit-common-16,Bs3ExtCtxGetFsw)
 $(call BS3KIT_FN_GEN_CMN_NEARSTUB,bs3kit-common-16,Bs3PicUpdateMask)
+$(call BS3KIT_FN_GEN_CMN_NEARSTUB,bs3kit-common-16,Bs3SlabAllocFixed)
 $(call BS3KIT_FN_GEN_CMN_NEARSTUB,bs3kit-common-16,Bs3SlabFree)
 $(call BS3KIT_FN_GEN_CMN_NEARSTUB,bs3kit-common-16,Bs3TestSubErrorCount)
@@ -194,3 +195,6 @@
 $(call BS3KIT_FN_GEN_MODE_NEARSTUB,bs3kit-common-16,Bs3SwitchTo32BitAndCallC)
 $(call BS3KIT_FN_GEN_MODE_NEARSTUB,bs3kit-common-16,Bs3BiosInt15h88)
+$(call BS3KIT_FN_GEN_MODE_NEARSTUB,bs3kit-common-16,Bs3DiskQueryGeometry)
+$(call BS3KIT_FN_GEN_MODE_NEARSTUB,bs3kit-common-16,Bs3DiskRead)
+$(call BS3KIT_FN_GEN_MODE_NEARSTUB,bs3kit-common-16,Bs3MemCopyFlat)
 $(call BS3KIT_FN_GEN_MODE_NEARSTUB,bs3kit-common-16,Bs3TrapInit)
Index: trunk/src/VBox/ValidationKit/bootsectors/bs3kit/bs3kit-linker.h
===================================================================
--- trunk/src/VBox/ValidationKit/bootsectors/bs3kit/bs3kit-linker.h	(revision 102157)
+++ trunk/src/VBox/ValidationKit/bootsectors/bs3kit/bs3kit-linker.h	(revision 102157)
@@ -0,0 +1,125 @@
+/* $Id$ */
+/** @file
+ * BS3Kit - Linker related structures and defines.
+ */
+
+/*
+ * Copyright (C) 2007-2023 Oracle and/or its affiliates.
+ *
+ * This file is part of VirtualBox base platform packages, as
+ * available from https://www.virtualbox.org.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, in version 3 of the
+ * License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses>.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+ * in the VirtualBox distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+ */
+
+#ifndef BS3KIT_INCLUDED_bs3kit_linker_h
+#define BS3KIT_INCLUDED_bs3kit_linker_h
+#ifndef RT_WITHOUT_PRAGMA_ONCE
+# pragma once
+#endif
+
+#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 */
+
+
+/** The default address to start load high DLLs at.
+ * We start at 8MB to make sure the start is 16-bit tiled addressable, that we
+ * can load high DLLs on 286es, and to avoid using up the upper/tiled memory. */
+#define BS3HIGHDLL_LOAD_ADDRESS         ( _8M )
+
+/**
+ * High DLL table entry.
+ * These are found at the end of the base image.
+ */
+typedef struct BS3HIGHDLLENTRY
+{
+    char        achMagic[8];        /**< BS3HIGHDLLENTRY_MAGIC */
+    uint32_t    uLoadAddr;          /**< The load address. Set by the linker. */
+    uint32_t    cbLoaded;           /**< The number of bytes when loaded. */
+    uint32_t    offInImage;         /**< Byte offset in the linked image blob. */
+    uint32_t    cbInImage;          /**< The number of bytes to load from the linked image blob. */
+    uint32_t    cImports;           /**< Number of imports. */
+    int32_t     offImports;         /**< Relative address (to entry start) of the import table. */
+    uint32_t    cExports;           /**< Number of exports. */
+    int32_t     offExports;         /**< Relative address (to entry start) of the export table. */
+    uint32_t    cbStrings;          /**< Size of the string table in bytes. */
+    int32_t     offStrings;         /**< Relative address (to entry start) of the string table. */
+    uint32_t    offFilename;        /**< String table offset of the DLL name (sans path, with extension). */
+} BS3HIGHDLLENTRY;
+/** Magic value for BS3HIGHDLLENTRY. */
+#define BS3HIGHDLLENTRY_MAGIC           "HighDLL"
+
+typedef struct BS3HIGHDLLIMPORTENTRY
+{
+    uint16_t    offName;
+    uint16_t    uSeg;
+    uint32_t    offFlat;
+} BS3HIGHDLLIMPORTENTRY;
+
+typedef struct BS3HIGHDLLEXPORTENTRY
+{
+    uint32_t    offFlat;
+    uint16_t    offName;
+} BS3HIGHDLLEXPORTENTRY;
+
+
+#endif /* !BS3KIT_INCLUDED_bs3kit_linker_h */
+
Index: trunk/src/VBox/ValidationKit/bootsectors/bs3kit/bs3kit-mangling-code-define.h
===================================================================
--- trunk/src/VBox/ValidationKit/bootsectors/bs3kit/bs3kit-mangling-code-define.h	(revision 102150)
+++ trunk/src/VBox/ValidationKit/bootsectors/bs3kit/bs3kit-mangling-code-define.h	(revision 102157)
@@ -181,4 +181,5 @@
 #define Bs3SlabAlloc BS3_CMN_MANGLER(Bs3SlabAlloc)
 #define Bs3SlabAllocEx BS3_CMN_MANGLER(Bs3SlabAllocEx)
+#define Bs3SlabAllocFixed BS3_CMN_MANGLER(Bs3SlabAllocFixed)
 #define Bs3SlabFree BS3_CMN_MANGLER(Bs3SlabFree)
 #define Bs3SlabInit BS3_CMN_MANGLER(Bs3SlabInit)
@@ -251,4 +252,7 @@
 # define Bs3BiosInt15hE820 BS3_MODE_MANGLER(Bs3BiosInt15hE820)
 # define Bs3CpuDetect BS3_MODE_MANGLER(Bs3CpuDetect)
+# define Bs3DiskQueryGeometry BS3_MODE_MANGLER(Bs3DiskQueryGeometry)
+# define Bs3DiskRead BS3_MODE_MANGLER(Bs3DiskRead)
+# define Bs3MemCopyFlat BS3_MODE_MANGLER(Bs3MemCopyFlat)
 # define Bs3SwitchTo32BitAndCallC BS3_MODE_MANGLER(Bs3SwitchTo32BitAndCallC)
 # define Bs3TestDoModes BS3_MODE_MANGLER(Bs3TestDoModes)
Index: trunk/src/VBox/ValidationKit/bootsectors/bs3kit/bs3kit-mangling-code-undef.h
===================================================================
--- trunk/src/VBox/ValidationKit/bootsectors/bs3kit/bs3kit-mangling-code-undef.h	(revision 102150)
+++ trunk/src/VBox/ValidationKit/bootsectors/bs3kit/bs3kit-mangling-code-undef.h	(revision 102157)
@@ -181,4 +181,5 @@
 #undef Bs3SlabAlloc
 #undef Bs3SlabAllocEx
+#undef Bs3SlabAllocFixed
 #undef Bs3SlabFree
 #undef Bs3SlabInit
@@ -251,4 +252,7 @@
 # undef Bs3BiosInt15hE820
 # undef Bs3CpuDetect
+# undef Bs3DiskQueryGeometry
+# undef Bs3DiskRead
+# undef Bs3MemCopyFlat
 # undef Bs3SwitchTo32BitAndCallC
 # undef Bs3TestDoModes
Index: trunk/src/VBox/ValidationKit/bootsectors/bs3kit/bs3kit.h
===================================================================
--- trunk/src/VBox/ValidationKit/bootsectors/bs3kit/bs3kit.h	(revision 102150)
+++ trunk/src/VBox/ValidationKit/bootsectors/bs3kit/bs3kit.h	(revision 102157)
@@ -615,4 +615,12 @@
 # define BS3_FP_OFF(a_pv)            ((uintptr_t)(a_pv))
 #endif
+
+/**
+ * Converts a far real mode address to a 32-bit flat address.
+ *
+ * @returns Flat address.
+ * @param   a_pv        The _real_ _mode_ far pointer to convert.
+ */
+#define BS3_FP_REAL_TO_FLAT(a_pv)   (((uint32_t)BS3_FP_SEG(a_pv) << 4) + BS3_FP_OFF(a_pv))
 
 /** @def BS3_MAKE_PROT_R0PTR_FROM_FLAT
@@ -1757,4 +1765,5 @@
  * @param   pvSrc           The source buffer.
  * @param   cbToCopy        The number of bytes to copy.
+ * @sa      Bs3MemCopyFlat
  */
 BS3_CMN_PROTO_STUB(void BS3_FAR *, Bs3MemCpy,(void BS3_FAR *pvDst, const void BS3_FAR *pvSrc, size_t cbToCopy));
@@ -2152,5 +2161,5 @@
 
 /**
- * Allocates one or more chunks rom a slab.
+ * Allocates one or more chunks from a slab.
  *
  * @returns Pointer to the request number of chunks on success, NULL if we're
@@ -2161,4 +2170,17 @@
  */
 BS3_CMN_PROTO_STUB(void BS3_FAR *, Bs3SlabAllocEx,(PBS3SLABCTL pSlabCtl, uint16_t cChunks, uint16_t fFlags));
+
+/**
+ * Allocates a specific range of chunks from a slab.
+ *
+ * @returns Number of chunks it was possible to allocate in the slab.
+ * @retval  0 if the given address isn't in the slab.
+ * @retval  UINT16_MAX if one or more of the requested chunks are already in
+ *          use, so the request cannot be fulfilled.
+ * @param   pSlabCtl        The slab control structure to allocate from.
+ * @param   uFlatAddr       The flat address of the range to allocate.
+ * @param   cChunks         The number of contiguous chunks we want.
+ */
+BS3_CMN_PROTO_STUB(uint16_t, Bs3SlabAllocFixed,(PBS3SLABCTL pSlabCtl, uint32_t uFlatAddr, uint16_t cChunks));
 
 /**
@@ -2542,5 +2564,5 @@
  * Call 16-bit prot mode function from v8086 mode.
  *
- * This switches from v8086 mode to 16-bit protected mode (code) and executed
+ * This switches from v8086 mode to 16-bit protected mode (code) and executes
  * @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.
@@ -4131,4 +4153,9 @@
 
 /**
+ * Initializes all of boot sector kit \#3 as well as the high DLLs.
+ */
+BS3_DECL(void) Bs3InitAllWithHighDlls_rm(void);
+
+/**
  * Initializes the REAL and TILED memory pools.
  *
@@ -4141,4 +4168,11 @@
  */
 BS3_DECL_FAR(void) Bs3InitGdt_rm_far(void);
+
+/**
+ * Initializes (loads) any high DLLs.
+ *
+ * @note This cannot be called after the PIC or traps have been initialized!
+ */
+BS3_DECL_FAR(void) Bs3InitHighDlls_rm_far(void);
 
 
@@ -4337,4 +4371,17 @@
 
 /**
+ * Special version of memcpy for copying from/to real mode.
+ *
+ * @returns pvDst
+ * @param   uFlatDst        The flat address of the destination buffer.
+ * @param   uFlatSrc        The flat address of the source buffer.
+ * @param   cbToCopy        The number of bytes to copy.  Max 64KB.
+ *
+ * @todo    Only work on 386+ at present.   Could be made to work for 286 and
+ *          addresses < 16MB if we care...
+ */
+BS3_MODE_PROTO_STUB(void BS3_FAR *, Bs3MemCopyFlat,(uint32_t uFlatDst, uint32_t uFlatSrc, uint32_t cbToCopy));
+
+/**
  * Executes the array of tests in every possibly mode.
  *
@@ -4546,4 +4593,40 @@
 /** @} */
 
+/** @defgroup grp_bs3kit_disk   Disk via INT 13h
+ * @{
+ */
+
+/**
+ * Performs a int 13h function AL=08h call to get the driver parameters.
+ *
+ * @returns 0 on success, non-zero error BIOS code on failure.
+ * @param   bDrive          The drive to get parameters for.
+ * @param   puMaxCylinder   Where to store the max cylinder value.
+ *                          Range: 0 thru *pcMaxCylinder.
+ * @param   puMaxHead       Where to store the max head value.
+ *                          Range: 0 thru *pcMaxHead.
+ * @param   puMaxSector     Where to store the max sector value.
+ *                          Range: 1 thru *pcMaxSector.
+ */
+BS3_MODE_PROTO_STUB(uint8_t, Bs3DiskQueryGeometry,(uint8_t bDrive, uint16_t *puMaxCylinder,
+                                                   uint8_t *puMaxHead, uint8_t *puMaxSector));
+
+/**
+ * Performs a int 13h function AL=08h call to get the driver parameters.
+ *
+ * @returns 0 on success, non-zero error BIOS code on failure.
+ * @param   bDrive          The drive to read from.
+ * @param   uCylinder       The cylinder to start read at (0-max).
+ * @param   uHead           The head to start reading at (0-max).
+ * @param   uSector         The sector to start reading at (1-max).
+ * @param   cSectors        The number of sectors to read (1+).
+ * @param   pvBuf           The buffer to read into.  This MUST be addressable
+ *                          from real mode!
+ */
+BS3_MODE_PROTO_STUB(uint8_t, Bs3DiskRead,(uint8_t bDrive, uint16_t uCylinder, uint8_t uHead, uint8_t uSector,
+                                          uint8_t cSectors, void RT_FAR *pvBuf));
+
+/** @} */
+
 
 /** @} */
Index: trunk/src/VBox/ValidationKit/bootsectors/bs3kit/bs3kit.mac
===================================================================
--- trunk/src/VBox/ValidationKit/bootsectors/bs3kit/bs3kit.mac	(revision 102150)
+++ trunk/src/VBox/ValidationKit/bootsectors/bs3kit/bs3kit.mac	(revision 102157)
@@ -333,6 +333,13 @@
 ;
 ; !!HACK ALERT!!
+ %ifndef BS3_IS_HIGH_IMAGE
 segment BS3FLAT use32 class=BS3FLAT
 GROUP FLAT BS3FLAT
+ %else
+; For HIGH DLLs the hack is WRONG, so we just declare both BS3FLAT and FLAT the way
+; wlink wants flat groups to be defined. (See FIX_FRAME_FLAT use in omfreloc.c.)
+GROUP BS3FLAT
+GROUP FLAT
+ %endif
 %endif
 
