[HIVEBCD]: Fix wrong element type for application device element.
authorAlex Ionescu <aionescu@gmail.com>
Mon, 18 Jan 2016 16:54:44 +0000 (16:54 +0000)
committerAlex Ionescu <aionescu@gmail.com>
Mon, 18 Jan 2016 16:54:44 +0000 (16:54 +0000)
[BOOTMGR]: Implement boot sequence population. We correctly detect our winload.efi entry in the BCD hive.
[BOOTMGR]: Document more application entry flags.
[BOOTLIB]: Document and implement BCD object description parsing. Based off BCD Reference Guide / Geoff Chappel's website.
[BOOTLIB]: Add support for appending a boot option to an entry.

svn path=/trunk/; revision=70614

reactos/boot/bootdata/hivebcd.inf
reactos/boot/environ/app/bootmgr/bootmgr.c
reactos/boot/environ/include/bcd.h
reactos/boot/environ/include/bl.h
reactos/boot/environ/lib/misc/bcd.c
reactos/boot/environ/lib/misc/bcdopt.c
reactos/boot/environ/lib/misc/bootreg.c

index 4ea5358..c8f14a0 100644 (file)
@@ -22,7 +22,7 @@ BCD,"BCD00000000\Objects\{9dea862c-5cdd-4e70-acc1-f32b344d4795}\Elements\2500000
 ; ReactOS Boot Loader
 ;
 BCD,"BCD00000000\Objects\{7619dcc9-fafe-11d9-b411-000476eba25f}\Description","Type",0x00010001,0x10200003                                       ; identifier={winload}
-BCD,"BCD00000000\Objects\{7619dcc9-fafe-11d9-b411-000476eba25f}\Elements\11000011","Element",0x1,\                                              ; device=boot
+BCD,"BCD00000000\Objects\{7619dcc9-fafe-11d9-b411-000476eba25f}\Elements\11000001","Element",0x1,\                                              ; device=boot
     00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,\
     05,00,00,00,\
     00,00,00,00,\
@@ -45,7 +45,7 @@ BCD,"BCD00000000\Objects\{7619dcc9-fafe-11d9-b411-000476eba25f}\Elements\260000b
 ; ReactOS Memory Tester
 ;
 BCD,"BCD00000000\Objects\{b2721d73-1db4-4c62-bf78-c548a880142d}\Description","Type",0x00010001,0x10200005                                       ; identifier={memdiag}
-BCD,"BCD00000000\Objects\{b2721d73-1db4-4c62-bf78-c548a880142d}\Elements\11000011","Element",0x1,\                                              ; device=boot
+BCD,"BCD00000000\Objects\{b2721d73-1db4-4c62-bf78-c548a880142d}\Elements\11000001","Element",0x1,\                                              ; device=boot
     00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,\
     05,00,00,00,\
     00,00,00,00,\
index c355897..92bdcf9 100644 (file)
@@ -121,7 +121,6 @@ BmGetOptionList (
     /* Start going through each option */
     PreviousOption = NULL;
     Option = Options;
-    EfiPrintf(L"BCD Options found: %d\r\n", ElementCount);
     for (i = 0; i < ElementCount; i++)
     {
         /* Read the header and type */
@@ -1230,6 +1229,40 @@ BmPurgeOption (
     return Status;
 }
 
+NTSTATUS
+BmGetEntryDescription (
+    _In_ HANDLE BcdHandle,
+    _In_ PGUID ObjectId,
+    _Out_ PBCD_OBJECT_DESCRIPTION Description
+    )
+{
+    NTSTATUS Status;
+    HANDLE ObjectHandle;
+
+    /* Open the BCD object */
+    Status = BcdOpenObject(BcdHandle, ObjectId, &ObjectHandle);
+    if (NT_SUCCESS(Status))
+    {
+        /* Make sure the caller passed this argument in */
+        if (!Description)
+        {
+            /* Fail otherwise */
+            Status = STATUS_INVALID_PARAMETER;
+        }
+        else
+        {
+            /* Query the description from the BCD interface */
+            Status = BiGetObjectDescription(ObjectHandle, Description);
+        }
+
+        /* Close the object key */
+        BiCloseKey(ObjectHandle);
+    }
+
+    /* Return the result back */
+    return Status;
+}
+
 NTSTATUS
 BmpPopulateBootEntryList (
     _In_ HANDLE BcdHandle,
@@ -1239,10 +1272,211 @@ BmpPopulateBootEntryList (
     _Out_ PULONG SequenceCount
     )
 {
-    EfiPrintf(L"Boot population not yet supported\r\n");
-    *SequenceCount = 0;
-    *BootSequence = NULL;
-    return STATUS_NOT_IMPLEMENTED;
+    NTSTATUS Status;
+    ULONG BootIndex, i, OptionSize;
+    PBL_LOADED_APPLICATION_ENTRY BootEntry;
+    PBL_BCD_OPTION Options;
+    BCD_OBJECT_DESCRIPTION Description;
+    BcdObjectType ObjectType;
+    BOOLEAN HavePath, IsWinPe, SoftReboot;
+    PWCHAR LoaderPath;
+
+    /* Initialize locals */
+    Options = NULL;
+    BootIndex = 0;
+    Status = STATUS_NOT_FOUND;
+
+    /* Loop through every element in the sequence */
+    for (i = 0; i < *SequenceCount; i++)
+    {
+        /* Assume failure */
+        BootEntry = NULL;
+
+        /* Get the options for the sequence element */
+        Status = BmGetOptionList(BcdHandle, SequenceList, &Options);
+        if (!NT_SUCCESS(Status))
+        {
+            EfiPrintf(L"option list failed: %lx\r\n", Status);
+            goto LoopQuickie;
+        }
+
+        /* Make sure there's at least a path and description */
+        if (!(MiscGetBootOption(Options, BcdLibraryDevice_ApplicationDevice)) ||
+            !(MiscGetBootOption(Options, BcdLibraryString_Description)))
+        {
+            Status = STATUS_UNSUCCESSFUL;
+            EfiPrintf(L"missing list failed: %lx\r\n", Status);
+            goto LoopQuickie;
+        }
+
+        /* Get the size of the BCD options and allocate a large enough entry */
+        OptionSize = BlGetBootOptionListSize(Options);
+        BootEntry = BlMmAllocateHeap(sizeof(*BootEntry) + OptionSize);
+        if (!BootEntry)
+        {
+            Status = STATUS_NO_MEMORY;
+            goto Quickie;
+        }
+
+        /* Save it as part of the sequence */
+        BootSequence[BootIndex] = BootEntry;
+
+        /* Initialize it, and copy the BCD data */
+        RtlZeroMemory(BootEntry, sizeof(*BootEntry));
+        BootEntry->Guid = *SequenceList;
+        BootEntry->BcdData = (PBL_BCD_OPTION)(BootEntry + 1);
+        BootEntry->Flags = Flags;
+        RtlCopyMemory(BootEntry->BcdData, Options, OptionSize);
+
+        /* Get the object descriptor to find out what kind of entry it is */
+        Status = BmGetEntryDescription(BcdHandle,
+                                       &BootEntry->Guid,
+                                       &Description);
+        if (!NT_SUCCESS(Status))
+        {
+            EfiPrintf(L"missing desc failed: %lx\r\n", Status);
+            goto LoopQuickie;
+        }
+
+        /* Check if a path was given or not */
+        HavePath = MiscGetBootOption(Options, BcdLibraryString_ApplicationPath) ?
+                   TRUE : FALSE;
+
+        /* Now select based on what type of object this is -- must be an app */
+        ObjectType.PackedValue = Description.Type;
+        if (ObjectType.Application.ObjectCode == BCD_OBJECT_TYPE_APPLICATION)
+        {
+            /* Then select based on what kind of app it is */
+            switch (ObjectType.Application.ApplicationCode)
+            {
+                /* Another boot manager */
+                case BCD_APPLICATION_TYPE_BOOTMGR:
+                    BootEntry->Flags |= BCD_APPLICATION_TYPE_BOOTMGR;
+                    break;
+
+                /* An OS loader */
+                case BCD_APPLICATION_TYPE_OSLOADER:
+                    BootEntry->Flags |= BL_APPLICATION_ENTRY_WINLOAD;
+
+                    /* Do we have a path for it? */
+                    if (!HavePath)
+                    {
+                        /* We'll try to make one up. Is this WinPE? */
+                        IsWinPe = FALSE;
+                        Status = BlGetBootOptionBoolean(Options,
+                                                        BcdOSLoaderBoolean_WinPEMode,
+                                                        &IsWinPe);
+                        if (!(NT_SUCCESS(Status)) && (Status != STATUS_NOT_FOUND))
+                        {
+                            goto Quickie;
+                        }
+
+                        /* Use the appropriate path for WinPE or local install */
+                        LoaderPath = IsWinPe ?
+                                     L"\\Windows\\System32\\boot\\winload.efi" :
+                                     L"\\Windows\\System32\\winload.efi";
+
+                        /* Add the path to the boot entry */
+                        Status = BlAppendBootOptionString(BootEntry, LoaderPath);
+                        if (!NT_SUCCESS(Status))
+                        {
+                            goto Quickie;
+                        }
+
+                        /* We have a path now */
+                        HavePath = TRUE;
+                    }
+                    break;
+
+                /* A hibernate-resume application */
+                case BCD_APPLICATION_TYPE_RESUME:
+                    BootEntry->Flags |= BL_APPLICATION_ENTRY_WINRESUME;
+                    break;
+
+                /* An older OS NTLDR */
+                case BCD_APPLICATION_TYPE_NTLDR:
+                    BootEntry->Flags |= BL_APPLICATION_ENTRY_NTLDR;
+                    break;
+
+                /* An older OS SETUPLDR */
+                case BCD_APPLICATION_TYPE_SETUPLDR:
+                    BootEntry->Flags |= BL_APPLICATION_ENTRY_SETUPLDR;
+                    break;
+
+                /* A 3rd party/Win9x boot sector */
+                case BCD_APPLICATION_TYPE_BOOTSECTOR:
+                    BootEntry->Flags |= BL_APPLICATION_ENTRY_BOOTSECTOR;
+                    break;
+
+                /* Something else entirely */
+                default:
+                    break;
+            }
+        }
+
+        /* We better have a path by now */
+        if (!HavePath)
+        {
+            Status = STATUS_UNSUCCESSFUL;
+            goto LoopQuickie;
+        }
+
+        /* Check if this is a real mode startup.com */
+        if ((ObjectType.Application.ObjectCode == BCD_OBJECT_TYPE_APPLICATION) &&
+            (ObjectType.Application.ImageCode = BCD_IMAGE_TYPE_REAL_MODE) &&
+            (ObjectType.Application.ApplicationCode == BCD_APPLICATION_TYPE_STARTUPCOM))
+        {
+            /* Check if PXE soft reboot will occur */
+            Status = BlGetBootOptionBoolean(Options,
+                                            BcdStartupBoolean_PxeSoftReboot,
+                                            &SoftReboot);
+            if ((NT_SUCCESS(Status)) && (SoftReboot))
+            {
+                /* Then it's a valid startup.com entry */
+                BootEntry->Flags |= BL_APPLICATION_ENTRY_STARTUP;
+            }
+        }
+
+LoopQuickie:
+        /* All done with this entry -- did we have BCD options? */
+        if (Options)
+        {
+            /* Free them, they're part of the entry now */
+            BlMmFreeHeap(Options);
+            Options = NULL;
+        }
+
+        /* Did we fail anywhere? */
+        if (!NT_SUCCESS(Status))
+        {
+            /* Yep -- did we fail with an active boot entry? */
+            if (BootEntry)
+            {
+                /* Destroy it */
+                BlDestroyBootEntry(BootEntry);
+                BootSequence[BootIndex] = NULL;
+            }
+        }
+        else
+        {
+            /* It worked, so populate the next index now */
+            BootIndex++;
+        }
+
+        /* And move to the next GUID in the sequence list */
+        SequenceList++;
+    }
+
+Quickie:
+    /* All done now -- did we have any BCD options? */
+    if (Options)
+    {
+        /* Free them */
+        BlMmFreeHeap(Options);
+    }
+
+    /* Return the status */
+    return Status;
 }
 
 NTSTATUS
@@ -1363,7 +1597,7 @@ BmEnumerateBootEntries (
         /* Populate the list of bootable entries */
         Status = BmpPopulateBootEntryList(BcdHandle,
                                           DisplayOrder,
-                                          0x800000,
+                                          BL_APPLICATION_ENTRY_DISPLAY_ORDER,
                                           Sequence,
                                           &BcdCount);
         if (!NT_SUCCESS(Status))
@@ -1454,7 +1688,8 @@ BmpGetSelectedBootEntry (
         goto Quickie;
     }
 
-    EfiPrintf(L"Boot selection not yet implemented\r\n");
+    EfiPrintf(L"Boot selection not yet implemented. %d entries found\r\n", Count);
+    EfiStall(10000000);
     *SelectedBootEntry = NULL;
 
 Quickie:
@@ -1772,7 +2007,7 @@ BmMain (
                 Status = BmGetBootSequence(BcdHandle,
                                            SequenceList,
                                            SequenceListCount,
-                                           0x20000000,
+                                           BL_APPLICATION_ENTRY_FIXED_SEQUENCE,
                                            &BootSequence,
                                            &SequenceCount);
                 if (NT_SUCCESS(Status))
index 9d3d7fa..75630af 100644 (file)
 #define BCD_TYPE_BOOLEAN        0x06
 #define BCD_TYPE_INTEGER_LIST   0x07
 
+#define BCD_IMAGE_TYPE_FIRMWARE     0x01
+#define BCD_IMAGE_TYPE_BOOT_APP     0x02
+#define BCD_IMAGE_TYPE_NTLDR        0x03
+#define BCD_IMAGE_TYPE_REAL_MODE    0x04
+
+#define BCD_APPLICATION_TYPE_FWBOOTMGR  0x01
+#define BCD_APPLICATION_TYPE_BOOTMGR    0x02
+#define BCD_APPLICATION_TYPE_OSLOADER   0x03
+#define BCD_APPLICATION_TYPE_RESUME     0x04
+#define BCD_APPLICATION_TYPE_MEMDIAG    0x05
+#define BCD_APPLICATION_TYPE_NTLDR      0x06
+#define BCD_APPLICATION_TYPE_SETUPLDR   0x07
+#define BCD_APPLICATION_TYPE_BOOTSECTOR 0x08
+#define BCD_APPLICATION_TYPE_STARTUPCOM 0x09
+
+#define BCD_OBJECT_TYPE_APPLICATION     0x01
+#define BCD_OBJECT_TYPE_INHEREIT        0x02
+#define BCD_OBJECT_TYPE_DEVICE          0x03
+
 typedef enum BcdLibraryElementTypes
 {
     BcdLibraryDevice_ApplicationDevice = 0x11000001,
@@ -172,13 +191,20 @@ typedef enum BcdBootMgrElementTypes
     BcdBootMgrBoolean_PersistBootSequence = 0x26000031
 } BcdBootMgrElementTypes;
 
+/* Undocumented */
+typedef enum BcdStartupElementTypes
+{
+    BcdStartupBoolean_PxeSoftReboot = 0x26000001,
+    BcdStartupString_PxeApplicationName = 0x22000002,
+} BcdStartupElementTypes;
+
 /* DATA STRUCTURES ***********************************************************/
 
 typedef struct
 {
     union
     {
-        ULONG  PackedValue;
+        ULONG PackedValue;
         struct
         {
             ULONG SubType : 24;
@@ -188,6 +214,36 @@ typedef struct
     };
 } BcdElementType;
 
+typedef struct
+{
+    union
+    {
+        ULONG PackedValue;
+        union
+        {
+            struct
+            {
+                ULONG ApplicationCode : 20;
+                ULONG ImageCode : 4;
+                ULONG Reserved : 4;
+                ULONG ObjectCode : 4;
+            } Application;
+            struct
+            {
+                ULONG Value : 20;
+                ULONG ClassCode : 4;
+                ULONG Reserved : 4;
+                ULONG ObjectCode : 4;
+            } Inherit;
+            struct
+            {
+                ULONG Reserved:28;
+                ULONG ObjectCode : 4;
+            } Device;
+        };
+    };
+} BcdObjectType;
+
 typedef struct _BCD_ELEMENT_HEADER
 {
     ULONG Version;
@@ -215,6 +271,12 @@ typedef struct _BCD_DEVICE_OPTION
     BL_DEVICE_DESCRIPTOR DeviceDescriptor;
 } BCD_DEVICE_OPTION, *PBCD_DEVICE_OPTION;
 
+typedef struct _BCD_OBJECT_DESCRIPTION
+{
+    ULONG Valid;
+    ULONG Type;
+} BCD_OBJECT_DESCRIPTION, *PBCD_OBJECT_DESCRIPTION;;
+
 /* FUNCTIONS ******************************************************************/
 
 NTSTATUS
@@ -260,4 +322,10 @@ BcdEnumerateAndUnpackElements (
     _Out_ PULONG ElementCount
     );
 
+NTSTATUS
+BiGetObjectDescription (
+    _In_ HANDLE ObjectHandle,
+    _Out_ PBCD_OBJECT_DESCRIPTION Description
+    );
+
 #endif
index a03f9d0..df69fd9 100644 (file)
@@ -66,8 +66,17 @@ DEFINE_GUID(BadMemoryGuid, 0x54B8275B, 0xD431, 0x473F, 0xAC, 0xFB, 0xE5, 0x36, 0
 
 #define BL_APPLICATION_ENTRY_FLAG_NO_GUID               0x01
 #define BL_APPLICATION_ENTRY_BCD_OPTIONS_INTERNAL       0x02
+#define BL_APPLICATION_ENTRY_WINLOAD                    0x04
+#define BL_APPLICATION_ENTRY_STARTUP                    0x08
 #define BL_APPLICATION_ENTRY_REBOOT_ON_ERROR            0x20
+#define BL_APPLICATION_ENTRY_NTLDR                      0x40
 #define BL_APPLICATION_ENTRY_BCD_OPTIONS_EXTERNAL       0x80
+#define BL_APPLICATION_ENTRY_WINRESUME                  0x100
+#define BL_APPLICATION_ENTRY_SETUPLDR                   0x200
+#define BL_APPLICATION_ENTRY_BOOTSECTOR                 0x400
+#define BL_APPLICATION_ENTRY_BOOTMGR                    0x1000
+#define BL_APPLICATION_ENTRY_DISPLAY_ORDER              0x800000
+#define BL_APPLICATION_ENTRY_FIXED_SEQUENCE             0x20000000
 
 #define BL_CONTEXT_PAGING_ON                            1
 #define BL_CONTEXT_INTERRUPTS_ON                        2
@@ -1742,6 +1751,12 @@ BlCopyBootOptions (
     _Out_ PBL_BCD_OPTION *CopiedOptions
     );
 
+NTSTATUS
+BlAppendBootOptionString (
+    _In_ PBL_LOADED_APPLICATION_ENTRY AppEntry,
+    _In_ PWCHAR OptionString
+    );
+
 NTSTATUS
 BlAppendBootOptions (
     _In_ PBL_LOADED_APPLICATION_ENTRY AppEntry,
@@ -1784,7 +1799,6 @@ NTSTATUS
 BiGetRegistryValue (
     _In_ HANDLE KeyHandle,
     _In_ PWCHAR ValueName,
-    _In_ PWCHAR KeyName,
     _In_ ULONG Type,
     _Out_ PVOID* Buffer,
     _Out_ PULONG ValueLength
index 7d32fa7..786c55d 100644 (file)
@@ -881,7 +881,6 @@ BiEnumerateElements (
         /* Read the appropriate registry value type for this element */
         Status = BiGetRegistryValue(ElementHandle,
                                     L"Element",
-                                    NULL,
                                     BiConvertElementFormatToValueType(
                                     ElementType.Format),
                                     &RegistryElementData,
@@ -1176,6 +1175,69 @@ BiAddStoreFromFile (
     return Status;
 }
 
+NTSTATUS
+BiGetObjectDescription (
+    _In_ HANDLE ObjectHandle,
+    _Out_ PBCD_OBJECT_DESCRIPTION Description
+    )
+{
+    NTSTATUS Status;
+    HANDLE DescriptionHandle;
+    PULONG Data;
+    ULONG Length;
+
+    /* Initialize locals */
+    Data = NULL;
+    DescriptionHandle = NULL;
+
+    /* Open the description key */
+    Status = BiOpenKey(ObjectHandle, L"Description", &DescriptionHandle);
+    if (NT_SUCCESS(Status))
+    {
+        /* It exists */
+        Description->Valid = TRUE;
+
+        /* Read the type */
+        Length = 0;
+        Status = BiGetRegistryValue(DescriptionHandle,
+                                    L"Type", 
+                                    REG_DWORD,
+                                    (PVOID*)&Data,
+                                    &Length);
+        if (NT_SUCCESS(Status))
+        {
+            /* Make sure it's the length we expected it to be */
+            if (Length == sizeof(Data))
+            {
+                /* Return the type that is stored there */
+                Description->Type = *Data;
+            }
+            else
+            {
+                /* Invalid type value */
+                Status = STATUS_OBJECT_TYPE_MISMATCH;
+            }
+        }
+    }
+
+    /* Did we have a handle open? */
+    if (DescriptionHandle)
+    {
+        /* Close it */
+        BiCloseKey(DescriptionHandle);
+    }
+
+    /* Did we have data allocated? */
+    if (Data)
+    {
+        /* Free it */
+        BlMmFreeHeap(Data);
+    }
+
+    /* Return back to caller */
+    return Status;
+}
+
 NTSTATUS
 BcdEnumerateAndUnpackElements (
     _In_ HANDLE BcdHandle,
index f70995e..b281761 100644 (file)
@@ -621,6 +621,53 @@ BlCopyBootOptions (
     return Status;
 }
 
+NTSTATUS
+BlAppendBootOptionString (
+    _In_ PBL_LOADED_APPLICATION_ENTRY AppEntry,
+    _In_ PWCHAR OptionString
+    )
+{
+    NTSTATUS Status;
+    ULONG StringSize;
+    PBL_BCD_OPTION Option;
+
+    /* Get the length in bytes */
+    Status = RtlULongLongToULong(wcslen(OptionString) * sizeof(WCHAR),
+                                 &StringSize);
+    if (!NT_SUCCESS(Status))
+    {
+        return Status;
+    }
+
+    /* Add a NULL-terminator */
+    Status = RtlULongAdd(StringSize, sizeof(UNICODE_NULL), &StringSize);
+    if (!NT_SUCCESS(Status))
+    {
+        return Status;
+    }
+
+    /* Allocate space for the entry */
+    Option = BlMmAllocateHeap(sizeof(*Option) + StringSize);
+    if (!Option)
+    {
+        return STATUS_NO_MEMORY;
+    }
+
+    /* Initialize it and copy the string value */
+    RtlZeroMemory(Option, sizeof(*Option) + StringSize);
+    Option->DataSize = StringSize;
+    Option->Type = BcdLibraryString_ApplicationPath;
+    Option->DataOffset = sizeof(*Option);
+    wcsncpy((PWCHAR)Option + 1, OptionString, StringSize / sizeof(WCHAR));
+
+    /* Append it */
+    Status = BlAppendBootOptions(AppEntry, Option);
+
+    /* We're all done, free our initial option */
+    BlMmFreeHeap(Option);
+    return Status;
+}
+
 NTSTATUS
 BlAppendBootOptions (
     _In_ PBL_LOADED_APPLICATION_ENTRY AppEntry,
index e9eebab..d1ac812 100644 (file)
@@ -655,7 +655,6 @@ NTSTATUS
 BiGetRegistryValue (
     _In_ HANDLE KeyHandle,
     _In_ PWCHAR ValueName,
-    _In_ PWCHAR KeyName,
     _In_ ULONG Type,
     _Out_ PVOID* Buffer,
     _Out_ PULONG ValueLength