[BOOTMGR]: Support for launching a recovery sequence.
authorAlex Ionescu <aionescu@gmail.com>
Tue, 19 Jan 2016 18:21:54 +0000 (18:21 +0000)
committerAlex Ionescu <aionescu@gmail.com>
Tue, 19 Jan 2016 18:21:54 +0000 (18:21 +0000)
[BOOTMGR]: Stub support for boot errors.
[BOOTMGR]: Stubplement support for device creation for boot applications (only for fully specified devices)
[BOOTMGR]: Implement support for execution transfer, including recovery mode/sequence.
[BOOTMGR]: Implement support for launching a boot entry.
[BOOTLIB]: Support for EFI Firmware device enumeration, driver attachment, and comparison.
[BOOTLIB]: Support for appending BOOLEAN or INTEGER BCD options.
Next step is the PE loader.

svn path=/trunk/; revision=70618

reactos/boot/environ/app/bootmgr/bootmgr.c
reactos/boot/environ/include/bcd.h
reactos/boot/environ/include/bl.h
reactos/boot/environ/lib/firmware/efi/firmware.c
reactos/boot/environ/lib/io/device.c
reactos/boot/environ/lib/misc/bcdopt.c

index ae31bb0..b2a1bdc 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * COPYRIGHT:       See COPYING.ARM in the top level directory
  * PROJECT:         ReactOS UEFI Boot Manager
- * FILE:            boot/environ/app/bootmgr/bootmgr.c
+ * FILE:            boot/environ/app/bootmgr/bootmgr.cla
  * PURPOSE:         Boot Manager Entrypoint
  * PROGRAMMER:      Alex Ionescu (alex.ionescu@reactos.org)
  */
@@ -2033,15 +2033,564 @@ NTSTATUS
 BmpLaunchBootEntry (
     _In_ PBL_LOADED_APPLICATION_ENTRY BootEntry,
     _Out_ PULONG EntryIndex,
-    _In_ ULONG Unknown,
+    _In_ ULONG LaunchCode,
     _In_ BOOLEAN LaunchWinRe
+    );
+
+NTSTATUS 
+BmLaunchRecoverySequence (
+    _In_ PBL_LOADED_APPLICATION_ENTRY BootEntry,
+    _In_ ULONG LaunchCode
     )
 {
-    EfiPrintf(L"Boot launch not yet implemented\r\n");
-    EfiStall(1000000000);
+    NTSTATUS Status;
+    PBL_LOADED_APPLICATION_ENTRY RecoveryEntry;
+    HANDLE BcdHandle;
+    PGUID RecoverySequence;
+    ULONG Count, i, RecoveryIndex, SequenceCount;
+    PBL_LOADED_APPLICATION_ENTRY* Sequence;
+
+    RecoveryIndex = 0;
+    Sequence = NULL;
+    RecoverySequence = NULL;
+    Count = 0;
+    BcdHandle = NULL;
+
+    Status = BmOpenDataStore(&BcdHandle);
+    if (NT_SUCCESS(Status))
+    {
+        Status = BlGetBootOptionGuidList(BootEntry->BcdData,
+                                         BcdLibraryObjectList_RecoverySequence,
+                                         &RecoverySequence,
+                                         &SequenceCount);
+        if (NT_SUCCESS(Status))
+        {
+            Status = BmGetBootSequence(BcdHandle,
+                                       RecoverySequence,
+                                       SequenceCount,
+                                       BL_APPLICATION_ENTRY_RECOVERY,
+                                       &Sequence,
+                                       &Count);
+            if (NT_SUCCESS(Status))
+            {
+                if (BcdHandle)
+                {
+                    BmCloseDataStore(BcdHandle);
+                }
+
+                for (i = 0; i < Count; ++i)
+                {
+                    if (LaunchCode == 2 || LaunchCode == 5)
+                    {
+                        BlRemoveBootOption(Sequence[i]->BcdData, BcdLibraryInteger_DisplayMessageOverride);
+                        BlAppendBootOptionInteger(Sequence[i],
+                                                  BcdLibraryInteger_DisplayMessageOverride,
+                                                  4);
+                    }
+                    else if (LaunchCode == 3)
+                    {
+                        BlRemoveBootOption(Sequence[i]->BcdData, BcdLibraryInteger_DisplayMessageOverride);
+                        BlAppendBootOptionInteger(Sequence[i],
+                                                  BcdLibraryInteger_DisplayMessageOverride,
+                                                  10);
+                    }
+
+                    Status = BmpLaunchBootEntry(Sequence[i], NULL, LaunchCode, FALSE);
+                    if (!NT_SUCCESS(Status))
+                    {
+                        break;
+                    }
+                }
+            }
+
+            if (Sequence)
+            {
+                for (RecoveryIndex = 0; RecoveryIndex < Count; RecoveryIndex++)
+                {
+                    RecoveryEntry = Sequence[RecoveryIndex];
+                    if (RecoveryEntry)
+                    {
+                        BlDestroyBootEntry(RecoveryEntry);
+                    }
+                }
+                BlMmFreeHeap(Sequence);
+            }
+        }
+
+        if (RecoverySequence)
+        {
+            BlMmFreeHeap(RecoverySequence);
+        }
+    }
+
+    return Status;
+}
+
+ULONG
+BmDisplayDumpError (
+    _In_ PBL_LOADED_APPLICATION_ENTRY BootEntry,
+    _In_ ULONG LaunchCode
+    )
+{
+    ULONG BootError;
+    NTSTATUS Status;
+    BOOLEAN Restart, NoError;
+
+    BootError = 1;
+
+    Status = BlGetBootOptionBoolean(BlpApplicationEntry.BcdData,
+                                    BcdLibraryBoolean_RestartOnFailure,
+                                    &Restart);
+    if ((NT_SUCCESS(Status)) && (Restart))
+    {
+        return BootError;
+    }
+
+    Status = BlGetBootOptionBoolean(BlpApplicationEntry.BcdData,
+                                    BcdBootMgrBoolean_NoErrorDisplay,
+                                    &NoError);
+    if ((NT_SUCCESS(Status)) && (NoError))
+    {
+        return BootError;
+    }
+
+    if (BmpInternalBootError)
+    {
+        return (ULONG)BmpInternalBootError; // ???
+    }
+
+    EfiPrintf(L"Error menu not yet implemented\r\n");
+    return BootError;
+}
+
+NTSTATUS
+BmpCreateDevices (
+    _In_ PBL_LOADED_APPLICATION_ENTRY BootEntry
+    )
+{
+    ULONG NextOffset, DataOffset, ListOffset;
+    PBL_BCD_OPTION Option, ListOption;
+    BcdElementType ElementType;
+    PBCD_DEVICE_OPTION BcdDevice;
+
+    NextOffset = 0;
+    do
+    {
+        Option = (PBL_BCD_OPTION)((ULONG_PTR)BootEntry->BcdData + NextOffset);
+        NextOffset = Option->NextEntryOffset;
+
+        if (Option->Empty)
+        {
+            continue;
+        }
+
+        ElementType.PackedValue = Option->Type;
+        if (ElementType.Format != BCD_TYPE_DEVICE)
+        {
+            continue;
+        }
+
+        DataOffset = Option->DataOffset;
+
+        BcdDevice = (PBCD_DEVICE_OPTION)((ULONG_PTR)BootEntry->BcdData + DataOffset);
+        if (!(BcdDevice->DeviceDescriptor.Flags & 1))
+        {
+            continue;
+        }
+
+        ListOption = NULL;
+        ListOffset = Option->ListOffset;
+        if (Option->ListOffset)
+        {
+            ListOption = (PBL_BCD_OPTION)((ULONG_PTR)BootEntry->BcdData + ListOffset);
+        }
+
+        EfiPrintf(L"Unspecified devices not yet supported: %p\r\n", ListOption);
+        return STATUS_NOT_SUPPORTED;
+    } while (NextOffset != 0);
+
+    return STATUS_SUCCESS;
+}
+
+/* MOVE TO IMAGe.C */
+NTSTATUS
+BlImgLoadBootApplication (
+    _In_ PBL_LOADED_APPLICATION_ENTRY BootEntry,
+    _Out_ PHANDLE AppHandle
+    )
+{
+    EfiPrintf(L"Loading application %p\r\n", BootEntry);
+
+    return STATUS_NOT_IMPLEMENTED;
+}
+
+NTSTATUS
+BlImgStartBootApplication (
+    _In_ HANDLE AppHandle,
+    _Inout_ PBL_RETURN_ARGUMENTS ReturnArguments
+    )
+{
+    EfiPrintf(L"Starting application %p\r\n", AppHandle);
+
     return STATUS_NOT_IMPLEMENTED;
 }
 
+NTSTATUS
+BlImgUnloadBootApplication (
+    _In_ HANDLE AppHandle
+    )
+{
+    EfiPrintf(L"Unloading application %p\r\n", AppHandle);
+
+    return STATUS_NOT_IMPLEMENTED;
+}
+
+NTSTATUS
+BmpTransferExecution (
+    _In_ PBL_LOADED_APPLICATION_ENTRY BootEntry,
+    _Out_ PULONG LaunchCode,
+    _Out_ PBOOLEAN Recover
+    )
+{
+    PWCHAR AppPath;
+    NTSTATUS Status;
+    PBL_DEVICE_DESCRIPTOR AppDevice;
+    BL_RETURN_ARGUMENTS ReturnArgs;
+    BOOLEAN AdvancedOptions;
+    HANDLE AppHandle;
+
+    Status = BlGetBootOptionString(BootEntry->BcdData,
+                                   BcdLibraryString_ApplicationPath,
+                                   &AppPath);
+    if (!NT_SUCCESS(Status))
+    {
+        AppPath = NULL;
+    }
+
+    if (BootEntry->Flags & BL_APPLICATION_ENTRY_STARTUP)
+    {
+#if BL_NET_SUPPORT
+        Status = BlNetSoftReboot(BootEntry);
+#else
+        EfiPrintf(L"Net boot not supported\r\n");
+        Status = STATUS_NOT_SUPPORTED;
+#endif
+        goto Quickie;
+    }
+
+    do
+    {
+        Status = BlImgLoadBootApplication(BootEntry, &AppHandle);
+        if (Status == STATUS_NOT_FOUND)
+        {
+            Status = BlGetBootOptionDevice(BootEntry->BcdData,
+                                           BcdLibraryDevice_ApplicationDevice,
+                                           &AppDevice,
+                                           NULL);
+            if (NT_SUCCESS(Status))
+            {
+                Status = BlFwEnumerateDevice(AppDevice);
+            }
+
+            if (!NT_SUCCESS(Status))
+            {
+                BmFatalErrorEx(2, (ULONG_PTR)AppPath, Status, 0, 0);
+                goto Quickie;
+            }
+
+            Status = BlImgLoadBootApplication(BootEntry, &AppHandle);
+        }
+
+        if (Status == STATUS_CANCELLED)
+        {
+            if ((BmGetBootMenuPolicy(BootEntry) != MenuPolicyStandard) ||
+                !(MiscGetBootOption(BootEntry->BcdData,
+                                    BcdLibraryObjectList_RecoverySequence)))
+            {
+                goto Quickie;
+            }
+
+            *LaunchCode = 4;
+            *Recover = TRUE;
+            goto Quickie;
+        }
+
+        if (Status == 0xC0210000)
+        {
+            *LaunchCode = 4;
+            *Recover = TRUE;
+            goto Quickie;
+        }
+
+        if (!NT_SUCCESS(Status))
+        {
+            BmFatalErrorEx(2, (ULONG_PTR)AppPath, Status, 0, 0);
+            goto Quickie;
+        }
+
+        RtlZeroMemory(&ReturnArgs, sizeof(ReturnArgs));
+        //BmpLogApplicationLaunchEvent(&BootEntry->Guid, AppPath);
+
+        Status = BlImgStartBootApplication(AppHandle, &ReturnArgs);
+
+#if BL_BITLOCKER_SUPPORT
+        BlFveSecureBootCheckpointAppReturn(BootEntry, &ReturnArgs);
+#endif
+
+        //BlBsdLogEntry(1, 0x12, &BootEntry->Guid, 0x14);
+
+        BlImgUnloadBootApplication(AppHandle);
+
+    } while (Status != 0xC0000453);
+
+    *Recover = TRUE;
+    if (ReturnArgs.Flags & 1)
+    {
+        Status = BlGetBootOptionBoolean(BootEntry->BcdData,
+                                        BcdLibraryBoolean_DisplayAdvancedOptions,
+                                        &AdvancedOptions);
+        if ((NT_SUCCESS(Status)) && (AdvancedOptions))
+        {
+            *LaunchCode = 2;
+        }
+        else
+        {
+            *LaunchCode = 1;
+        }
+    }
+    else if (ReturnArgs.Flags & 4)
+    {
+        *LaunchCode = 1;
+    }
+    else if (ReturnArgs.Flags & 8)
+    {
+        *LaunchCode = 5;
+    }
+    else if (ReturnArgs.Flags & 0x10)
+    {
+        *LaunchCode = 6;
+    }
+    else if (ReturnArgs.Flags & 0x20)
+    {
+        *LaunchCode = 7;
+    }
+    else if (ReturnArgs.Flags & 0x40)
+    {
+        *Recover = FALSE;
+        BmFatalErrorEx(11, Status, 0, 0, 0);
+    }
+
+Quickie:
+    if (AppPath)
+    {
+        BlMmFreeHeap(AppPath);
+    }
+
+    return Status;
+}
+
+NTSTATUS
+BmpLaunchBootEntry (
+    _In_ PBL_LOADED_APPLICATION_ENTRY BootEntry,
+    _Out_ PULONG EntryIndex,
+    _In_ ULONG LaunchCode,
+    _In_ BOOLEAN LaunchWinRe
+    )
+{
+    HANDLE BcdHandle;
+    NTSTATUS Status;
+    GUID ObjectId;
+    BOOLEAN DoRecovery, AutoRecovery, DoRestart, RestartOnFailure;
+    ULONG ErrorCode;
+    BOOLEAN AdvancedOneTime, EditOneTime, Recover;
+
+    if (BootEntry->Flags & BL_APPLICATION_ENTRY_WINLOAD)
+    {
+        if (MiscGetBootOption(BootEntry->BcdData, BcdOSLoaderBoolean_AdvancedOptionsOneTime))
+        {
+            BcdHandle = NULL;
+            Status = BmOpenDataStore(BcdHandle);
+            if (NT_SUCCESS(Status))
+            {
+                ObjectId = BootEntry->Guid;
+                BmPurgeOption(BcdHandle, &ObjectId, BcdOSLoaderBoolean_AdvancedOptionsOneTime);
+                BmCloseDataStore(BcdHandle);
+            }
+        }
+        if (MiscGetBootOption(BootEntry->BcdData, BcdOSLoaderBoolean_OptionsEditOneTime))
+        {
+            BcdHandle = NULL;
+            Status = BmOpenDataStore(BcdHandle);
+            if (NT_SUCCESS(Status))
+            {
+                ObjectId = BootEntry->Guid;
+                BmPurgeOption(BcdHandle, &ObjectId, BcdOSLoaderBoolean_OptionsEditOneTime);
+                BmCloseDataStore(BcdHandle);
+            }
+        }
+    }
+
+TryAgain:
+    DoRecovery = FALSE;
+    Recover = FALSE;
+    BmpSelectedBootEntry = BootEntry;
+
+    Status = BmpCreateDevices(BootEntry);
+    if (!NT_SUCCESS(Status))
+    {
+        if (!LaunchWinRe)
+        {
+            return Status;
+        }
+
+        LaunchCode = 2;
+        goto Quickie;
+    }
+
+    if (BootEntry->Flags & BL_APPLICATION_ENTRY_WINLOAD)
+    {
+        Status = BlGetBootOptionBoolean(BootEntry->BcdData, BcdOSLoaderBoolean_AdvancedOptionsOneTime, &AdvancedOneTime);
+        if (NT_SUCCESS(Status))
+        {
+            if (AdvancedOneTime)
+            {
+                BlAppendBootOptionBoolean(BootEntry, BcdLibraryBoolean_DisplayAdvancedOptions);
+            }
+            else
+            {
+                BlRemoveBootOption(BootEntry->BcdData, BcdLibraryBoolean_DisplayAdvancedOptions);
+            }
+
+            BlRemoveBootOption(BootEntry->BcdData, BcdOSLoaderBoolean_AdvancedOptionsOneTime);
+        }
+
+        Status = BlGetBootOptionBoolean(BootEntry->BcdData, BcdOSLoaderBoolean_OptionsEditOneTime, &EditOneTime);
+        if (NT_SUCCESS(Status))
+        {
+            if (AdvancedOneTime)
+            {
+                BlAppendBootOptionBoolean(BootEntry, BcdLibraryBoolean_DisplayOptionsEdit);
+            }
+            else
+            {
+                BlRemoveBootOption(BootEntry->BcdData, BcdLibraryBoolean_DisplayOptionsEdit);
+            }
+
+            BlRemoveBootOption(BootEntry->BcdData, BcdOSLoaderBoolean_OptionsEditOneTime);
+        }
+    }
+
+    Status = BmpTransferExecution(BootEntry, &LaunchCode, &Recover);
+    if (!LaunchWinRe)
+    {
+        return Status;
+    }
+
+    DoRecovery = Recover;
+
+    if (((NT_SUCCESS(Status)) || (Status == STATUS_CANCELLED)) && !(Recover))
+    {
+        return Status;
+    }
+
+    if (!Recover)
+    {
+        LaunchCode = 2;
+        goto Quickie;
+    }
+
+Quickie:
+    if (MiscGetBootOption(BootEntry->BcdData, BcdLibraryObjectList_RecoverySequence))
+    {
+        if ((LaunchCode == 3) || (LaunchCode == 5) || (LaunchCode == 6))
+        {
+            Status = BlGetBootOptionBoolean(BootEntry->BcdData, BcdLibraryBoolean_AutoRecoveryEnabled, &AutoRecovery);
+            if (NT_SUCCESS(Status))
+            {
+                DoRecovery = AutoRecovery;
+            }
+        }
+    }
+    else
+    {
+        DoRecovery = FALSE;
+    }
+
+    RestartOnFailure = FALSE;
+    BlGetBootOptionBoolean(BlpApplicationEntry.BcdData, BcdLibraryBoolean_RestartOnFailure, &RestartOnFailure);
+    DoRestart = RestartOnFailure ? FALSE : DoRecovery;
+    while (1)
+    {
+        if (DoRestart)
+        {
+            if (AutoRecovery)
+            {
+                //BlFveRegisterBootEntryForTrustedWimBoot(BootEntry, TRUE);
+            }
+
+            Status = BmLaunchRecoverySequence(BootEntry, LaunchCode);
+
+            if (AutoRecovery)
+            {
+                //BlFveRegisterBootEntryForTrustedWimBoot(BootEntry, FALSE);
+                AutoRecovery = FALSE;
+            }
+
+            if (NT_SUCCESS(Status))
+            {
+                return STATUS_SUCCESS;
+            }
+
+            BlRemoveBootOption(BootEntry->BcdData, BcdLibraryObjectList_RecoverySequence);
+        }
+
+        if (!BmpInternalBootError)
+        {
+            BmFatalErrorEx(4, Status, 0, 0, 0);
+        }
+
+        ErrorCode = BmDisplayDumpError(BootEntry, LaunchCode);
+        BmErrorPurge();
+
+        switch (ErrorCode)
+        {
+            case 6:
+                goto TryAgain;
+            case 5:
+                break;
+            case 4:
+                return STATUS_CANCELLED;
+            case 3:
+                Status = BmOpenDataStore(BcdHandle);
+                if (NT_SUCCESS(Status))
+                {
+                    Status = BmProcessCustomAction(BcdHandle, NULL);
+                }
+                if (BcdHandle)
+                {
+                    BmCloseDataStore(BcdHandle);
+                }
+                return Status;
+            case 7:
+                BlAppendBootOptionBoolean(BootEntry, BcdOSLoaderBoolean_AdvancedOptionsOneTime);
+                goto TryAgain;
+            case 8:
+                BlAppendBootOptionBoolean(BootEntry, BcdOSLoaderBoolean_OptionsEditOneTime);
+                goto TryAgain;
+            case 2:
+                DoRestart = TRUE;
+                LaunchCode = 1;
+                goto TryAgain;
+            default:
+                return STATUS_CANCELLED;
+        }
+    }
+
+
+
+    return STATUS_SUCCESS;
+}
+
 /*++
  * @name BmMain
  *
index 6d21720..4a606ec 100644 (file)
@@ -92,6 +92,8 @@ typedef enum BcdLibraryElementTypes
     BcdLibraryInteger_FveBandId = 0x1500004C,
     BcdLibraryBoolean_ConsoleExtendedInput = 0x16000050,
     BcdLibraryInteger_GraphicsResolution = 0x15000052,
+    BcdLibraryInteger_DisplayMessage = 0x15000065, /* Undocumented */
+    BcdLibraryInteger_DisplayMessageOverride = 0x15000066, /* Undocumented */
     BcdLibraryBoolean_RestartOnFailure = 0x16000053,
     BcdLibraryBoolean_GraphicsForceHighestMode = 0x16000054,
     BcdLibraryBoolean_IsolatedExecutionContext = 0x16000060,
@@ -151,6 +153,7 @@ typedef enum BcdOSLoaderElementTypes
     BcdOSLoaderInteger_DriverLoadFailurePolicy = 0x250000c1,
     BcdOSLoaderInteger_BootMenuPolicy = 0x250000C2,
     BcdOSLoaderBoolean_AdvancedOptionsOneTime = 0x260000C3,
+    BcdOSLoaderBoolean_OptionsEditOneTime = 0x260000C4, /* Undocumented */
     BcdOSLoaderInteger_BootStatusPolicy = 0x250000E0,
     BcdOSLoaderBoolean_DisableElamDrivers = 0x260000E1,
     BcdOSLoaderInteger_HypervisorLaunchType = 0x250000F0,
index 1d11349..68ce20e 100644 (file)
@@ -77,6 +77,7 @@ DEFINE_GUID(BadMemoryGuid, 0x54B8275B, 0xD431, 0x473F, 0xAC, 0xFB, 0xE5, 0x36, 0
 #define BL_APPLICATION_ENTRY_BOOTMGR                    0x1000
 #define BL_APPLICATION_ENTRY_DISPLAY_ORDER              0x800000
 #define BL_APPLICATION_ENTRY_FIXED_SEQUENCE             0x20000000
+#define BL_APPLICATION_ENTRY_RECOVERY                   0x40000000
 
 #define BL_CONTEXT_PAGING_ON                            1
 #define BL_CONTEXT_INTERRUPTS_ON                        2
@@ -110,6 +111,8 @@ DEFINE_GUID(BadMemoryGuid, 0x54B8275B, 0xD431, 0x473F, 0xAC, 0xFB, 0xE5, 0x36, 0
 #define BL_FS_REGISTER_AT_HEAD_FLAG                     1
 
 #define BL_BLOCK_DEVICE_REMOVABLE_FLAG                  0x01
+#define BL_BLOCK_DEVICE_PRESENT_FLAG                    0x02
+#define BL_BLOCK_DEVICE_VIRTUAL_FLAG                    0x04
 
 #define BL_MEMORY_CLASS_SHIFT                           28
 
@@ -685,7 +688,9 @@ typedef struct _BL_RETURN_ARGUMENTS
 {
     ULONG Version;
     NTSTATUS Status;
-    ULONG ReturnArgumentData[5];
+    ULONG Flags;
+    ULONGLONG DataSize;
+    ULONGLONG DataPage;
 } BL_RETURN_ARGUMENTS, *PBL_RETURN_ARGUMENTS;
 
 typedef struct _BL_MEMORY_DESCRIPTOR
@@ -794,8 +799,10 @@ typedef struct _BL_LOCAL_DEVICE
             LARGE_INTEGER ImageSize;
             ULONG ImageOffset;
         } RamDisk;
+
+        ULONG File; // unknown for now
     };
-} BL_LOCAL_DEVICE;
+} BL_LOCAL_DEVICE, *PBL_LOCAL_DEVICE;
 
 typedef struct _BL_DEVICE_DESCRIPTOR
 {
@@ -1316,6 +1323,11 @@ EfiPrintf (
     ...
     );
 
+NTSTATUS
+BlFwEnumerateDevice (
+    _In_ PBL_DEVICE_DESCRIPTOR Device
+    );
+
 NTSTATUS
 EfiAllocatePages (
     _In_ ULONG Type,
@@ -1776,6 +1788,19 @@ BlCopyBootOptions (
     _Out_ PBL_BCD_OPTION *CopiedOptions
     );
 
+NTSTATUS
+BlAppendBootOptionBoolean (
+    _In_ PBL_LOADED_APPLICATION_ENTRY AppEntry,
+    _In_ ULONG OptionId
+    );
+
+NTSTATUS
+BlAppendBootOptionInteger (
+    _In_ PBL_LOADED_APPLICATION_ENTRY AppEntry,
+    _In_ ULONG OptionId,
+    _In_ ULONGLONG Value
+    );
+
 NTSTATUS
 BlAppendBootOptionString (
     _In_ PBL_LOADED_APPLICATION_ENTRY AppEntry,
@@ -2142,6 +2167,14 @@ BlFileOpen (
     _Out_ PULONG FileId
     );
 
+/* BLOCK I/O ROUTINES *******************************************************/
+
+NTSTATUS
+BlockIoEfiCompareDevice (
+    _In_ PBL_DEVICE_DESCRIPTOR Device,
+    _In_ EFI_HANDLE Handle
+    );
+
 /* INPUT CONSOLE ROUTINES ****************************************************/
 
 VOID
index 18d9751..4e4eb4c 100644 (file)
@@ -1049,6 +1049,42 @@ EfiResetSystem (
     EfiRT->ResetSystem(ResetType, EFI_SUCCESS, 0, NULL);
 }
 
+NTSTATUS
+EfiConnectController (
+    _In_ EFI_HANDLE ControllerHandle
+    )
+{
+    BL_ARCH_MODE OldMode;
+    EFI_STATUS EfiStatus;
+
+    /* Is this EFI 1.02? */
+    if (EfiST->Hdr.Revision == EFI_1_02_SYSTEM_TABLE_REVISION)
+    {
+        /* This function didn't exist back then */
+        return STATUS_NOT_SUPPORTED;
+    }
+
+    /* Are we in protected mode? */
+    OldMode = CurrentExecutionContext->Mode;
+    if (OldMode != BlRealMode)
+    {
+        /* FIXME: Not yet implemented */
+        return STATUS_NOT_IMPLEMENTED;
+    }
+
+    /* Make the EFI call */
+    EfiStatus = EfiBS->ConnectController(ControllerHandle, NULL, NULL, TRUE);
+
+    /* Switch back to protected mode if we came from there */
+    if (OldMode != BlRealMode)
+    {
+        BlpArchSwitchContext(OldMode);
+    }
+
+    /* Convert the error to an NTSTATUS */
+    return EfiGetNtStatusCode(EfiStatus);
+}
+
 NTSTATUS
 EfiAllocatePages (
     _In_ ULONG Type,
@@ -1748,6 +1784,91 @@ BlpFwInitialize (
     return Status;
 }
 
+NTSTATUS
+BlFwEnumerateDevice (
+    _In_ PBL_DEVICE_DESCRIPTOR Device
+    )
+{
+    NTSTATUS Status;
+    ULONG PathProtocols, BlockProtocols;
+    EFI_HANDLE* PathArray;
+    EFI_HANDLE* BlockArray;
+
+    /* Initialize locals */
+    BlockArray = NULL;
+    PathArray = NULL;
+    PathProtocols = 0;
+    BlockProtocols = 0;
+
+    /* Enumeration only makes sense on disks or partitions */
+    if ((Device->DeviceType != DiskDevice) &&
+        (Device->DeviceType != LegacyPartitionDevice) &&
+        (Device->DeviceType != PartitionDevice))
+    {
+        return STATUS_NOT_SUPPORTED;
+    }
+
+    /* Enumerate the list of device paths */
+    Status = EfiLocateHandleBuffer(ByProtocol,
+                                   &EfiDevicePathProtocol,
+                                   &PathProtocols,
+                                   &PathArray);
+    if (NT_SUCCESS(Status))
+    {
+        /* Loop through each one */
+        Status = STATUS_NOT_FOUND;
+        while (PathProtocols)
+        {
+            /* Attempt to connect the driver for this device epath */
+            Status = EfiConnectController(PathArray[--PathProtocols]);
+            if (NT_SUCCESS(Status))
+            {
+                /* Now enumerate any block I/O devices the driver added */
+                Status = EfiLocateHandleBuffer(ByProtocol,
+                                               &EfiBlockIoProtocol,
+                                               &BlockProtocols,
+                                               &BlockArray);
+                if (!NT_SUCCESS(Status))
+                {
+                    break;
+                }
+
+                /* Loop through each one */
+                while (BlockProtocols)
+                {
+                    /* Check if one of the new devices is the one we want */
+                    Status = BlockIoEfiCompareDevice(Device,
+                                                     BlockArray[--BlockProtocols]);
+                    if (NT_SUCCESS(Status))
+                    {
+                        /* Yep, all done */
+                        goto Quickie;
+                    }
+                }
+
+                /* Move on to the next device path */
+                BlMmFreeHeap(BlockArray);
+                BlockArray = NULL;
+            }
+        }
+    }
+
+Quickie:
+    /* We're done -- free the array of device path protocols, if any */
+    if (PathArray)
+    {
+        BlMmFreeHeap(PathArray);
+    }
+
+    /* We're done -- free the array of block I/O protocols, if any */
+    if (BlockArray)
+    {
+        BlMmFreeHeap(BlockArray);
+    }
+
+    /* Return if we found the device or not */
+    return Status;
+}
 
 /*++
  * @name EfiGetEfiStatusCode
index 9c11eec..4095725 100644 (file)
@@ -371,7 +371,7 @@ BlockIopReadPhysicalDevice (
     )
 {
     PBL_BLOCK_DEVICE BlockDevice;
-    PVOID ReadBuffer; // edi@1
+    PVOID ReadBuffer;
     ULONGLONG OffsetEnd, AlignedOffsetEnd, Offset;
     NTSTATUS Status;
 
@@ -532,24 +532,32 @@ BlockIoRead (
     PBL_BLOCK_DEVICE BlockDevice;
     NTSTATUS Status;
 
+    /* Get the device-specific data, which is our block device descriptor */
     BlockDevice = DeviceEntry->DeviceSpecificData;
 
+    /* Make sure that the buffer and size is valid */
     Status = BlockIopBlockInformationCheck(BlockDevice, &Size, BytesRead, &Size);
     if (NT_SUCCESS(Status))
     {
-        if (BlockDevice->DeviceFlags & 4)
+        /* Check if this is a virtual device or a physical device */
+        if (BlockDevice->DeviceFlags & BL_BLOCK_DEVICE_VIRTUAL_FLAG)
         {
+            /* Do a virtual read or write */
             Status = BlockIopReadWriteVirtualDevice(DeviceEntry, Buffer, Size, 0, BytesRead);
         }
         else
         {
+            /* Do a physical read or write */
             Status = BlockIopReadPhysicalDevice(DeviceEntry, Buffer, Size, BytesRead);
         }
     }
     else if (BytesRead)
     {
+        /* We failed, if the caller wanted bytes read, return 0 */
         *BytesRead = 0;
     }
+
+    /* Return back to the caller */
     return Status;
 }
 
@@ -564,16 +572,25 @@ BlockIoSetInformation (
 
     BlockDevice = DeviceEntry->DeviceSpecificData;
 
-    Offset = DeviceInformation->BlockDeviceInfo.Block * BlockDevice->BlockSize + DeviceInformation->BlockDeviceInfo.Offset;
+    /* Take the current block number and block-offset and conver to full offset */
+    Offset = DeviceInformation->BlockDeviceInfo.Block * BlockDevice->BlockSize +
+             DeviceInformation->BlockDeviceInfo.Offset;
+
+    /* Make sure that the full offset is still within the bounds of the device */
     if (Offset > ((BlockDevice->LastBlock + 1) * BlockDevice->BlockSize - 1))
     {
-        EfiPrintf(L"Invalid offset\r\n");
+        EfiPrintf(L"Offset out of bounds\r\n");
         return STATUS_INVALID_PARAMETER;
     }
 
+    /* Convery the full raw offset into a block number and block-offset */
     BlockDevice->Block = Offset / BlockDevice->BlockSize;
     BlockDevice->Offset = Offset % BlockDevice->BlockSize;
+
+    /* Return the unknown */
     BlockDevice->Unknown = DeviceInformation->BlockDeviceInfo.Unknown;
+
+    /* All done */
     return STATUS_SUCCESS;
 }
 
@@ -583,13 +600,12 @@ BlockIoGetInformation (
     _Out_ PBL_DEVICE_INFORMATION DeviceInformation
     )
 {
-    PBL_BLOCK_DEVICE BlockDevice;
-
-    BlockDevice = DeviceEntry->DeviceSpecificData;
-
+    /* Copy the device speciifc data into the block device information */
     RtlCopyMemory(&DeviceInformation->BlockDeviceInfo,
-                  BlockDevice,
-                  sizeof(DeviceInformation->BlockDeviceInfo));
+                   DeviceEntry->DeviceSpecificData,
+                   sizeof(DeviceInformation->BlockDeviceInfo));
+
+    /* Hardcode the device type */
     DeviceInformation->DeviceType = DiskDevice;
     return STATUS_SUCCESS;
 }
@@ -732,22 +748,28 @@ BlDeviceReadAtOffset (
     )
 {
     NTSTATUS Status;
-    BL_DEVICE_INFORMATION DeviceInformation;
+    BL_DEVICE_INFORMATION DeviceInfo;
 
-    Status = BlDeviceGetInformation(DeviceId, &DeviceInformation);
+    /* Get the current block and offset  */
+    Status = BlDeviceGetInformation(DeviceId, &DeviceInfo);
     if (!NT_SUCCESS(Status))
     {
         return Status;
     }
 
-    DeviceInformation.BlockDeviceInfo.Block = Offset / DeviceInformation.BlockDeviceInfo.BlockSize;
-    DeviceInformation.BlockDeviceInfo.Offset = Offset % DeviceInformation.BlockDeviceInfo.BlockSize;
-    Status = BlDeviceSetInformation(DeviceId, &DeviceInformation);
+    /* Get the block and block-offset based on the new raw offset */
+    DeviceInfo.BlockDeviceInfo.Block = Offset / DeviceInfo.BlockDeviceInfo.BlockSize;
+    DeviceInfo.BlockDeviceInfo.Offset = Offset % DeviceInfo.BlockDeviceInfo.BlockSize;
+
+    /* Update the block and offset */
+    Status = BlDeviceSetInformation(DeviceId, &DeviceInfo);
     if (NT_SUCCESS(Status))
     {
+        /* Now issue a read, with this block and offset configured */
         Status = BlDeviceRead(DeviceId, Buffer, Size, BytesRead);
     }
 
+    /* All good, return the caller */
     return Status;
 }
 
@@ -828,7 +850,7 @@ BlockIoEfiGetBlockIoInformation (
     }
     if (Media->MediaPresent)
     {
-        BlockDevice->DeviceFlags |= 2;
+        BlockDevice->DeviceFlags |= BL_BLOCK_DEVICE_PRESENT_FLAG;
     }
 
     /* No clue */
@@ -1211,6 +1233,158 @@ BlockIoEfiCreateDeviceEntry (
     return Status;
 }
 
+NTSTATUS
+BlockIoEfiCompareDevice (
+    _In_ PBL_DEVICE_DESCRIPTOR Device,
+    _In_ EFI_HANDLE Handle
+    )
+{
+    PBL_LOCAL_DEVICE LocalDeviceInfo, EfiLocalDeviceInfo;
+    PBL_DEVICE_ENTRY DeviceEntry;
+    PBL_DEVICE_DESCRIPTOR EfiDevice;
+    NTSTATUS Status;
+
+    DeviceEntry = NULL;
+
+    /* Check if no device was given */
+    if (!Device)
+    {
+        /* Fail the comparison */
+        Status = STATUS_INVALID_PARAMETER;
+        goto Quickie;
+    }
+
+    /* Check if this is a local disk device */
+    if (Device->DeviceType != DiskDevice)
+    {
+        /* Nope -- is it a partition device? */
+        if ((Device->DeviceType != LegacyPartitionDevice) &&
+            (Device->DeviceType != PartitionDevice))
+        {
+            /* Nope, so we can't compare */
+            Status = STATUS_INVALID_PARAMETER;
+            goto Quickie;
+        }
+
+        /* If so, return the device information for the parent disk */
+        LocalDeviceInfo = &Device->Partition.Disk;
+    }
+    else
+    {
+        /* Just return the disk information itself */
+        LocalDeviceInfo = &Device->Local;
+    }
+
+    /* Create an EFI device entry for the EFI device handle */
+    Status = BlockIoEfiCreateDeviceEntry(&DeviceEntry, Handle);
+    if (!NT_SUCCESS(Status))
+    {
+        goto Quickie;
+    }
+
+    /* Read the descriptor and assume failure for now */
+    EfiDevice = DeviceEntry->DeviceDescriptor;
+    Status = STATUS_UNSUCCESSFUL;
+
+    /* Check if the EFI device is a disk */
+    if (EfiDevice->DeviceType != DiskDevice)
+    {
+        /* Nope, is it a partition? */
+        if ((EfiDevice->DeviceType != LegacyPartitionDevice) &&
+            (EfiDevice->DeviceType != PartitionDevice))
+        {
+            /* Neither, invalid handle so bail out */
+            Status = STATUS_INVALID_PARAMETER;
+            goto Quickie;
+        }
+
+        /* Yes, so get the information of the parent disk */
+        EfiLocalDeviceInfo = &EfiDevice->Partition.Disk;
+    }
+    else
+    {
+        /* It's a disk, so get the disk information itself */
+        EfiLocalDeviceInfo = &EfiDevice->Local;
+    }
+
+    /* Are the two devices the same type? */
+    if (EfiLocalDeviceInfo->Type != LocalDeviceInfo->Type)
+    {
+        /* Nope, that was easy */
+        goto Quickie;
+    }
+
+    /* Yes, what kind of device is the EFI side? */
+    switch (EfiLocalDeviceInfo->Type)
+    {
+        case LocalDevice:
+
+            /* Local hard drive, compare the signature */
+            if (RtlCompareMemory(&EfiLocalDeviceInfo->HardDisk,
+                                 &LocalDeviceInfo->HardDisk,
+                                 sizeof(LocalDeviceInfo->HardDisk)) ==
+                sizeof(LocalDeviceInfo->HardDisk))
+            {
+                Status = STATUS_SUCCESS;
+            }
+            break;
+
+        case FloppyDevice:
+        case CdRomDevice:
+
+            /* Removable floppy or CD, compare the disk number */
+            if (RtlCompareMemory(&EfiLocalDeviceInfo->FloppyDisk,
+                                 &LocalDeviceInfo->FloppyDisk,
+                                 sizeof(LocalDeviceInfo->FloppyDisk)) ==
+                sizeof(LocalDeviceInfo->FloppyDisk))
+            {
+                Status = STATUS_SUCCESS;
+            }
+            break;
+
+        case RamDiskDevice:
+
+            /* RAM disk, compare the size and base information */
+            if (RtlCompareMemory(&EfiLocalDeviceInfo->RamDisk,
+                                 &LocalDeviceInfo->RamDisk,
+                                 sizeof(LocalDeviceInfo->RamDisk)) ==
+                sizeof(LocalDeviceInfo->RamDisk))
+            {
+                Status = STATUS_SUCCESS;
+            }
+            break;
+
+        case FileDevice:
+
+            /* File, compare the file identifier */
+            if (RtlCompareMemory(&EfiLocalDeviceInfo->File,
+                                 &LocalDeviceInfo->File,
+                                 sizeof(LocalDeviceInfo->File)) ==
+                sizeof(LocalDeviceInfo->File))
+            {
+                Status = STATUS_SUCCESS;
+            }
+            break;
+
+        /* Something else we don't support */
+        default:
+            break;
+    }
+
+Quickie:
+    /* All done, did we have an EFI device entry? */
+    if (DeviceEntry)
+    {
+        /* Free it, since we only needed it locally for comparison */
+        BlMmFreeHeap(DeviceEntry->DeviceDescriptor);
+        BlockIopFreeAllocations(DeviceEntry->DeviceSpecificData);
+        BlMmFreeHeap(DeviceEntry);
+    }
+
+    /* Return back to the caller */
+    return Status;
+}
+
 NTSTATUS
 BlockIoFirmwareOpen (
     _In_ PBL_DEVICE_DESCRIPTOR Device,
index b281761..75a0545 100644 (file)
@@ -621,6 +621,69 @@ BlCopyBootOptions (
     return Status;
 }
 
+NTSTATUS
+BlAppendBootOptionBoolean (
+    _In_ PBL_LOADED_APPLICATION_ENTRY AppEntry,
+    _In_ ULONG OptionId
+    )
+{
+    NTSTATUS Status;
+    PBL_BCD_OPTION Option;
+
+    /* Allocate space for the entry -- remember BOOLEANs are USHORTs in BCD */
+    Option = BlMmAllocateHeap(sizeof(*Option) + sizeof(USHORT));
+    if (!Option)
+    {
+        return STATUS_NO_MEMORY;
+    }
+
+    /* Initialize it and set the boolean to TRUE */
+    RtlZeroMemory(Option, sizeof(*Option) + sizeof(USHORT));
+    Option->DataSize = sizeof(USHORT);
+    Option->Type = OptionId;
+    Option->DataOffset = sizeof(*Option);
+    *(PBOOLEAN)(Option + 1) = TRUE;
+
+    /* Append it */
+    Status = BlAppendBootOptions(AppEntry, Option);
+
+    /* We're all done, free our initial option */
+    BlMmFreeHeap(Option);
+    return Status;
+}
+
+NTSTATUS
+BlAppendBootOptionInteger (
+    _In_ PBL_LOADED_APPLICATION_ENTRY AppEntry,
+    _In_ ULONG OptionId,
+    _In_ ULONGLONG Value
+    )
+{
+    NTSTATUS Status;
+    PBL_BCD_OPTION Option;
+
+    /* Allocate space for the entry */
+    Option = BlMmAllocateHeap(sizeof(*Option) + sizeof(Value));
+    if (!Option)
+    {
+        return STATUS_NO_MEMORY;
+    }
+
+    /* Initialize it and set the integer to the given value */
+    RtlZeroMemory(Option, sizeof(*Option) + sizeof(Value));
+    Option->DataSize = sizeof(Value);
+    Option->Type = OptionId;
+    Option->DataOffset = sizeof(*Option);
+    *(PULONGLONG)(Option + 1) = Value;
+
+    /* Append it */
+    Status = BlAppendBootOptions(AppEntry, Option);
+
+    /* We're all done, free our initial option */
+    BlMmFreeHeap(Option);
+    return Status;
+}
+
 NTSTATUS
 BlAppendBootOptionString (
     _In_ PBL_LOADED_APPLICATION_ENTRY AppEntry,