Browse Source

Boot app changes to compile x64 32-bit boot manager.

This commit contains changes to the boot manager and OS loader needed to
transition between to long mode. So far only PC/AT compiles, and because
of the -mno-sse issue I haven't been able to run it yet, so the trampoline
code is untested.

Most of this change has to do with de-pointerizing the
BOOT_INITIALIZATION_BLOCK structure passed between the boot manager and OS
loader. This can't have pointers because the two apps will disagree on
what size a pointer is. Now all the pointer fields are 64-bit integer
sizes.
Evan Green 7 years ago
parent
commit
37a82cb425

+ 24 - 15
boot/bootman/bootman.c

@@ -112,6 +112,7 @@ Return Value:
 
 {
 
+    PCSTR ApplicationName;
     INT ApplicationReturn;
     UINTN BaseDifference;
     BOOT_CONFIGURATION_CONTEXT BootConfigurationContext;
@@ -165,7 +166,8 @@ Return Value:
     //
 
     RtlZeroMemory(&BmModuleBuffer, sizeof(BmModuleBuffer));
-    ModuleNameLength = RtlStringLength(Parameters->ApplicationName) + 1;
+    ApplicationName = (PVOID)(UINTN)(Parameters->ApplicationName);
+    ModuleNameLength = RtlStringLength(ApplicationName) + 1;
     if (ModuleNameLength > BOOT_MANAGER_BINARY_NAME_MAX_SIZE) {
         ModuleNameLength = BOOT_MANAGER_BINARY_NAME_MAX_SIZE;
     }
@@ -173,11 +175,10 @@ Return Value:
     DebugModule->StructureSize = sizeof(DEBUG_MODULE) + ModuleNameLength -
                                  (ANYSIZE_ARRAY * sizeof(CHAR));
 
-    RtlStringCopy(DebugModule->BinaryName,
-                  Parameters->ApplicationName,
-                  ModuleNameLength);
+    RtlStringCopy(DebugModule->BinaryName, ApplicationName, ModuleNameLength);
+    DebugModule->LowestAddress =
+                          (PVOID)(UINTN)(Parameters->ApplicationLowestAddress);
 
-    DebugModule->LowestAddress = Parameters->ApplicationLowestAddress;
     DebugModule->Size = Parameters->ApplicationSize;
     BoProductName = BOOT_MANAGER_NAME;
     if (BmDebug != FALSE) {
@@ -297,7 +298,9 @@ Return Value:
     Step += 1;
     RtlZeroMemory(LoaderParameters, sizeof(BOOT_INITIALIZATION_BLOCK));
     LoaderParameters->Version = BOOT_INITIALIZATION_BLOCK_VERSION;
-    LoaderParameters->BootConfigurationFile = BootConfigurationContext.FileData;
+    LoaderParameters->BootConfigurationFile =
+                                    (UINTN)(BootConfigurationContext.FileData);
+
     LoaderParameters->BootConfigurationFileSize =
                                          BootConfigurationContext.FileDataSize;
 
@@ -308,27 +311,33 @@ Return Value:
     LoaderParameters->Flags = Parameters->Flags |
                               BOOT_INITIALIZATION_FLAG_SCREEN_CLEAR;
 
+    if (LoaderImage->Format == ImageElf64) {
+        LoaderParameters->Flags |= BOOT_INITIALIZATION_FLAG_64BIT;
+    }
+
     BaseDifference = LoaderImage->BaseDifference;
 
     //
     // Set the file name and base address of the loader.
     //
 
-    LoaderParameters->ApplicationName =
-                  RtlStringFindCharacterRight(LoaderName, '/', LoaderNameSize);
+    ApplicationName = RtlStringFindCharacterRight(LoaderName,
+                                                  '/',
+                                                  LoaderNameSize);
 
-    if (LoaderParameters->ApplicationName == NULL) {
-        LoaderParameters->ApplicationName = LoaderName;
+    if (ApplicationName == NULL) {
+        ApplicationName = LoaderName;
 
     } else {
-        LoaderParameters->ApplicationName += 1;
+        ApplicationName += 1;
     }
 
+    LoaderParameters->ApplicationName = (UINTN)ApplicationName;
     LoaderParameters->ApplicationLowestAddress =
-                          LoaderImage->PreferredLowestAddress + BaseDifference;
+                   (UINTN)LoaderImage->PreferredLowestAddress + BaseDifference;
 
     LoaderParameters->ApplicationSize = LoaderImage->Size;
-    LoaderParameters->ApplicationArguments = BootEntry->LoaderArguments;
+    LoaderParameters->ApplicationArguments = (UINTN)BootEntry->LoaderArguments;
     Status = BmpFwInitializeBootBlock(LoaderParameters, OsDevice);
     if (!KSUCCESS(Status)) {
         goto MainEnd;
@@ -372,8 +381,8 @@ Return Value:
     //
 
     if (LoaderParameters != NULL) {
-        if (LoaderParameters->ReservedRegions != NULL) {
-            BoFreeMemory(LoaderParameters->ReservedRegions);
+        if (LoaderParameters->ReservedRegions != (UINTN)NULL) {
+            BoFreeMemory((PVOID)(UINTN)(LoaderParameters->ReservedRegions));
         }
 
         BoFreeMemory(LoaderParameters);

+ 65 - 62
boot/bootman/build.ck

@@ -31,15 +31,12 @@ from menv import application, binplace, executable, flattenedBinary, mconfig;
 
 function build() {
     var arch = mconfig.arch;
-    var baseLibs;
+    var baseRtl = "lib/rtl/base:basertl";
     var bootmanPe;
-    var commonLibs;
     var commonSources;
     var efiApp;
-    var efiAppLibs;
+    var efiConfig;
     var efiLibs;
-    var efiLinkConfig;
-    var efiLinkLdflags;
     var efiSources;
     var elfconvConfig;
     var entries;
@@ -47,12 +44,11 @@ function build() {
     var includes;
     var linkerScript;
     var pcatApp;
-    var pcatAppLibs;
+    var pcatConfig;
     var pcatLibs;
-    var pcatLinkConfig;
-    var pcatLinkLdflags;
     var pcatSources;
     var sourcesConfig;
+    var x6432 = "";
 
     commonSources = [
         "bootman.c",
@@ -65,6 +61,7 @@ function build() {
         ":bootim.o",
         "pcat/bootxfr.c",
         "pcat/main.c",
+        "pcat/paging.c"
     ];
 
     efiSources = [
@@ -81,74 +78,57 @@ function build() {
         "CFLAGS": ["-fshort-wchar"],
     };
 
-    efiLinkLdflags = [
-        "-nostdlib",
-        "-pie",
-        "-static",
-    ];
+    efiConfig = {
+        "LDFLAGS": ["-nostdlib", "-pie", "-static"]
+    };
 
-    pcatLinkLdflags = [
-        "-nostdlib",
-        "-static"
-    ];
+    pcatConfig = {
+        "LDFLAGS": ["-nostdlib", "-static"]
+    };
 
     efiLibs = [
+        "kernel/kd:kdboot",
+        "kernel/hl:hlboot",
+        "lib/im:imu",
+        "lib/bconflib:bconf",
+        "kernel/kd/kdusb:kdnousb",
         "boot/lib:bootefi",
+        "lib/basevid:basevid",
+        "lib/fatlib:fat",
+        "kernel/mm:mmboot"
     ];
 
     if ((arch == "armv7") || (arch == "armv6")) {
         linkerScript = "$S/uefi/include/link_arm.x";
-        efiLinkLdflags += [
-            "-Wl,--no-wchar-size-warning"
-        ];
-
-        efiLibs = ["kernel:archboot"] + efiLibs;
+        efiConfig["LDFLAGS"] += ["-Wl,--no-wchar-size-warning"];
+        baseRtl = "lib/rtl/base:basertlb";
+        efiLibs += ["kernel:archboot"];
 
     } else if (arch == "x86") {
         linkerScript = "$S/uefi/include/link_x86.x";
-    }
-
-    efiLinkConfig = {
-        "LDFLAGS": efiLinkLdflags
-    };
-
-    pcatLinkConfig = {
-        "LDFLAGS": pcatLinkLdflags
-    };
-
-    //
-    // These base libraries are relied upon by the boot library and so they
-    // must go after the boot library.
-    //
-
-    baseLibs = [
-        "lib/basevid:basevid",
-        "lib/fatlib:fat",
-        "kernel/mm:mmboot",
-        "lib/rtl/kmode:krtl",
-        "lib/rtl/base:basertlb"
-    ];
+        pcatSources += [
+            "pcat/x86/xferc.c"
+        ];
 
-    commonLibs = [
-        "kernel/kd:kdboot",
-        "kernel/hl:hlboot",
-        "lib/im:imu",
-        "lib/bconflib:bconf",
-        "kernel/kd/kdusb:kdnousb"
-    ];
+    } else if (arch == "x64") {
+        linkerScript = "$S/uefi/include/link_x64.x";
+        pcatSources += [
+            "pcat/x64/xfera.S",
+            "pcat/x64/xferc.c"
+        ];
+    }
 
-    pcatLibs = [
-        "boot/lib:bootpcat",
-        "lib/partlib:partlib"
+    efiLibs += [
+        baseRtl,
+        "lib/rtl/kmode:krtl"
     ];
 
-    efiAppLibs = commonLibs + efiLibs + baseLibs;
     efiApp = {
         "label": "bootmefi.elf",
-        "inputs": commonSources + efiSources + efiAppLibs,
+        "inputs": commonSources + efiSources + efiLibs,
         "sources_config": sourcesConfig,
         "includes": includes,
-        "config": efiLinkConfig,
+        "config": efiConfig,
         "entry": "BmEfiApplicationMain",
         "linker_script": linkerScript
     };
@@ -176,17 +156,40 @@ function build() {
     entries += binplace(bootmanPe);
 
     //
-    // On PC machines, build the BIOS library as well.
+    // On PC machines, build the BIOS version as well. The boot manager is
+    // 32-bits even on 64-bit machines so that both 32 and 64-bit OS loaders
+    // can be launched. This means that on x64 all the libraries need to be
+    // recompiled as 32-bit libraries.
     //
 
-    if (arch == "x86") {
-        pcatAppLibs = commonLibs + pcatLibs + baseLibs;
+    if ((arch == "x86") || (arch == "x64")) {
+        if (arch == "x64") {
+            x6432 = "32";
+            pcatConfig["LDFLAGS"] += ["-m32"];
+            sourcesConfig["CPPFLAGS"] = ["-m32"];
+        }
+
+        pcatLibs = [
+            "kernel/kd:kdboot" + x6432,
+            "kernel/hl:hlboot" + x6432,
+            "lib/im:imu" + x6432,
+            "lib/bconflib:bconf" + x6432,
+            "kernel/kd/kdusb:kdnousb" + x6432,
+            "boot/lib:bootpcat" + x6432,
+            "lib/partlib:partlib" + x6432,
+            "lib/basevid:basevid" + x6432,
+            "lib/fatlib:fat" + x6432,
+            "kernel/mm:mmboot" + x6432,
+            "lib/rtl/base:basertl" + x6432,
+            "lib/rtl/kmode:krtl" + x6432
+        ];
+
         pcatApp = {
             "label": "bootman.elf",
-            "inputs": pcatSources + pcatAppLibs,
+            "inputs": pcatSources + pcatLibs,
             "sources_config": sourcesConfig,
             "includes": includes,
-            "config": pcatLinkConfig,
+            "config": pcatConfig,
             "text_address": "0x100000",
             "binplace": "bin"
         };

+ 2 - 2
boot/bootman/efi/bootxfr.c

@@ -92,8 +92,8 @@ Return Value:
     // and EFI image handle, in case EFI ever changes the size of an EFI_HANDLE.
     //
 
-    Parameters->EfiImageHandle = &BoEfiImageHandle;
-    Parameters->EfiSystemTable = BoEfiSystemTable;
+    Parameters->EfiImageHandle = (UINTN)&BoEfiImageHandle;
+    Parameters->EfiSystemTable = (UINTN)BoEfiSystemTable;
     return STATUS_SUCCESS;
 }
 

+ 7 - 6
boot/bootman/efi/main.c

@@ -110,19 +110,20 @@ Return Value:
 
     RtlZeroMemory(&BmBootBlock, sizeof(BOOT_INITIALIZATION_BLOCK));
     BmBootBlock.Version = BOOT_INITIALIZATION_BLOCK_VERSION;
-    BmBootBlock.EfiImageHandle = &ImageHandle;
-    BmBootBlock.EfiSystemTable = SystemTable;
-    BmBootBlock.ApplicationName = "bootmefi.efi";
+    BmBootBlock.EfiImageHandle = (UINTN)&ImageHandle;
+    BmBootBlock.EfiSystemTable = (UINTN)SystemTable;
+    BmBootBlock.ApplicationName = (UINTN)"bootmefi.efi";
     BmpEfiGetLoadedImageProtocol(ImageHandle,
                                  SystemTable,
                                  &LoadedImage);
 
-    BmBootBlock.ApplicationArguments = "";
+    BmBootBlock.ApplicationArguments = (UINTN)"";
     if (LoadedImage != NULL) {
-        BmBootBlock.ApplicationLowestAddress = LoadedImage->ImageBase;
+        BmBootBlock.ApplicationLowestAddress = (UINTN)LoadedImage->ImageBase;
         BmBootBlock.ApplicationSize = LoadedImage->ImageSize;
         if (LoadedImage->LoadOptionsSize != 0) {
-            BmBootBlock.ApplicationArguments = LoadedImage->LoadOptions;
+            BmBootBlock.ApplicationArguments =
+                                             (UINTN)(LoadedImage->LoadOptions);
         }
     }
 

+ 25 - 1
boot/bootman/pcat/Makefile

@@ -32,19 +32,43 @@ VPATH += $(SRCDIR)/..:
 
 OBJS += bootxfr.o   \
         main.o      \
+        paging.o    \
 
 X86_OBJS = x86/entry.o  \
+           x86/xferc.o  \
+
+X64_OBJS = x86/entry.o  \
+           x64/xfera.o  \
+           x64/xferc.o  \
 
 LDFLAGS += -nodefaultlibs -nostartfiles -nostdlib
 
+##
+## The PCAT boot manager is always compiled for 32-bits, even for AMD64.
+##
+
+ifeq ($(ARCH),x64)
+EXTRA_CPPFLAGS += -m32
+EXTRA_LDFLAGS += -m32
+endif
+
 TEXT_ADDRESS := 0x100000
 
 INCLUDES += $(SRCROOT)/os/boot/lib/include;$(SRCDIR)/..;
 
+ifeq ($(ARCH),x64)
+
+TARGETLIBS += $(OBJROOT)/os/boot/lib/pcat/x6432/bootpcat.a \
+              $(OBJROOT)/os/lib/partlib/x6432/partlib.a    \
+
+else
+
 TARGETLIBS += $(OBJROOT)/os/boot/lib/pcat/bootpcat.a \
               $(OBJROOT)/os/lib/partlib/partlib.a    \
 
-EXTRA_SRC_DIRS = x86
+endif
+
+EXTRA_SRC_DIRS = x86 x64
 
 include $(SRCROOT)/os/minoca.mk
 

+ 17 - 35
boot/bootman/pcat/bootxfr.c

@@ -73,6 +73,11 @@ typedef struct _BOOT_BLOCK_DESCRIPTOR_CONTEXT {
 // ----------------------------------------------- Internal Function Prototypes
 //
 
+KSTATUS
+BmpFwCreatePageTables (
+    PBOOT_INITIALIZATION_BLOCK Parameters
+    );
+
 VOID
 BmpFwBootBlockDescriptorIterationRoutine (
     PMEMORY_DESCRIPTOR_LIST DescriptorList,
@@ -149,6 +154,17 @@ Return Value:
     Context.AllocatedRegionCount = AllocatedRegionCount;
     Context.RegionCount = 0;
 
+    //
+    // Allocate page tables if transferring to a 64-bit application.
+    //
+
+    if ((Parameters->Flags & BOOT_INITIALIZATION_FLAG_64BIT) != 0) {
+        Status = BmpFwCreatePageTables(Parameters);
+        if (!KSUCCESS(Status)) {
+            goto FwInitializeBootBlockEnd;
+        }
+    }
+
     //
     // Loop through the descriptors again and mark all the regions used by this
     // and previous boot applications.
@@ -158,7 +174,7 @@ Return Value:
                 BmpFwBootBlockDescriptorIterationRoutine,
                 &Context);
 
-    Parameters->ReservedRegions = Context.RegionArray;
+    Parameters->ReservedRegions = (UINTN)(Context.RegionArray);
     Parameters->ReservedRegionCount = Context.RegionCount;
     FwpPcatGetDiskInformation(OsVolume->DiskHandle,
                               &(Parameters->DriveNumber),
@@ -176,40 +192,6 @@ FwInitializeBootBlockEnd:
     return Status;
 }
 
-INT
-BmpFwTransferToBootApplication (
-    PBOOT_INITIALIZATION_BLOCK Parameters,
-    PBOOT_APPLICATION_ENTRY EntryPoint
-    )
-
-/*++
-
-Routine Description:
-
-    This routine transfers control to another boot application.
-
-Arguments:
-
-    Parameters - Supplies a pointer to the initialization block.
-
-    EntryPoint - Supplies tne address of the entry point routine of the new
-        application.
-
-Return Value:
-
-    Returns the integer return value from the application. Often does not
-    return on success.
-
---*/
-
-{
-
-    INT Result;
-
-    Result = EntryPoint(Parameters);
-    return Result;
-}
-
 //
 // --------------------------------------------------------- Internal Functions
 //

+ 5 - 5
boot/bootman/pcat/main.c

@@ -127,14 +127,14 @@ Return Value:
     PageSize = MmPageSize();
     RtlZeroMemory(&BmBootBlock, sizeof(BOOT_INITIALIZATION_BLOCK));
     BmBootBlock.Version = BOOT_INITIALIZATION_BLOCK_VERSION;
-    BmBootBlock.StackTop = TopOfStack;
+    BmBootBlock.StackTop = (UINTN)TopOfStack;
     BmBootBlock.StackSize = StackSize;
     BmBootBlock.PartitionOffset = PartitionOffset;
     BmBootBlock.DriveNumber = BootDriveNumber;
-    BmBootBlock.ApplicationName = "bootman";
-    BmBootBlock.ApplicationLowestAddress = &__executable_start;
+    BmBootBlock.ApplicationName = (UINTN)"bootman";
+    BmBootBlock.ApplicationLowestAddress = (UINTN)&__executable_start;
     BmBootBlock.ApplicationSize = (UINTN)&_end - (UINTN)&__executable_start;
-    BmBootBlock.ApplicationArguments = "";
+    BmBootBlock.ApplicationArguments = (UINTN)"";
 
     //
     // Initialize the reserved regions for the image itself and the stack.
@@ -155,7 +155,7 @@ Return Value:
                             BmBootRegions[1].Address;
 
     BmBootRegions[1].Flags = 0;
-    BmBootBlock.ReservedRegions = BmBootRegions;
+    BmBootBlock.ReservedRegions = (UINTN)BmBootRegions;
     BmBootBlock.ReservedRegionCount = BOOT_MANAGER_RESERVED_REGION_COUNT;
 
     //

+ 408 - 0
boot/bootman/pcat/paging.c

@@ -0,0 +1,408 @@
+/*++
+
+Copyright (c) 2017 Minoca Corp.
+
+    This file is licensed under the terms of the GNU General Public License
+    version 3. Alternative licensing terms are available. Contact
+    info@minocacorp.com for details. See the LICENSE file at the root of this
+    project for complete licensing information.
+
+Module Name:
+
+    paging.c
+
+Abstract:
+
+    This module sets up PAE paging for a 64-bit OS loader.
+
+Author:
+
+    Evan Green 31-May-2017
+
+Environment:
+
+    Boot
+
+--*/
+
+//
+// ------------------------------------------------------------------- Includes
+//
+
+#include <minoca/kernel/kernel.h>
+#include <minoca/kernel/x64.h>
+#include "firmware.h"
+#include "bootlib.h"
+#include "bios.h"
+
+//
+// --------------------------------------------------------------------- Macros
+//
+
+//
+// ---------------------------------------------------------------- Definitions
+//
+
+//
+// ------------------------------------------------------ Data Type Definitions
+//
+
+/*++
+
+Structure Description:
+
+    This structure defines the iteration context for mapping all the boot
+    manager allocations.
+
+Members:
+
+    PagesMapped - Stores the number of pages that were successfully mapped.
+
+    Status - Stores the overall status code.
+
+--*/
+
+typedef struct _BOOTMAN_MAPPING_CONTEXT {
+    UINTN PagesMapped;
+    KSTATUS Status;
+} BOOTMAN_MAPPING_CONTEXT, *PBOOTMAN_MAPPING_CONTEXT;
+
+//
+// ----------------------------------------------- Internal Function Prototypes
+//
+
+VOID
+BmpFwBootMappingIterationRoutine (
+    PMEMORY_DESCRIPTOR_LIST DescriptorList,
+    PMEMORY_DESCRIPTOR Descriptor,
+    PVOID Context
+    );
+
+KSTATUS
+BmpFwIdentityMapPages (
+    ULONGLONG Address,
+    UINTN Size,
+    PUINTN PagesMapped
+    );
+
+KSTATUS
+BmpFwIdentityMapPage (
+    ULONGLONG Address,
+    PUINTN PagesMapped
+    );
+
+//
+// -------------------------------------------------------------------- Globals
+//
+
+//
+// Define the PML4 table address.
+//
+
+PPTE FwPml4Table;
+
+//
+// Define the PML4 self map index.
+//
+
+ULONG FwSelfMapIndex;
+
+//
+// ------------------------------------------------------------------ Functions
+//
+
+KSTATUS
+BmpFwCreatePageTables (
+    PBOOT_INITIALIZATION_BLOCK Parameters
+    )
+
+/*++
+
+Routine Description:
+
+    This routine sets up the page tables used by a 64-bit boot application.
+
+Arguments:
+
+    Parameters - Supplies a pointer to the boot initialization block.
+
+Return Value:
+
+    Status code.
+
+--*/
+
+{
+
+    BOOTMAN_MAPPING_CONTEXT Context;
+    ULONGLONG Page;
+    KSTATUS Status;
+
+    Context.PagesMapped = 0;
+    Context.Status = STATUS_SUCCESS;
+
+    //
+    // Allocate and initialize a PML4.
+    //
+
+    if (FwPml4Table == INVALID_PHYSICAL_ADDRESS) {
+        Status = FwAllocatePages(&Page,
+                                 PAGE_SIZE,
+                                 PAGE_SIZE,
+                                 MemoryTypeLoaderTemporary);
+
+        if (!KSUCCESS(Status)) {
+            goto FwCreatePageTablesEnd;
+        }
+
+        ASSERT(Page == (UINTN)Page);
+
+        FwPml4Table = (PVOID)(UINTN)Page;
+        RtlZeroMemory(FwPml4Table, PAGE_SIZE);
+
+        //
+        // Just use the highest value as the self map index. This conveniently
+        // keeps it out of a range where the self map might collide with real
+        // physical pages.
+        //
+
+        FwSelfMapIndex = X64_PTE_COUNT;
+        FwPml4Table[FwSelfMapIndex] =
+                              X86_ENTRY_PTE((UINTN)FwPml4Table >> PAGE_SHIFT) |
+                              X86_PTE_PRESENT |
+                              X86_PTE_WRITABLE;
+    }
+
+    MmMdIterate(&BoMemoryMap,
+                BmpFwBootMappingIterationRoutine,
+                &Context);
+
+    if (!KSUCCESS(Context.Status)) {
+        goto FwCreatePageTablesEnd;
+    }
+
+    Parameters->PageDirectory = (UINTN)FwPml4Table;
+    Parameters->PageTables = ((ULONGLONG)FwSelfMapIndex << X64_PML4E_SHIFT) |
+                             X64_CANONICAL_HIGH;
+
+FwCreatePageTablesEnd:
+    return Status;
+}
+
+//
+// --------------------------------------------------------- Internal Functions
+//
+
+VOID
+BmpFwBootMappingIterationRoutine (
+    PMEMORY_DESCRIPTOR_LIST DescriptorList,
+    PMEMORY_DESCRIPTOR Descriptor,
+    PVOID Context
+    )
+
+/*++
+
+Routine Description:
+
+    This routine is called once for each descriptor in the memory descriptor
+    list.
+
+Arguments:
+
+    DescriptorList - Supplies a pointer to the descriptor list being iterated
+        over.
+
+    Descriptor - Supplies a pointer to the current descriptor.
+
+    Context - Supplies an optional opaque pointer of context that was provided
+        when the iteration was requested.
+
+Return Value:
+
+    None.
+
+--*/
+
+{
+
+    PBOOTMAN_MAPPING_CONTEXT IterationContext;
+    UINTN PagesMapped;
+    KSTATUS Status;
+
+    IterationContext = Context;
+    if (!KSUCCESS(IterationContext->Status)) {
+        return;
+    }
+
+    //
+    // Skip all except interesting descriptors.
+    //
+
+    if ((Descriptor->Type == MemoryTypeFirmwareTemporary) ||
+        (Descriptor->Type == MemoryTypeLoaderTemporary) ||
+        (Descriptor->Type == MemoryTypeLoaderPermanent)) {
+
+        PagesMapped = 0;
+        Status = BmpFwIdentityMapPages(Descriptor->BaseAddress,
+                                       Descriptor->Size,
+                                       &PagesMapped);
+
+        IterationContext->PagesMapped += PagesMapped;
+        if (!KSUCCESS(Status)) {
+            IterationContext->Status = Status;
+        }
+    }
+
+    return;
+}
+
+KSTATUS
+BmpFwIdentityMapPages (
+    ULONGLONG Address,
+    UINTN Size,
+    PUINTN PagesMapped
+    )
+
+/*++
+
+Routine Description:
+
+    This routine identity maps a region of memory in preparation for switching
+    64-bit paging on.
+
+Arguments:
+
+    Address - Supplies the address to identity map.
+
+    Size - Supplies the size to map.
+
+    PagesMapped - Supplies a pointer where the number of pages successfully
+        mapped will be incremented. Pages already mapped do not count.
+
+Return Value:
+
+    Status code.
+
+--*/
+
+{
+
+    ULONGLONG Current;
+    UINTN Index;
+    UINTN PageCount;
+    KSTATUS Status;
+
+    Current = ALIGN_RANGE_DOWN(Address, PAGE_SIZE);
+    PageCount = (ALIGN_RANGE_UP(Address + Size, PAGE_SIZE) - Current) >>
+                PAGE_SHIFT;
+
+    for (Index = 0; Index < PageCount; Index += 1) {
+        Status = BmpFwIdentityMapPage(Current, PagesMapped);
+        if (!KSUCCESS(Status)) {
+            return Status;
+        }
+
+        Current += PAGE_SIZE;
+    }
+
+    return STATUS_SUCCESS;
+}
+
+KSTATUS
+BmpFwIdentityMapPage (
+    ULONGLONG Address,
+    PUINTN PagesMapped
+    )
+
+/*++
+
+Routine Description:
+
+    This routine identity maps a page of memory in preparation for switching
+    64-bit paging on.
+
+Arguments:
+
+    Address - Supplies the address of the page to identity map.
+
+    PagesMapped - Supplies a pointer whose value will be incremented if a new
+        page was mapped.
+
+Return Value:
+
+    Status code.
+
+--*/
+
+{
+
+    ULONG EntryIndex;
+    ULONG Index;
+    ULONGLONG NewPage;
+    ULONG Shift;
+    KSTATUS Status;
+    PPTE Table;
+
+    //
+    // Walk the page tables, creating any needed pages along the way.
+    //
+
+    Table = FwPml4Table;
+    Shift = X64_PML4E_SHIFT;
+    for (Index = 0; Index < X64_PAGE_LEVEL - 1; Index += 1) {
+        EntryIndex = (Address >> Shift) & X64_PT_MASK;
+        if (X86_PTE_ENTRY(Table[EntryIndex]) == 0) {
+            Status = FwAllocatePages(&NewPage,
+                                     PAGE_SIZE,
+                                     PAGE_SIZE,
+                                     MemoryTypeLoaderTemporary);
+
+            if (!KSUCCESS(Status)) {
+                return Status;
+            }
+
+            ASSERT(NewPage == (UINTN)NewPage);
+
+            RtlZeroMemory((PVOID)(UINTN)NewPage, PAGE_SIZE);
+            Table[EntryIndex] = X86_ENTRY_PTE(NewPage) |
+                                X86_PTE_PRESENT |
+                                X86_PTE_WRITABLE;
+        }
+
+        ASSERT(X86_PTE_ENTRY(Table[EntryIndex]) ==
+               (UINTN)(X86_PTE_ENTRY(Table[EntryIndex])));
+
+        Table = (PPTE)(UINTN)(X86_PTE_ENTRY(Table[EntryIndex]));
+        Shift -= X64_PTE_BITS;
+    }
+
+    ASSERT(Shift == PAGE_SHIFT);
+
+    EntryIndex = (Address >> PAGE_SHIFT) & X64_PT_MASK;
+    if ((Table[EntryIndex] & X86_PTE_PRESENT) != 0) {
+        if (X86_PTE_ENTRY(Table[EntryIndex]) != (Address >> PAGE_SHIFT)) {
+
+            //
+            // Some page is already mapped here, and it's not the right one.
+            //
+
+            ASSERT(FALSE);
+
+            return STATUS_MEMORY_CONFLICT;
+        }
+
+        return STATUS_SUCCESS;
+    }
+
+    //
+    // Set the PTE to point at the page itself.
+    //
+
+    Table[EntryIndex] = X86_ENTRY_PTE(Address >> PAGE_SHIFT) |
+                        X86_PTE_PRESENT |
+                        X86_PTE_WRITABLE;
+
+    *PagesMapped += 1;
+    return STATUS_SUCCESS;
+}
+

+ 180 - 0
boot/bootman/pcat/x64/xfera.S

@@ -0,0 +1,180 @@
+/*++
+
+Copyright (c) 2017 Minoca Corp.
+
+    This file is licensed under the terms of the GNU General Public License
+    version 3. Alternative licensing terms are available. Contact
+    info@minocacorp.com for details. See the LICENSE file at the root of this
+    project for complete licensing information.
+
+Module Name:
+
+    xfera.S
+
+Abstract:
+
+    This module implements the assembly trampoline that transfers between
+    a 32-bit boot application and a 64-bit boot application. This is where
+    long mode and paging are enabled.
+
+Author:
+
+    Evan Green 31-May-2017
+
+Environment:
+
+    Boot
+
+--*/
+
+##
+## ------------------------------------------------------------------ Includes
+##
+
+//
+// Include the 32-bit header since this is really only compiled in 32-bit mode.
+//
+
+#include <minoca/kernel/x86.inc>
+
+##
+## ---------------------------------------------------------------------- Code
+##
+
+.text
+.code32
+
+##
+## INT
+## BmpFwTransferTo64BitApplication (
+##     PBOOT_INITIALIZATION_BLOCK Parameters,
+##     PBOOT_APPLICATION_ENTRY EntryPoint,
+##     ULONG PageDirectory
+##     )
+##
+
+/*++
+
+Routine Description:
+
+    This routine enables paging, enables long mode, and jumps to the
+    application entry point. Upon return, it returns to 32-bit mode and disables
+    paging. This function starts and ends in 32-bit mode.
+
+Arguments:
+
+    Parameters - Supplies the parameters to pass to the application entry
+        point. This is a 32-bit pointer.
+
+    EntryPoint - Supplies a pointer to the function to call. This is a 32-bit
+        pointer.
+
+    PageDirectory - Supplies the physical address of the value to set in CR3.
+        This is a 32-bit value.
+
+Return Value:
+
+    Returns the value returned from the entry point function. Usually on
+    success, this does not return, but launches the OS instead.
+
+--*/
+
+FUNCTION(BmpFwTransferTo64BitApplication)
+    pushl   %ebp                    # Save previous frame pointer.
+    movl    %esp, %ebp              # Set new frame pointer.
+    CFI_DEF_CFA(%ebp, 8)            # Return address is counted in this frame.
+    andl    $0xFFFFFFF0, %esp       # Align the stack.
+    pushl   %edi                    # Save EDI, first 64-bit parameter register.
+    pushl   %esi                    # Save ESI, volatile in 64-bit land.
+    movl    8(%ebp), %edi           # Load the parameters parameter.
+    movl    12(%ebp), %edx          # Load the function pointer.
+    movl    16(%ebp), %eax          # Load up the page directory.
+    movl    %cr3, %ecx              # Get the old CR3.
+    pushl   %ecx                    # Save it, probably not necessary.
+    movl    %eax, %cr3              # Set the new CR3.
+    subl    $4, %esp                # Dummy push for 16-byte stack alignment.
+    pushl   $0                      # Zero high word of selector.
+    pushl   $KERNEL_CS              # Push CS selector.
+    pushl   $0                      # Zero high word of return RIP.
+    pushl   $ProtectedModeReturn    # Push "return" address to protected mode.
+
+    ##
+    ## Enable paging.
+    ##
+
+    movl    %cr4, %eax              # Read CR4.
+    orl     $CR4_OR_MASK, %eax      # OR in the PAE bit and others.
+    movl    %eax, %cr4              # Set CR4.
+    movl    %cr0, %eax              # Read CR0.
+    orl     $CR0_OR_MASK, %eax      # OR in the right bits.
+    andl    $CR0_AND_MASK, %eax     # AND out the right bits.
+    movl    %eax, %cr0              # Boom, paging enabled.
+
+    ##
+    ## Enable long mode in EFER.
+    ##
+
+    movl    $X86_MSR_EFER, %ecx     # Get EFER as MSR register.
+    rdmsr                           # Read it.
+    orl     $EFER_LONG_MODE_ENABLE, %eax    # Enable long mode.
+    wrmsr                           # Write it.
+
+    ##
+    ## Perform a long jump to get to long mode. USER_CS was commandeered as a
+    ## 64-bit code selector. The next boot application will set up their own
+    ## GDT, so use of this selector is short lived.
+    ##
+
+movl    $TestLoaderFunction, %edx
+    ljmp    $USER_CS, $LongModeCode
+
+LongModeCode:
+.code64
+
+    ##
+    ## Wow, long mode. Call the next application.
+    ##
+
+    callq   *%rdx
+
+    ##
+    ## Perform a far return, which pops a return RIP and CS. This will switch
+    ## things back to 32-bit mode.
+    ##
+
+    retf
+
+    ## TODO: Remove this test function
+TestLoaderFunction:
+    movq    $0x12345678FEDBCA98, %rax
+    ret
+
+.code32
+ProtectedModeReturn:
+
+    ##
+    ## Disable paging.
+    ##
+
+    movl    %cr0, %ecx              # Get CR0.
+    andl    $~CR0_PAGING_ENABLE, %ecx   # Remove paging enable bit.
+    movl    %ecx, %cr0              # Save to disable paging.
+
+    ##
+    ## Restore things and return.
+    ##
+
+    addl    $4, %esp                # Remove the dummy alignment value.
+    popl    %edi                    # Pop the old CR3.
+    movl    %edi, %cr3              # Restore it.
+    popl    %esi                    # Restore esi.
+    popl    %edi                    # Restore the original edi.
+    leave                           # Set esp to ebp, and pop ebp.
+    ret
+
+END_FUNCTION(BmpFwTransferTo64BitApplication)
+
+##
+## --------------------------------------------------------- Internal Functions
+##
+

+ 164 - 0
boot/bootman/pcat/x64/xferc.c

@@ -0,0 +1,164 @@
+/*++
+
+Copyright (c) 2017 Minoca Corp.
+
+    This file is licensed under the terms of the GNU General Public License
+    version 3. Alternative licensing terms are available. Contact
+    info@minocacorp.com for details. See the LICENSE file at the root of this
+    project for complete licensing information.
+
+Module Name:
+
+    xferc.c
+
+Abstract:
+
+    This module implements the trampoline that transfers control to a 32 or 64
+    bit boot application.
+
+Author:
+
+    Evan Green 31-May-2017
+
+Environment:
+
+    Boot
+
+--*/
+
+//
+// ------------------------------------------------------------------- Includes
+//
+
+#include <minoca/kernel/kernel.h>
+#include <minoca/kernel/x86.h>
+#include "firmware.h"
+#include "bootlib.h"
+#include "../../bootman.h"
+
+//
+// --------------------------------------------------------------------- Macros
+//
+
+//
+// ---------------------------------------------------------------- Definitions
+//
+
+//
+// ------------------------------------------------------ Data Type Definitions
+//
+
+//
+// ----------------------------------------------- Internal Function Prototypes
+//
+
+INT
+BmpFwTransferTo64BitApplication (
+    PBOOT_INITIALIZATION_BLOCK Parameters,
+    PBOOT_APPLICATION_ENTRY EntryPoint,
+    ULONG PageDirectory
+    );
+
+//
+// -------------------------------------------------------------------- Globals
+//
+
+//
+// Reach around and grab at the GDT.
+//
+
+extern GDT_ENTRY BoGdt[GDT_ENTRIES];
+
+//
+// ------------------------------------------------------------------ Functions
+//
+
+INT
+BmpFwTransferToBootApplication (
+    PBOOT_INITIALIZATION_BLOCK Parameters,
+    PBOOT_APPLICATION_ENTRY EntryPoint
+    )
+
+/*++
+
+Routine Description:
+
+    This routine transfers control to another boot application.
+
+Arguments:
+
+    Parameters - Supplies a pointer to the initialization block.
+
+    EntryPoint - Supplies tne address of the entry point routine of the new
+        application.
+
+Return Value:
+
+    Returns the integer return value from the application. Often does not
+    return on success.
+
+--*/
+
+{
+
+    BOOL CanDoIt;
+    ULONG Eax;
+    ULONG Ebx;
+    ULONG Ecx;
+    ULONG Edx;
+    INT Result;
+
+    //
+    // If this is a 32-bit application, just call the function directly, no
+    // acrobatics needed.
+    //
+
+    if ((Parameters->Flags & BOOT_INITIALIZATION_FLAG_64BIT) == 0) {
+        return EntryPoint(Parameters);
+    }
+
+    //
+    // See if cpuid exposes the required leaf.
+    //
+
+    CanDoIt = FALSE;
+    Eax = X86_CPUID_EXTENDED_IDENTIFICATION;
+    ArCpuid(&Eax, &Ebx, &Ecx, &Edx);
+    if (Eax >= X86_CPUID_EXTENDED_INFORMATION) {
+
+        //
+        // See if long mode is supported.
+        //
+
+        Eax = X86_CPUID_EXTENDED_INFORMATION;
+        ArCpuid(&Eax, &Ebx, &Ecx, &Edx);
+        if ((Eax & X86_CPUID_EXTENDED_INFORMATION_EDX_LONG_MODE) != 0) {
+            CanDoIt = TRUE;
+        }
+    }
+
+    if (CanDoIt == FALSE) {
+        FwPrintString(0, 0, "CPU is not 64-bit");
+        return STATUS_NOT_SUPPORTED;
+    }
+
+    //
+    // Commandeer the USER_CS descriptor as a long mode code segment
+    // descriptor. The next boot application will set up their own GDT, so this
+    // is very short lived.
+    //
+
+    BoGdt[USER_CS / sizeof(GDT_ENTRY)] = BoGdt[KERNEL_CS / sizeof(GDT_ENTRY)];
+    BoGdt[USER_CS / sizeof(GDT_ENTRY)].Access |= GDT_ACCESS_LONG_MODE;
+    Result = BmpFwTransferTo64BitApplication(
+                                           Parameters,
+                                           EntryPoint,
+                                           (ULONG)(Parameters->PageDirectory));
+
+    return Result;
+}
+
+//
+// --------------------------------------------------------- Internal Functions
+//
+

+ 107 - 0
boot/bootman/pcat/x86/xferc.c

@@ -0,0 +1,107 @@
+/*++
+
+Copyright (c) 2017 Minoca Corp.
+
+    This file is licensed under the terms of the GNU General Public License
+    version 3. Alternative licensing terms are available. Contact
+    info@minocacorp.com for details. See the LICENSE file at the root of this
+    project for complete licensing information.
+
+Module Name:
+
+    xferc.c
+
+Abstract:
+
+    This module implements the trampoline that transfers control to another
+    32-bit boot application.
+
+Author:
+
+    Evan Green 31-May-2017
+
+Environment:
+
+    Boot
+
+--*/
+
+//
+// ------------------------------------------------------------------- Includes
+//
+
+#include <minoca/kernel/kernel.h>
+#include "firmware.h"
+#include "bootlib.h"
+#include "../../bootman.h"
+
+//
+// --------------------------------------------------------------------- Macros
+//
+
+//
+// ---------------------------------------------------------------- Definitions
+//
+
+//
+// ------------------------------------------------------ Data Type Definitions
+//
+
+//
+// ----------------------------------------------- Internal Function Prototypes
+//
+
+//
+// -------------------------------------------------------------------- Globals
+//
+
+//
+// ------------------------------------------------------------------ Functions
+//
+
+INT
+BmpFwTransferToBootApplication (
+    PBOOT_INITIALIZATION_BLOCK Parameters,
+    PBOOT_APPLICATION_ENTRY EntryPoint
+    )
+
+/*++
+
+Routine Description:
+
+    This routine transfers control to another boot application.
+
+Arguments:
+
+    Parameters - Supplies a pointer to the initialization block.
+
+    EntryPoint - Supplies tne address of the entry point routine of the new
+        application.
+
+Return Value:
+
+    Returns the integer return value from the application. Often does not
+    return on success.
+
+--*/
+
+{
+
+    INT Result;
+
+    if ((Parameters->Flags & BOOT_INITIALIZATION_FLAG_64BIT) != 0) {
+        FwPrintString(0,
+                      0,
+                      "Cannot launch 64-bit loader with 32-bit boot manager");
+
+        return STATUS_NOT_CONFIGURED;
+    }
+
+    Result = EntryPoint(Parameters);
+    return Result;
+}
+
+//
+// --------------------------------------------------------- Internal Functions
+//
+

+ 22 - 0
boot/bootman/sources

@@ -34,6 +34,26 @@ BINPLACE = bin
 OBJS     = bootman.o  \
            bootim.o   \
 
+##
+## The boot manager is a 32-bit fish in a 64-bit pond. All of its libraries
+## need to be specially compiled 32-bit versions.
+##
+
+ifeq ($(ARCH),x64)
+
+TARGETLIBS = $(OBJROOT)/os/lib/rtl/base/boot/x6432/basertlb.a      \
+             $(OBJROOT)/os/lib/rtl/kmode/x6432/krtl.a              \
+             $(OBJROOT)/os/lib/im/x6432/imu.a                      \
+             $(OBJROOT)/os/lib/fatlib/x6432/fat.a                  \
+             $(OBJROOT)/os/lib/basevid/x6432/basevid.a             \
+             $(OBJROOT)/os/lib/bconflib/x6432/bconflib.a           \
+             $(OBJROOT)/os/kernel/kd/boot/x6432/kdboot.a           \
+             $(OBJROOT)/os/kernel/kd/kdusb/kdnousb/x6432/kdnousb.a \
+             $(OBJROOT)/os/kernel/hl/boot/x6432/hlboot.a           \
+             $(OBJROOT)/os/kernel/mm/boot/x6432/mmboot.a           \
+
+else
+
 TARGETLIBS = $(OBJROOT)/os/lib/rtl/base/boot/basertlb.a      \
              $(OBJROOT)/os/lib/rtl/kmode/krtl.a              \
              $(OBJROOT)/os/lib/im/imu.a                      \
@@ -45,5 +65,7 @@ TARGETLIBS = $(OBJROOT)/os/lib/rtl/base/boot/basertlb.a      \
              $(OBJROOT)/os/kernel/hl/boot/hlboot.a           \
              $(OBJROOT)/os/kernel/mm/boot/mmboot.a           \
 
+endif
+
 EXTRA_SRC_DIRS = x86
 

+ 20 - 16
boot/loader/loader.c

@@ -293,7 +293,9 @@ Return Value:
     //
 
     RtlZeroMemory(&BoLoaderModuleBuffer, sizeof(BoLoaderModuleBuffer));
-    LoaderModuleNameLength = RtlStringLength(Parameters->ApplicationName) + 1;
+    LoaderModuleNameLength =
+              RtlStringLength((PVOID)(UINTN)(Parameters->ApplicationName)) + 1;
+
     if (LoaderModuleNameLength > LOADER_BINARY_NAME_MAX_SIZE) {
         LoaderModuleNameLength = LOADER_BINARY_NAME_MAX_SIZE;
     }
@@ -303,10 +305,12 @@ Return Value:
                                   (ANYSIZE_ARRAY * sizeof(CHAR));
 
     RtlStringCopy(LoaderModule->BinaryName,
-                  Parameters->ApplicationName,
+                  (PVOID)(UINTN)(Parameters->ApplicationName),
                   LoaderModuleNameLength);
 
-    LoaderModule->LowestAddress = Parameters->ApplicationLowestAddress;
+    LoaderModule->LowestAddress =
+                          (PVOID)(UINTN)(Parameters->ApplicationLowestAddress);
+
     LoaderModule->Size = Parameters->ApplicationSize;
     BoProductName = LOADER_NAME;
     if ((BoForceDebug != FALSE) ||
@@ -358,10 +362,10 @@ Return Value:
     //
 
     AlignedLoaderStart = (PVOID)(UINTN)ALIGN_RANGE_DOWN(
-                                 (UINTN)(Parameters->ApplicationLowestAddress),
-                                 PageSize);
+                                          Parameters->ApplicationLowestAddress,
+                                          PageSize);
 
-    PageOffset = (UINTN)(Parameters->ApplicationLowestAddress) -
+    PageOffset = Parameters->ApplicationLowestAddress -
                  (UINTN)AlignedLoaderStart;
 
     AlignedLoaderSize = ALIGN_RANGE_UP(Parameters->ApplicationSize + PageOffset,
@@ -400,9 +404,9 @@ Return Value:
     // global).
     //
 
-    StackBottom = (UINTN)Parameters->StackTop - Parameters->StackSize;
+    StackBottom = Parameters->StackTop - Parameters->StackSize;
     StackOutsideImage = TRUE;
-    if ((StackBottom >= (UINTN)Parameters->ApplicationLowestAddress) &&
+    if ((StackBottom >= Parameters->ApplicationLowestAddress) &&
         (Parameters->StackTop <
          Parameters->ApplicationLowestAddress + Parameters->ApplicationSize)) {
 
@@ -411,9 +415,7 @@ Return Value:
 
     if (StackOutsideImage != FALSE) {
         RoundedStackMinimum = ALIGN_RANGE_DOWN(StackBottom, PageSize);
-        RoundedStackMaximum = ALIGN_RANGE_UP((UINTN)Parameters->StackTop,
-                                             PageSize);
-
+        RoundedStackMaximum = ALIGN_RANGE_UP(Parameters->StackTop, PageSize);
         Status = BoMapPhysicalAddress((PVOID)&RoundedStackMinimum,
                                       RoundedStackMinimum,
                                       RoundedStackMaximum - RoundedStackMinimum,
@@ -1243,7 +1245,7 @@ Return Value:
         // the RSDT.
         //
 
-        RsdtTable = (PRSDT)RsdpTable->RsdtAddress;
+        RsdtTable = (PRSDT)(UINTN)RsdpTable->RsdtAddress;
         RsdtTableCount = (RsdtTable->Header.Length -
                           sizeof(DESCRIPTION_HEADER)) / sizeof(ULONG);
 
@@ -1266,9 +1268,9 @@ Return Value:
         //
 
         for (TableIndex = 0; TableIndex < RsdtTableCount; TableIndex += 1) {
-            FadtTable = (PFADT)RsdtTableEntry[TableIndex];
+            FadtTable = (PFADT)(UINTN)RsdtTableEntry[TableIndex];
             if (FadtTable->Header.Signature == FADT_SIGNATURE) {
-                DsdtTable = (PDESCRIPTION_HEADER)FadtTable->DsdtAddress;
+                DsdtTable = (PDESCRIPTION_HEADER)(UINTN)FadtTable->DsdtAddress;
                 if ((DsdtTable != NULL) &&
                     (DsdtTable->Signature == DSDT_SIGNATURE)) {
 
@@ -1424,7 +1426,7 @@ Return Value:
 
         RtlCopyMemory(NewTable, SmbiosTable, sizeof(SMBIOS_ENTRY_POINT));
         RtlCopyMemory(NewTable + sizeof(SMBIOS_ENTRY_POINT),
-                      (PVOID)(SmbiosTable->StructureTableAddress),
+                      (PVOID)(UINTN)(SmbiosTable->StructureTableAddress),
                       SmbiosTable->StructureTableLength);
 
         TableEntry[TableDirectory->TableCount] = NewTable;
@@ -1861,7 +1863,9 @@ Return Value:
     RtlZeroMemory(BootConfiguration, sizeof(BOOT_CONFIGURATION_CONTEXT));
     BootConfiguration->AllocateFunction = BoAllocateMemory;
     BootConfiguration->FreeFunction = BoFreeMemory;
-    BootConfiguration->FileData = Parameters->BootConfigurationFile;
+    BootConfiguration->FileData =
+                             (PVOID)(UINTN)(Parameters->BootConfigurationFile);
+
     BootConfiguration->FileDataSize = Parameters->BootConfigurationFileSize;
     Status = BcInitializeContext(BootConfiguration);
     if (!KSUCCESS(Status)) {

+ 31 - 22
include/minoca/kernel/bootload.h

@@ -33,7 +33,7 @@ Author:
 // ---------------------------------------------------------------- Definitions
 //
 
-#define BOOT_INITIALIZATION_BLOCK_VERSION 3
+#define BOOT_INITIALIZATION_BLOCK_VERSION 4
 
 #define KERNEL_INITIALIZATION_BLOCK_VERSION 4
 
@@ -42,6 +42,7 @@ Author:
 //
 
 #define BOOT_INITIALIZATION_FLAG_SCREEN_CLEAR 0x00000001
+#define BOOT_INITIALIZATION_FLAG_64BIT 0x00000002
 
 //
 // Define the initial size of the memory allocation to hand to the hardware
@@ -87,30 +88,32 @@ Structure Description:
     This structure stores the information passed between the boot manager and
     OS loader or other boot application. Future versions of this structure must
     be backwards compatible as newer boot managers may pass control over to
-    older OS loaders.
+    older OS loaders. Pointers here are saved as 64-bit values because this
+    structure may be passed from a 32-bit boot manager to a 64-bit OS loader.
 
 Members:
 
     Version - Stores the version number of the loader initialization block.
         Set to BOOT_INITIALIZATION_BLOCK_VERSION.
 
-    BootConfigurationFile - Stores a pointer to a buffer containing the
-        contents of the boot configuration file.
-
     BootConfigurationFileSize - Stores the size of the boot configuration file
         buffer in bytes.
 
-    BootEntryId - Stores the identifier of the selected boot entry.
+    BootConfigurationFile - Stores a pointer to a buffer containing the
+        contents of the boot configuration file.
 
     BootEntryFlags - Stores the flags associated with this boot entry. See
         BOOT_ENTRY_FLAG_* definitions.
 
-    ReservedRegions - Stores a pointer to an array of reserved regions of
-        memeory that may or may not be in the firmware memory map.
+    BootEntryId - Stores the identifier of the selected boot entry.
 
     ReservedRegionCount - Stores the number of reserved region structures in
         the array.
 
+    ReservedRegions - Stores a pointer to an array of reserved regions of
+        memeory that may or may not be in the firmware memory map. This array
+        is of type BOOT_RESERVED_REGION.
+
     StackTop - Stores a pointer to the top of the stack.
 
     StackSize - Stores the size of the boot stack region, in bytes.
@@ -126,9 +129,6 @@ Members:
         disk to the OS partition if the firmware doesn't support partitions
         natively.
 
-    DriveNumber - Stores the drive number of the OS partition for legacy PC/AT
-        systems.
-
     ApplicationName - Stores a pointer to a string containing the file name of
         the application being launched.
 
@@ -141,6 +141,13 @@ Members:
     ApplicationArguments - Stores a pointer to a null terminated string
         containing the command-line-esque arguments to the application.
 
+    PageDirectory - Stores the address of the top level page table in use.
+
+    PageTables - Stores the address of the page table self map.
+
+    DriveNumber - Stores the drive number of the OS partition for legacy PC/AT
+        systems.
+
     Flags - Stores flags describing the environment state. See
         BOOT_INITIALIZATION_FLAG_* definitions.
 
@@ -148,22 +155,24 @@ Members:
 
 typedef struct _BOOT_INITIALIZATION_BLOCK {
     ULONG Version;
-    PVOID BootConfigurationFile;
     ULONG BootConfigurationFileSize;
-    ULONG BootEntryId;
+    ULONGLONG BootConfigurationFile;
     ULONGLONG BootEntryFlags;
-    PBOOT_RESERVED_REGION ReservedRegions;
+    ULONG BootEntryId;
     ULONG ReservedRegionCount;
-    PVOID StackTop;
-    UINTN StackSize;
-    PVOID EfiImageHandle;
-    PVOID EfiSystemTable;
+    ULONGLONG ReservedRegions;
+    ULONGLONG StackTop;
+    ULONGLONG StackSize;
+    ULONGLONG EfiImageHandle;
+    ULONGLONG EfiSystemTable;
     ULONGLONG PartitionOffset;
+    ULONGLONG ApplicationName;
+    ULONGLONG ApplicationLowestAddress;
+    ULONGLONG ApplicationSize;
+    ULONGLONG ApplicationArguments;
+    ULONGLONG PageDirectory;
+    ULONGLONG PageTables;
     ULONG DriveNumber;
-    PCSTR ApplicationName;
-    PVOID ApplicationLowestAddress;
-    UINTN ApplicationSize;
-    PCSTR ApplicationArguments;
     ULONG Flags;
 } BOOT_INITIALIZATION_BLOCK, *PBOOT_INITIALIZATION_BLOCK;