2 * COPYRIGHT: See COPYING.ARM in the top level directory
3 * PROJECT: ReactOS UEFI Boot Manager
4 * FILE: boot/environ/app/efiemu.c
5 * PURPOSE: UEFI Entrypoint for Boot Manager
6 * PROGRAMMER: Alex Ionescu (alex.ionescu@reactos.org)
9 /* INCLUDES ******************************************************************/
14 /* DATA STRUCTURES ***********************************************************/
16 typedef struct _BOOT_APPLICATION_PARAMETER_BLOCK_SCRATCH
18 BOOT_APPLICATION_PARAMETER_BLOCK
;
19 BL_MEMORY_DATA BootMemoryData
;
20 BL_MEMORY_DESCRIPTOR MemEntry
;
22 } BOOT_APPLICATION_PARAMETER_BLOCK_SCRATCH
;
24 /* DATA VARIABLES ************************************************************/
26 ULONG BlpApplicationFlags
;
28 BOOT_APPLICATION_PARAMETER_BLOCK_SCRATCH EfiInitScratch
;
30 /* FUNCTIONS *****************************************************************/
33 * @name AhCreateLoadOptionsList
35 * The AhCreateLoadOptionsList routine
38 * UEFI Image Handle for the current loaded application.
41 * Pointer to the UEFI System Table.
43 * @param MaximumLength
44 * Pointer to the UEFI System Table.
47 * Pointer to the UEFI System Table.
49 * @param PreviousOption
50 * Pointer to the UEFI System Table.
52 * @param PreviousOptionSize
53 * Pointer to the UEFI System Table.
59 AhCreateLoadOptionsList (
60 _In_ PWCHAR CommandLine
,
61 _In_ PBL_BCD_OPTION BootOptions
,
62 _In_ ULONG MaximumLength
,
63 _Out_ PULONG OptionSize
,
64 _In_ PBL_BCD_OPTION
* PreviousOption
,
65 _In_ PULONG PreviousOptionSize
68 return STATUS_NOT_IMPLEMENTED
;
72 * @name EfiInitpAppendPathString
74 * The EfiInitpAppendPathString routine
76 * @param DestinationPath
77 * UEFI Image Handle for the current loaded application.
79 * @param RemainingSize
80 * Pointer to the UEFI System Table.
83 * Pointer to the UEFI System Table.
86 * Pointer to the UEFI System Table.
88 * @param BytesAppended
89 * Pointer to the UEFI System Table.
95 EfiInitpAppendPathString (
96 _In_ PWCHAR PathString
,
97 _In_ ULONG MaximumLength
,
98 _In_ PWCHAR NewPathString
,
99 _In_ ULONG NewPathLength
,
100 _Out_ PULONG ResultLength
104 ULONG FinalPathLength
;
106 /* We deal in Unicode, validate the length */
107 if (NewPathLength
& 1)
109 return STATUS_INVALID_PARAMETER
;
112 /* Is the new element at least a character? */
113 Status
= STATUS_SUCCESS
;
114 if (NewPathLength
>= sizeof(WCHAR
))
116 /* Is the last character already a NULL character? */
117 if (NewPathString
[(NewPathLength
- sizeof(WCHAR
)) / sizeof(WCHAR
)] ==
120 /* Then we won't need to count it */
121 NewPathLength
-= sizeof(UNICODE_NULL
);
124 /* Was it more than just a NULL character? */
125 if (NewPathLength
>= sizeof(WCHAR
))
127 /* Yep -- but does it have a separator? */
128 if (*NewPathString
== OBJ_NAME_PATH_SEPARATOR
)
130 /* Skip it, we'll add our own later */
132 NewPathLength
-= sizeof(OBJ_NAME_PATH_SEPARATOR
);
135 /* Was it more than just a separator? */
136 if (NewPathLength
>= sizeof(WCHAR
))
138 /* Yep -- but does it end with a separator? */
139 if (NewPathString
[(NewPathLength
- sizeof(WCHAR
)) / sizeof(WCHAR
)] ==
140 OBJ_NAME_PATH_SEPARATOR
)
142 /* That's something else we won't need for now */
143 NewPathLength
-= sizeof(OBJ_NAME_PATH_SEPARATOR
);
149 /* Check if anything needs to be appended after all */
150 if (NewPathLength
!= 0)
152 /* We will append the length of the new path element, plus a separator */
153 FinalPathLength
= NewPathLength
+ sizeof(OBJ_NAME_PATH_SEPARATOR
);
154 if (MaximumLength
>= FinalPathLength
)
156 /* Add a separator to the existing path*/
157 *PathString
= OBJ_NAME_PATH_SEPARATOR
;
159 /* Followed by the new path element */
160 RtlCopyMemory(PathString
+ 1, NewPathString
, NewPathLength
);
162 /* Return the number of bytes appended */
163 *ResultLength
= FinalPathLength
;
167 /* There's not enough space to do this */
168 Status
= STATUS_BUFFER_TOO_SMALL
;
173 /* Nothing to append */
181 * @name EfiInitpConvertEfiDevicePath
183 * The EfiInitpConvertEfiDevicePath routine
186 * UEFI Image Handle for the current loaded application.
189 * Pointer to the UEFI System Table.
192 * Pointer to the UEFI System Table.
194 * @param MaximumLength
195 * Pointer to the UEFI System Table.
201 EfiInitpConvertEfiFilePath (
202 _In_ EFI_DEVICE_PATH_PROTOCOL
*DevicePath
,
204 _In_ PBL_BCD_OPTION Option
,
205 _In_ ULONG MaximumLength
208 ULONG BytesAppended
, DataSize
, StringLength
;
209 PBCDE_STRING StringEntry
;
211 FILEPATH_DEVICE_PATH
*FilePath
;
214 /* Make sure we have enough space for the option */
215 if (MaximumLength
< sizeof(*Option
))
217 return STATUS_INVALID_PARAMETER
;
220 /* Set the initial size of the option, and consume from our buffer */
221 DataSize
= sizeof(*Option
);
222 MaximumLength
-= sizeof(*Option
);
224 /* Zero out and fill the option header */
225 RtlZeroMemory(Option
, DataSize
);
226 Option
->Type
= PathType
;
227 Option
->DataOffset
= sizeof(*Option
);
229 /* Extract the string option */
230 StringEntry
= (PBCDE_STRING
)(Option
+ 1);
231 PathString
= StringEntry
->String
;
233 /* Start parsing the device path */
234 FilePath
= (FILEPATH_DEVICE_PATH
*)DevicePath
;
235 while (IsDevicePathEndType(FilePath
) == FALSE
)
237 /* Is this a file path? */
238 if ((FilePath
->Header
.Type
== MEDIA_DEVICE_PATH
) &&
239 (FilePath
->Header
.SubType
== MEDIA_FILEPATH_DP
))
241 /* Get the length of the file path string, avoiding overflow */
242 StringLength
= DevicePathNodeLength(FilePath
) -
243 FIELD_OFFSET(FILEPATH_DEVICE_PATH
, PathName
);
244 if (StringLength
< (ULONG
)FIELD_OFFSET(FILEPATH_DEVICE_PATH
, PathName
))
246 Status
= STATUS_INTEGER_OVERFLOW
;
250 /* Append this path string to the current path string */
251 Status
= EfiInitpAppendPathString(PathString
,
256 if (!NT_SUCCESS(Status
))
261 /* Increase the size of the data, consume buffer space */
262 DataSize
+= BytesAppended
;
263 MaximumLength
-= BytesAppended
;
265 /* Move to the next path string */
266 PathString
= (PWCHAR
)((ULONG_PTR
)PathString
+ BytesAppended
);
269 /* Move to the next path node */
270 FilePath
= (FILEPATH_DEVICE_PATH
*)NextDevicePathNode(FilePath
);
273 /* Check if we still have space for a NULL-terminator */
274 if (MaximumLength
< sizeof(UNICODE_NULL
))
276 Status
= STATUS_INVALID_PARAMETER
;
280 /* We do -- NULL-terminate the string */
281 *PathString
= UNICODE_NULL
;
282 DataSize
+= sizeof(UNICODE_NULL
);
284 /* Check if all of this has amounted to a single NULL-char */
285 if (PathString
== StringEntry
->String
)
287 /* Then this option is empty */
288 Option
->Empty
= TRUE
;
291 /* Set the final size of the option */
292 Option
->DataSize
= DataSize
;
295 return STATUS_SUCCESS
;
299 * @name EfiInitpGetDeviceNode
301 * The EfiInitpGetDeviceNode routine
304 * UEFI Image Handle for the current loaded application.
309 EFI_DEVICE_PATH_PROTOCOL
*
310 EfiInitpGetDeviceNode (
311 _In_ EFI_DEVICE_PATH_PROTOCOL
*DevicePath
314 EFI_DEVICE_PATH_PROTOCOL
* NextPath
;
316 /* Check if we hit the end terminator */
317 if (IsDevicePathEndType(DevicePath
))
322 /* Loop each device path, until we get to the end or to a file path device node */
323 for ((NextPath
= NextDevicePathNode(DevicePath
));
324 !(IsDevicePathEndType(NextPath
)) && ((NextPath
->Type
!= MEDIA_DEVICE_PATH
) &&
325 (NextPath
->SubType
!= MEDIA_FILEPATH_DP
));
326 (NextPath
= NextDevicePathNode(NextPath
)))
328 /* Keep iterating down */
329 DevicePath
= NextPath
;
332 /* Return the path found */
337 * @name EfiInitTranslateDevicePath
339 * The EfiInitTranslateDevicePath routine
342 * UEFI Image Handle for the current loaded application.
345 * Pointer to the UEFI System Table.
351 EfiInitTranslateDevicePath (
352 _In_ EFI_DEVICE_PATH_PROTOCOL
*DevicePath
,
353 _In_ PBL_DEVICE_DESCRIPTOR DeviceEntry
357 EFI_DEVICE_PATH_PROTOCOL
* DeviceNode
;
358 MEMMAP_DEVICE_PATH
* MemDevicePath
;
359 ACPI_HID_DEVICE_PATH
*AcpiPath
;
360 HARDDRIVE_DEVICE_PATH
*DiskPath
;
363 Status
= STATUS_UNSUCCESSFUL
;
366 DeviceEntry
->Size
= sizeof(*DeviceEntry
);
368 /* Check if we are booting from a RAM Disk */
369 if ((DevicePath
->Type
== HARDWARE_DEVICE_PATH
) &&
370 (DevicePath
->SubType
== HW_MEMMAP_DP
))
372 /* Get the EFI data structure matching this */
373 MemDevicePath
= (MEMMAP_DEVICE_PATH
*)DevicePath
;
375 /* Set the boot library specific device types */
376 DeviceEntry
->DeviceType
= LocalDevice
;
377 DeviceEntry
->Local
.Type
= RamDiskDevice
;
379 /* Extract the base, size, and offset */
380 DeviceEntry
->Local
.RamDisk
.ImageBase
.QuadPart
= MemDevicePath
->StartingAddress
;
381 DeviceEntry
->Local
.RamDisk
.ImageSize
.QuadPart
= MemDevicePath
->EndingAddress
-
382 MemDevicePath
->StartingAddress
;
383 DeviceEntry
->Local
.RamDisk
.ImageOffset
= 0;
384 return STATUS_SUCCESS
;
387 /* Otherwise, check what kind of device node this is */
388 DeviceNode
= EfiInitpGetDeviceNode(DevicePath
);
389 switch (DeviceNode
->Type
)
392 case ACPI_DEVICE_PATH
:
394 /* We only support floppy drives */
395 AcpiPath
= (ACPI_HID_DEVICE_PATH
*)DeviceNode
;
396 if ((AcpiPath
->HID
!= EISA_PNP_ID(0x604)) &&
397 (AcpiPath
->HID
!= EISA_PNP_ID(0x700)))
402 /* Set the boot library specific device types */
403 DeviceEntry
->DeviceType
= LocalDevice
;
404 DeviceEntry
->Local
.Type
= FloppyDevice
;
406 /* The ACPI UID is the drive number */
407 DeviceEntry
->Local
.FloppyDisk
.DriveNumber
= AcpiPath
->UID
;
408 return STATUS_SUCCESS
;
410 /* Network, ATAPI, SCSI, USB */
411 case MESSAGING_DEVICE_PATH
:
413 /* Check if it's network */
414 if ((DeviceNode
->SubType
== MSG_MAC_ADDR_DP
) ||
415 (DeviceNode
->SubType
== MSG_IPv4_DP
))
417 /* Set the boot library specific device types */
418 DeviceEntry
->DeviceType
= UdpDevice
;
419 DeviceEntry
->Remote
.Unknown
= 256;
420 return STATUS_SUCCESS
;
423 /* Other types should come in as MEDIA_DEVICE_PATH -- Windows assumes this is a floppy */
424 DeviceEntry
->DeviceType
= DiskDevice
;
425 DeviceEntry
->Local
.Type
= FloppyDevice
;
426 DeviceEntry
->Local
.FloppyDisk
.DriveNumber
= 0;
427 return STATUS_SUCCESS
;
430 case MEDIA_DEVICE_PATH
:
432 /* Extract the disk path and check if it's a physical disk */
433 DiskPath
= (HARDDRIVE_DEVICE_PATH
*)DeviceNode
;
434 if (DeviceNode
->SubType
== MEDIA_HARDDRIVE_DP
)
436 /* Check if this is an MBR partition */
437 if (DiskPath
->SignatureType
== SIGNATURE_TYPE_MBR
)
439 /* Set that this is a local partition */
440 DeviceEntry
->DeviceType
= LegacyPartitionDevice
;
441 DeviceEntry
->Partition
.Disk
.Type
= LocalDevice
;
443 DeviceEntry
->Partition
.Disk
.HardDisk
.PartitionType
= MbrPartition
;
444 DeviceEntry
->Partition
.Disk
.HardDisk
.Mbr
.PartitionSignature
=
445 *(PULONG
)&DiskPath
->Signature
[0];
446 DeviceEntry
->Partition
.Mbr
.PartitionNumber
= DiskPath
->PartitionNumber
;
447 return STATUS_SUCCESS
;
450 /* Check if it's a GPT partition */
451 if (DiskPath
->SignatureType
== SIGNATURE_TYPE_GUID
)
453 /* Set that this is a local disk */
454 DeviceEntry
->DeviceType
= PartitionDevice
;
455 DeviceEntry
->Partition
.Disk
.Type
= LocalDevice
;
457 /* Set GPT partition ID */
458 DeviceEntry
->Partition
.Disk
.HardDisk
.PartitionType
= GptPartition
;
460 /* Copy the signature GUID */
461 RtlCopyMemory(&DeviceEntry
->Partition
.Gpt
.PartitionGuid
,
465 DeviceEntry
->Flags
|= 4u;
466 return STATUS_SUCCESS
;
469 /* Otherwise, raw boot is not supported */
470 DeviceEntry
->DeviceType
= PartitionDevice
;
471 DeviceEntry
->Partition
.Disk
.Type
= LocalDevice
;
472 DeviceEntry
->Partition
.Disk
.HardDisk
.PartitionType
= RawPartition
;
473 DeviceEntry
->Partition
.Disk
.HardDisk
.Raw
.DiskNumber
= 0;
475 else if (DeviceNode
->SubType
== MEDIA_CDROM_DP
)
477 /* Set the right type for a CDROM */
478 DeviceEntry
->DeviceType
= DiskDevice
;
479 DeviceEntry
->Local
.Type
= CdRomDevice
;
481 /* Set the drive number to zero */
482 DeviceEntry
->Local
.FloppyDisk
.DriveNumber
= 0;
483 return STATUS_SUCCESS
;
486 /* Fail anything else */
491 /* Return here only on failure */
496 * @name EfiInitpConvertEfiDevicePath
498 * The EfiInitpConvertEfiDevicePath routine
501 * UEFI Image Handle for the current loaded application.
504 * Pointer to the UEFI System Table.
507 * Pointer to the UEFI System Table.
509 * @param MaximumLength
510 * Pointer to the UEFI System Table.
516 EfiInitpConvertEfiDevicePath (
517 _In_ EFI_DEVICE_PATH_PROTOCOL
*DevicePath
,
518 _In_ ULONG DeviceType
,
519 _In_ PBL_BCD_OPTION Option
,
520 _In_ ULONG MaximumLength
523 PBCDE_DEVICE DeviceEntry
;
526 /* Make sure we have enough space for the option */
527 if (MaximumLength
< sizeof(*Option
))
529 Status
= STATUS_INVALID_PARAMETER
;
533 /* Zero out the option */
534 RtlZeroMemory(Option
, sizeof(*Option
));
536 /* Make sure we have enough space for the device entry */
537 if ((MaximumLength
- sizeof(*Option
)) < (ULONG
)FIELD_OFFSET(BCDE_DEVICE
, Device
))
539 Status
= STATUS_INVALID_PARAMETER
;
544 DeviceEntry
= (PBCDE_DEVICE
)(Option
+ 1);
545 Status
= EfiInitTranslateDevicePath(DevicePath
, &DeviceEntry
->Device
);
546 if (!NT_SUCCESS(Status
))
551 /* Fill out the rest of the option structure */
552 Option
->DataOffset
= sizeof(*Option
);
553 Option
->Type
= DeviceType
;
554 Option
->DataSize
= FIELD_OFFSET(BCDE_DEVICE
, Device
) +
555 DeviceEntry
->Device
.Size
;
556 Status
= STATUS_SUCCESS
;
563 * @name EfiInitpCreateApplicationEntry
565 * The EfiInitpCreateApplicationEntry routine
568 * UEFI Image Handle for the current loaded application.
571 * Pointer to the UEFI System Table.
573 * @param MaximumLength
574 * Pointer to the UEFI System Table.
577 * Pointer to the UEFI System Table.
580 * Pointer to the UEFI System Table.
583 * Pointer to the UEFI System Table.
585 * @param LoadOptionsSize
586 * Pointer to the UEFI System Table.
589 * Pointer to the UEFI System Table.
591 * @param ResultLength
592 * Pointer to the UEFI System Table.
594 * @param AppEntryDevice
595 * Pointer to the UEFI System Table.
601 EfiInitpCreateApplicationEntry (
602 __in EFI_SYSTEM_TABLE
*SystemTable
,
603 __in PBL_APPLICATION_ENTRY Entry
,
604 __in ULONG MaximumLength
,
605 __in EFI_DEVICE_PATH
*DevicePath
,
606 __in EFI_DEVICE_PATH
*FilePath
,
607 __in PWCHAR LoadOptions
,
608 __in ULONG LoadOptionsSize
,
610 __out PULONG ResultLength
,
611 __out PBL_DEVICE_DESCRIPTOR
*AppEntryDevice
614 PBL_WINDOWS_LOAD_OPTIONS WindowsOptions
;
615 PWCHAR ObjectString
, CommandLine
;
616 PBL_BCD_OPTION Option
, PreviousOption
;
617 ULONG HeaderSize
, TotalOptionSize
, Size
, CommandLineSize
, RemainingSize
;
619 UNICODE_STRING GuidString
;
621 PBCDE_DEVICE BcdDevice
;
622 BOOLEAN HaveBinaryOptions
, HaveGuid
;
623 PBL_FILE_PATH_DESCRIPTOR OsPath
;
624 EFI_DEVICE_PATH
*OsDevicePath
;
626 /* Initialize everything */
628 *AppEntryDevice
= NULL
;
631 /* Check if the load options are in binary Windows format */
632 WindowsOptions
= (PBL_WINDOWS_LOAD_OPTIONS
)LoadOptions
;
633 if ((WindowsOptions
!= NULL
) &&
634 (LoadOptionsSize
>= sizeof(BL_WINDOWS_LOAD_OPTIONS
)) &&
635 (WindowsOptions
->Length
>= sizeof(BL_WINDOWS_LOAD_OPTIONS
)) &&
636 !(strncmp(WindowsOptions
->Signature
, "WINDOWS", 7)))
638 /* They are, so firmware must have loaded us -- extract arguments */
639 CommandLine
= WindowsOptions
->LoadOptions
;
640 CommandLineSize
= LoadOptionsSize
- FIELD_OFFSET(BL_WINDOWS_LOAD_OPTIONS
,
643 /* Remember that we used binary options */
644 HaveBinaryOptions
= TRUE
;
648 /* Nope -- so treat them as raw command-line options */
649 CommandLine
= LoadOptions
;
650 CommandLineSize
= LoadOptionsSize
;
652 /* No binary options */
653 HaveBinaryOptions
= FALSE
;
656 /* EFI uses UTF-16LE, like NT, so convert to characters */
657 CommandLineSize
/= sizeof(WCHAR
);
658 if (CommandLineSize
!= 0)
660 /* And check if the options are not NULL-terminated */
661 if (wcsnlen(CommandLine
, CommandLineSize
) == CommandLineSize
)
663 /* NULL-terminate them */
664 CommandLine
[CommandLineSize
- 1] = UNICODE_NULL
;
668 /* Begin by making sure we at least have space for the app entry header */
669 RemainingSize
= MaximumLength
;
670 if (RemainingSize
< sizeof(BL_APPLICATION_ENTRY
))
672 Status
= STATUS_INVALID_PARAMETER
;
676 /* On exit, return that we've at least consumed this much */
677 HeaderSize
= FIELD_OFFSET(BL_APPLICATION_ENTRY
, BcdData
);
679 /* Zero out the header, and write down the signature */
680 RtlZeroMemory(Entry
, sizeof(BL_APPLICATION_ENTRY
));
681 RtlCopyMemory(Entry
->Signature
, BL_APP_ENTRY_SIGNATURE
, 7);
683 /* Check if a BCD object was passed on the command-line */
684 ObjectString
= wcsstr(CommandLine
, L
"BCDOBJECT=");
685 if (ObjectString
!= NULL
)
687 /* Convert the BCD object to a GUID */
688 RtlInitUnicodeString(&GuidString
, ObjectString
+ 10);
689 RtlGUIDFromString(&GuidString
, &ObjectGuid
);
691 /* Store it in the application entry */
692 Entry
->Guid
= ObjectGuid
;
694 /* Remember one was passed */
699 /* Remember that no identifier was passed */
700 Entry
->Flags
|= BL_APPLICATION_ENTRY_FLAG_NO_GUID
;
704 /* At this point, the header is consumed, and we must now handle BCD options */
705 RemainingSize
-= FIELD_OFFSET(BL_APPLICATION_ENTRY
, BcdData
);
707 /* Convert the device path into a BCD option */
708 Status
= EfiInitpConvertEfiDevicePath(DevicePath
,
709 BcdLibraryDevice_ApplicationDevice
,
712 if (!NT_SUCCESS(Status
))
714 /* We failed, so mark the option as such and return an empty one */
715 Entry
->BcdData
.Empty
= TRUE
;
716 TotalOptionSize
= sizeof(BL_BCD_OPTION
);
720 /* Extract the device descriptor and return it */
721 BcdDevice
= (PVOID
)((ULONG_PTR
)&Entry
->BcdData
+ Entry
->BcdData
.DataOffset
);
722 *AppEntryDevice
= &BcdDevice
->Device
;
724 /* Calculate how big this option was and consume that from the buffer */
725 TotalOptionSize
= BlGetBootOptionSize(&Entry
->BcdData
);
726 RemainingSize
-= TotalOptionSize
;
728 /* Calculate where the next option should go */
729 Option
= (PVOID
)((ULONG_PTR
)&Entry
->BcdData
+ TotalOptionSize
);
731 /* Check if we're PXE booting or not */
732 if ((*AppEntryDevice
)->DeviceType
== UdpDevice
)
735 Status
= STATUS_NOT_IMPLEMENTED
;
739 /* Convert the local file path into a BCD option */
740 Status
= EfiInitpConvertEfiFilePath(FilePath
,
741 BcdLibraryString_ApplicationPath
,
746 /* Bail out on failure */
747 if (!NT_SUCCESS(Status
))
752 /* The next option is right after this one */
753 Entry
->BcdData
.NextEntryOffset
= TotalOptionSize
;
755 /* Now compute the size of the next option, and add to the rolling sum */
756 Size
= BlGetBootOptionSize(Option
);
757 TotalOptionSize
+= Size
;
759 /* Remember the previous option so we can update its next offset */
760 PreviousOption
= Option
;
762 /* Consume the option from the buffer */
763 RemainingSize
-= Size
;
765 /* Calculate where the next option should go */
766 Option
= (PVOID
)((ULONG_PTR
)Option
+ Size
);
768 /* Check if we were using binary options without a BCD GUID */
769 if ((HaveBinaryOptions
) && !(HaveGuid
))
771 /* Then this means we have to convert the OS paths to BCD too */
772 WindowsOptions
= (PBL_WINDOWS_LOAD_OPTIONS
)LoadOptions
;
773 OsPath
= (PVOID
)((ULONG_PTR
)WindowsOptions
+ WindowsOptions
->OsPathOffset
);
775 /* IS the OS path in EFI format? */
776 if ((OsPath
->Length
> (ULONG
)FIELD_OFFSET(BL_FILE_PATH_DESCRIPTOR
, Path
)) &&
777 (OsPath
->PathType
== EfiPath
))
779 /* Convert the device portion */
780 OsDevicePath
= (EFI_DEVICE_PATH
*)OsPath
->Path
;
781 Status
= EfiInitpConvertEfiDevicePath(OsDevicePath
,
782 BcdOSLoaderDevice_OSDevice
,
785 if (!NT_SUCCESS(Status
))
790 /* Update the offset of the previous option */
791 PreviousOption
->NextEntryOffset
= (ULONG_PTR
)Option
- (ULONG_PTR
)&Entry
->BcdData
;
793 /* Now compute the size of the next option, and add to the rolling sum */
794 Size
= BlGetBootOptionSize(Option
);
795 TotalOptionSize
+= Size
;
797 /* Remember the previous option so we can update its next offset */
798 PreviousOption
= Option
;
800 /* Consume the option from the buffer */
801 RemainingSize
-= Size
;
803 /* Calculate where the next option should go */
804 Option
= (PVOID
)((ULONG_PTR
)Option
+ Size
);
806 /* Convert the path oprtion */
807 Status
= EfiInitpConvertEfiFilePath(OsDevicePath
,
808 BcdOSLoaderString_SystemRoot
,
811 if (!NT_SUCCESS(Status
))
816 /* Update the offset of the previous option */
817 PreviousOption
->NextEntryOffset
= (ULONG_PTR
)Option
- (ULONG_PTR
)&Entry
->BcdData
;
819 /* Now compute the size of the next option, and add to the rolling sum */
820 Size
= BlGetBootOptionSize(Option
);
821 TotalOptionSize
+= Size
;
823 /* Remember the previous option so we can update its next offset */
824 PreviousOption
= Option
;
826 /* Consume the option from the buffer */
827 RemainingSize
-= Size
;
829 /* Calculate where the next option should go */
830 Option
= (PVOID
)((ULONG_PTR
)Option
+ Size
);
834 /* Now convert everything else */
835 AhCreateLoadOptionsList(CommandLine
,
843 /* Return the final size */
844 *ResultLength
= HeaderSize
+ TotalOptionSize
;
848 * @name EfiInitCreateInputParametersEx
850 * The EfiInitCreateInputParametersEx routine converts UEFI entrypoint
851 * parameters to the ones expected by Windows Boot Applications
854 * UEFI Image Handle for the current loaded application.
857 * Pointer to the UEFI System Table.
859 * @return A PBOOT_APPLICATION_PARAMETER_BLOCK structure containing the data
860 * from UEFI, translated to the Boot Library-compatible format.
863 PBOOT_APPLICATION_PARAMETER_BLOCK
864 EfiInitCreateInputParametersEx (
865 _In_ EFI_HANDLE ImageHandle
,
866 _In_ EFI_SYSTEM_TABLE
*SystemTable
869 EFI_BOOT_SERVICES
* BootServices
;
870 EFI_LOADED_IMAGE_PROTOCOL
*LoadedImage
;
871 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
872 PBL_FIRMWARE_DESCRIPTOR FirmwareData
;
873 PBL_RETURN_ARGUMENTS ReturnArguments
;
874 ULONG FirmwareOffset
, ConsumedSize
;
875 PBL_DEVICE_DESCRIPTOR AppDevice
;
878 /* Initialize the header with the signature and version */
879 EfiInitScratch
.Signature
[0] = BOOT_APPLICATION_SIGNATURE_1
;
880 EfiInitScratch
.Signature
[1] = BOOT_APPLICATION_SIGNATURE_2
;
881 EfiInitScratch
.Version
= BOOT_APPLICATION_VERSION
;
883 /* Set the image type to x86 */
884 EfiInitScratch
.ImageType
= EFI_IMAGE_MACHINE_IA32
;
886 /* Set the translation type to physical */
887 EfiInitScratch
.MemoryTranslationType
= BOOT_MEMORY_TRANSLATION_TYPE_PHYSICAL
;
889 /* Indicate that the data was converted from EFI */
890 BlpApplicationFlags
|= BL_APPLICATION_FLAG_CONVERTED_FROM_EFI
;
892 /* Grab the loaded image protocol, which has our base and size */
893 BootServices
= SystemTable
->BootServices
;
894 Status
= BootServices
->HandleProtocol(ImageHandle
,
895 &EfiLoadedImageProtocol
,
896 (VOID
**)&LoadedImage
);
897 if (Status
!= EFI_SUCCESS
)
902 /* Capture it in the boot application parameters */
903 EfiInitScratch
.ImageBase
= (ULONG_PTR
)LoadedImage
->ImageBase
;
904 EfiInitScratch
.ImageSize
= (ULONG
)LoadedImage
->ImageSize
;
906 /* Now grab our device path protocol, so we can convert the path later on */
907 Status
= BootServices
->HandleProtocol(LoadedImage
->DeviceHandle
,
908 &EfiDevicePathProtocol
,
909 (VOID
**)&DevicePath
);
910 if (Status
!= EFI_SUCCESS
)
915 /* The built-in boot memory data comes right after our block */
916 EfiInitScratch
.MemoryDataOffset
=
917 FIELD_OFFSET(BOOT_APPLICATION_PARAMETER_BLOCK_SCRATCH
, BootMemoryData
);
919 /* Build the boot memory data structure, with 1 descriptor */
920 EfiInitScratch
.BootMemoryData
.Version
= BL_MEMORY_DATA_VERSION
;
921 EfiInitScratch
.BootMemoryData
.MdListOffset
=
922 FIELD_OFFSET(BOOT_APPLICATION_PARAMETER_BLOCK_SCRATCH
, MemEntry
) -
923 EfiInitScratch
.MemoryDataOffset
;
924 EfiInitScratch
.BootMemoryData
.DescriptorSize
= sizeof(BL_MEMORY_DESCRIPTOR
);
925 EfiInitScratch
.BootMemoryData
.DescriptorCount
= 1;
926 EfiInitScratch
.BootMemoryData
.DescriptorOffset
= FIELD_OFFSET(BL_MEMORY_DESCRIPTOR
, BasePage
);
928 /* Build the memory entry descriptor for this image itself */
929 EfiInitScratch
.MemEntry
.Flags
= BlMemoryWriteBack
;
930 EfiInitScratch
.MemEntry
.Type
= BlLoaderMemory
;
931 EfiInitScratch
.MemEntry
.BasePage
= EfiInitScratch
.ImageBase
>> PAGE_SHIFT
;
932 EfiInitScratch
.MemEntry
.PageCount
= ALIGN_UP_BY(EfiInitScratch
.ImageSize
, PAGE_SIZE
) >> PAGE_SHIFT
;
934 /* The built-in application entry comes right after the memory descriptor*/
935 EfiInitScratch
.AppEntryOffset
=
936 FIELD_OFFSET(BOOT_APPLICATION_PARAMETER_BLOCK_SCRATCH
, AppEntry
);
938 /* Go and build it */
939 EfiInitpCreateApplicationEntry(SystemTable
,
940 (PBL_APPLICATION_ENTRY
)&EfiInitScratch
.AppEntry
,
941 sizeof(EfiInitScratch
.AppEntry
),
943 LoadedImage
->FilePath
,
944 LoadedImage
->LoadOptions
,
945 LoadedImage
->LoadOptionsSize
,
946 EfiInitScratch
.MemEntry
.PageCount
,
950 /* Boot device information comes right after the application entry */
951 EfiInitScratch
.BootDeviceOffset
= ConsumedSize
+ EfiInitScratch
.AppEntryOffset
;
953 /* Check if we have a boot device */
954 if (AppDevice
!= NULL
)
956 /* We do -- copy it */
957 RtlCopyMemory(EfiInitScratch
.AppEntry
+ ConsumedSize
,
961 /* Firmware data follows right after the boot device entry */
962 FirmwareOffset
= AppDevice
->Size
+ EfiInitScratch
.BootDeviceOffset
;
966 /* We do not, so zero out the space where a full boot device structure would fit */
967 RtlZeroMemory(EfiInitScratch
.AppEntry
+ ConsumedSize
,
968 sizeof(BL_DEVICE_DESCRIPTOR
));
970 /* And start the firmware data past that */
971 FirmwareOffset
= EfiInitScratch
.BootDeviceOffset
+ sizeof(BL_DEVICE_DESCRIPTOR
);
974 /* Set the computed firmware data offset */
975 EfiInitScratch
.FirmwareParametersOffset
= FirmwareOffset
;
977 /* Fill out the firmware data that's there */
978 FirmwareData
= (PVOID
)((ULONG_PTR
)&EfiInitScratch
+ EfiInitScratch
.FirmwareParametersOffset
);
979 FirmwareData
->Version
= BL_FIRMWARE_DESCRIPTOR_VERSION
;
980 FirmwareData
->ImageHandle
= ImageHandle
;
981 FirmwareData
->SystemTable
= SystemTable
;
983 /* Finally, set the return argument offset */
984 EfiInitScratch
.ReturnArgumentsOffset
= FirmwareOffset
+ sizeof(BL_FIRMWARE_DESCRIPTOR
);
986 /* And fill out the return argument data */
987 ReturnArguments
= (PVOID
)((ULONG_PTR
)&EfiInitScratch
+ EfiInitScratch
.ReturnArgumentsOffset
);
988 ReturnArguments
->Version
= BL_RETURN_ARGUMENTS_VERSION
;
990 /* We're done, compute the final size and return the block */
991 EfiInitScratch
.Size
= EfiInitScratch
.ReturnArgumentsOffset
+ sizeof(BL_RETURN_ARGUMENTS
);
992 return (PBOOT_APPLICATION_PARAMETER_BLOCK
)&EfiInitScratch
;
998 * The EfiEntry routine implements the UEFI entrypoint for the application.
1000 * @param ImageHandle
1001 * UEFI Image Handle for the current loaded application.
1003 * @param SystemTable
1004 * Pointer to the UEFI System Table.
1006 * @return EFI_SUCCESS if the image was loaded correctly, relevant error code
1013 _In_ EFI_HANDLE ImageHandle
,
1014 _In_ EFI_SYSTEM_TABLE
*SystemTable
1018 PBOOT_APPLICATION_PARAMETER_BLOCK BootParameters
;
1020 /* Convert EFI parameters to Windows Boot Application parameters */
1021 BootParameters
= EfiInitCreateInputParametersEx(ImageHandle
, SystemTable
);
1022 if (BootParameters
!= NULL
)
1024 /* Conversion was good -- call the Boot Manager Entrypoint */
1025 Status
= BmMain(BootParameters
);
1029 /* Conversion failed, bail out */
1030 Status
= STATUS_INVALID_PARAMETER
;
1033 /* Convert the NT status code to an EFI code */
1034 return EfiGetEfiStatusCode(Status
);