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 GUID EfiLoadedImageProtocol
= EFI_LOADED_IMAGE_PROTOCOL_GUID
;
29 GUID EfiDevicePathProtocol
= EFI_DEVICE_PATH_PROTOCOL_GUID
;
31 BOOT_APPLICATION_PARAMETER_BLOCK_SCRATCH EfiInitScratch
;
33 /* FUNCTIONS *****************************************************************/
36 * @name AhCreateLoadOptionsList
38 * The AhCreateLoadOptionsList routine
41 * UEFI Image Handle for the current loaded application.
44 * Pointer to the UEFI System Table.
46 * @param MaximumLength
47 * Pointer to the UEFI System Table.
50 * Pointer to the UEFI System Table.
52 * @param PreviousOption
53 * Pointer to the UEFI System Table.
55 * @param PreviousOptionSize
56 * Pointer to the UEFI System Table.
62 AhCreateLoadOptionsList (
63 _In_ PWCHAR CommandLine
,
64 _In_ PBL_BCD_OPTION BootOptions
,
65 _In_ ULONG MaximumLength
,
66 _Out_ PULONG OptionSize
,
67 _In_ PBL_BCD_OPTION
* PreviousOption
,
68 _In_ PULONG PreviousOptionSize
71 return STATUS_NOT_IMPLEMENTED
;
75 * @name EfiInitpAppendPathString
77 * The EfiInitpAppendPathString routine
79 * @param DestinationPath
80 * UEFI Image Handle for the current loaded application.
82 * @param RemainingSize
83 * Pointer to the UEFI System Table.
86 * Pointer to the UEFI System Table.
89 * Pointer to the UEFI System Table.
91 * @param BytesAppended
92 * Pointer to the UEFI System Table.
98 EfiInitpAppendPathString (
99 _In_ PWCHAR PathString
,
100 _In_ ULONG MaximumLength
,
101 _In_ PWCHAR NewPathString
,
102 _In_ ULONG NewPathLength
,
103 _Out_ PULONG ResultLength
107 ULONG FinalPathLength
;
109 /* We deal in Unicode, validate the length */
110 if (NewPathLength
& 1)
112 return STATUS_INVALID_PARAMETER
;
115 /* Is the new element at least a character? */
116 Status
= STATUS_SUCCESS
;
117 if (NewPathLength
>= sizeof(WCHAR
))
119 /* Is the last character already a NULL character? */
120 if (NewPathString
[(NewPathLength
- sizeof(WCHAR
)) / sizeof(WCHAR
)] ==
123 /* Then we won't need to count it */
124 NewPathLength
-= sizeof(UNICODE_NULL
);
127 /* Was it more than just a NULL character? */
128 if (NewPathLength
>= sizeof(WCHAR
))
130 /* Yep -- but does it have a separator? */
131 if (*NewPathString
== OBJ_NAME_PATH_SEPARATOR
)
133 /* Skip it, we'll add our own later */
135 NewPathLength
-= sizeof(OBJ_NAME_PATH_SEPARATOR
);
138 /* Was it more than just a separator? */
139 if (NewPathLength
>= sizeof(WCHAR
))
141 /* Yep -- but does it end with a separator? */
142 if (NewPathString
[(NewPathLength
- sizeof(WCHAR
)) / sizeof(WCHAR
)] ==
143 OBJ_NAME_PATH_SEPARATOR
)
145 /* That's something else we won't need for now */
146 NewPathLength
-= sizeof(OBJ_NAME_PATH_SEPARATOR
);
152 /* Check if anything needs to be appended after all */
153 if (NewPathLength
!= 0)
155 /* We will append the length of the new path element, plus a separator */
156 FinalPathLength
= NewPathLength
+ sizeof(OBJ_NAME_PATH_SEPARATOR
);
157 if (MaximumLength
>= FinalPathLength
)
159 /* Add a separator to the existing path*/
160 *PathString
= OBJ_NAME_PATH_SEPARATOR
;
162 /* Followed by the new path element */
163 RtlCopyMemory(PathString
+ 1, NewPathString
, NewPathLength
);
165 /* Return the number of bytes appended */
166 *ResultLength
= FinalPathLength
;
170 /* There's not enough space to do this */
171 Status
= STATUS_BUFFER_TOO_SMALL
;
176 /* Nothing to append */
184 * @name EfiInitpConvertEfiDevicePath
186 * The EfiInitpConvertEfiDevicePath routine
189 * UEFI Image Handle for the current loaded application.
192 * Pointer to the UEFI System Table.
195 * Pointer to the UEFI System Table.
197 * @param MaximumLength
198 * Pointer to the UEFI System Table.
204 EfiInitpConvertEfiFilePath (
205 _In_ EFI_DEVICE_PATH_PROTOCOL
*DevicePath
,
207 _In_ PBL_BCD_OPTION Option
,
208 _In_ ULONG MaximumLength
211 ULONG BytesAppended
, DataSize
, StringLength
;
212 PBCDE_STRING StringEntry
;
214 FILEPATH_DEVICE_PATH
*FilePath
;
217 /* Make sure we have enough space for the option */
218 if (MaximumLength
< sizeof(*Option
))
220 return STATUS_INVALID_PARAMETER
;
223 /* Set the initial size of the option, and consume from our buffer */
224 DataSize
= sizeof(*Option
);
225 MaximumLength
-= sizeof(*Option
);
227 /* Zero out and fill the option header */
228 RtlZeroMemory(Option
, DataSize
);
229 Option
->Type
= PathType
;
230 Option
->DataOffset
= sizeof(*Option
);
232 /* Extract the string option */
233 StringEntry
= (PBCDE_STRING
)(Option
+ 1);
234 PathString
= StringEntry
->String
;
236 /* Start parsing the device path */
237 FilePath
= (FILEPATH_DEVICE_PATH
*)DevicePath
;
238 while (IsDevicePathEndType(FilePath
) == FALSE
)
240 /* Is this a file path? */
241 if ((FilePath
->Header
.Type
== MEDIA_DEVICE_PATH
) &&
242 (FilePath
->Header
.SubType
== MEDIA_FILEPATH_DP
))
244 /* Get the length of the file path string, avoiding overflow */
245 StringLength
= DevicePathNodeLength(FilePath
) -
246 FIELD_OFFSET(FILEPATH_DEVICE_PATH
, PathName
);
247 if (StringLength
< (ULONG
)FIELD_OFFSET(FILEPATH_DEVICE_PATH
, PathName
))
249 Status
= STATUS_INTEGER_OVERFLOW
;
253 /* Append this path string to the current path string */
254 Status
= EfiInitpAppendPathString(PathString
,
259 if (!NT_SUCCESS(Status
)) return 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
= LocalDevice
;
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
= PartitionDevice
;
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
= HardDiskDevice
;
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 /* Othertwise, raw boot is not supported */
470 DeviceEntry
->DeviceType
= HardDiskDevice
;
471 DeviceEntry
->Partition
.Disk
.HardDisk
.PartitionType
= RawPartition
;
472 DeviceEntry
->Partition
.Disk
.HardDisk
.Raw
.DiskNumber
= 0;
474 else if (DeviceNode
->SubType
== MEDIA_CDROM_DP
)
476 /* Set the right type for a CDROM */
477 DeviceEntry
->DeviceType
= LocalDevice
;
478 DeviceEntry
->Local
.Type
= CdRomDevice
;
480 /* Set the drive number to zero */
481 DeviceEntry
->Local
.FloppyDisk
.DriveNumber
= 0;
482 return STATUS_SUCCESS
;
485 /* Fail anything else */
490 /* Return here only on failure */
495 * @name EfiInitpConvertEfiDevicePath
497 * The EfiInitpConvertEfiDevicePath routine
500 * UEFI Image Handle for the current loaded application.
503 * Pointer to the UEFI System Table.
506 * Pointer to the UEFI System Table.
508 * @param MaximumLength
509 * Pointer to the UEFI System Table.
515 EfiInitpConvertEfiDevicePath (
516 _In_ EFI_DEVICE_PATH_PROTOCOL
*DevicePath
,
517 _In_ ULONG DeviceType
,
518 _In_ PBL_BCD_OPTION Option
,
519 _In_ ULONG MaximumLength
522 PBCDE_DEVICE DeviceEntry
;
525 /* Make sure we have enough space for the option */
526 if (MaximumLength
< sizeof(*Option
))
528 Status
= STATUS_INVALID_PARAMETER
;
532 /* Zero out the option */
533 RtlZeroMemory(Option
, sizeof(*Option
));
535 /* Make sure we have enough space for the device entry */
536 if ((MaximumLength
- sizeof(*Option
)) < (ULONG
)FIELD_OFFSET(BCDE_DEVICE
, Device
))
538 Status
= STATUS_INVALID_PARAMETER
;
543 DeviceEntry
= (PBCDE_DEVICE
)(Option
+ 1);
544 Status
= EfiInitTranslateDevicePath(DevicePath
, &DeviceEntry
->Device
);
545 if (!NT_SUCCESS(Status
))
550 /* Fill out the rest of the option structure */
551 Option
->DataOffset
= sizeof(*Option
);
552 Option
->Type
= DeviceType
;
553 Option
->DataSize
= FIELD_OFFSET(BCDE_DEVICE
, Device
) +
554 DeviceEntry
->Device
.Size
;
555 Status
= STATUS_SUCCESS
;
562 * @name EfiInitpCreateApplicationEntry
564 * The EfiInitpCreateApplicationEntry routine
567 * UEFI Image Handle for the current loaded application.
570 * Pointer to the UEFI System Table.
572 * @param MaximumLength
573 * Pointer to the UEFI System Table.
576 * Pointer to the UEFI System Table.
579 * Pointer to the UEFI System Table.
582 * Pointer to the UEFI System Table.
584 * @param LoadOptionsSize
585 * Pointer to the UEFI System Table.
588 * Pointer to the UEFI System Table.
590 * @param ResultLength
591 * Pointer to the UEFI System Table.
593 * @param AppEntryDevice
594 * Pointer to the UEFI System Table.
600 EfiInitpCreateApplicationEntry (
601 __in EFI_SYSTEM_TABLE
*SystemTable
,
602 __in PBL_APPLICATION_ENTRY Entry
,
603 __in ULONG MaximumLength
,
604 __in EFI_DEVICE_PATH
*DevicePath
,
605 __in EFI_DEVICE_PATH
*FilePath
,
606 __in PWCHAR LoadOptions
,
607 __in ULONG LoadOptionsSize
,
609 __out PULONG ResultLength
,
610 __out PBL_DEVICE_DESCRIPTOR
*AppEntryDevice
613 PBL_WINDOWS_LOAD_OPTIONS WindowsOptions
;
614 PWCHAR ObjectString
, CommandLine
;
615 PBL_BCD_OPTION Option
, PreviousOption
;
616 ULONG HeaderSize
, TotalOptionSize
, Size
, CommandLineSize
, RemainingSize
;
618 UNICODE_STRING GuidString
;
620 PBCDE_DEVICE BcdDevice
;
621 BOOLEAN HaveBinaryOptions
, HaveGuid
;
622 PBL_FILE_PATH_DESCRIPTOR OsPath
;
623 EFI_DEVICE_PATH
*OsDevicePath
;
625 /* Initialize everything */
627 *AppEntryDevice
= NULL
;
630 /* Check if the load options are in binary Windows format */
631 WindowsOptions
= (PBL_WINDOWS_LOAD_OPTIONS
)LoadOptions
;
632 if ((WindowsOptions
!= NULL
) &&
633 (LoadOptionsSize
>= sizeof(BL_WINDOWS_LOAD_OPTIONS
)) &&
634 (WindowsOptions
->Length
>= sizeof(BL_WINDOWS_LOAD_OPTIONS
)) &&
635 !(strncmp(WindowsOptions
->Signature
, "WINDOWS", 7)))
637 /* They are, so firmware must have loaded us -- extract arguments */
638 CommandLine
= WindowsOptions
->LoadOptions
;
639 CommandLineSize
= LoadOptionsSize
- FIELD_OFFSET(BL_WINDOWS_LOAD_OPTIONS
,
642 /* Remember that we used binary options */
643 HaveBinaryOptions
= TRUE
;
647 /* Nope -- so treat them as raw command-line options */
648 CommandLine
= LoadOptions
;
649 CommandLineSize
= LoadOptionsSize
;
651 /* No binary options */
652 HaveBinaryOptions
= FALSE
;
655 /* EFI uses UTF-16LE, like NT, so convert to characters */
656 CommandLineSize
/= sizeof(WCHAR
);
657 if (CommandLineSize
!= 0)
659 /* And check if the options are not NULL-terminated */
660 if (wcsnlen(CommandLine
, CommandLineSize
) == CommandLineSize
)
662 /* NULL-terminate them */
663 CommandLine
[CommandLineSize
- 1] = UNICODE_NULL
;
667 /* Begin by making sure we at least have space for the app entry header */
668 RemainingSize
= MaximumLength
;
669 if (RemainingSize
< sizeof(BL_APPLICATION_ENTRY
))
671 EarlyPrint(L
"Remaining size too small!\n");
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 EarlyPrint(L
"Failed to convert device path: %lx\n", Status
);
716 Entry
->BcdData
.Empty
= TRUE
;
717 TotalOptionSize
= sizeof(BL_BCD_OPTION
);
721 /* Extract the device descriptor and return it */
722 BcdDevice
= (PVOID
)((ULONG_PTR
)&Entry
->BcdData
+ Entry
->BcdData
.DataOffset
);
723 *AppEntryDevice
= &BcdDevice
->Device
;
725 /* Calculate how big this option was and consume that from the buffer */
726 TotalOptionSize
= BlGetBootOptionSize(&Entry
->BcdData
);
727 RemainingSize
-= TotalOptionSize
;
729 /* Calculate where the next option should go */
730 Option
= (PVOID
)((ULONG_PTR
)&Entry
->BcdData
+ TotalOptionSize
);
732 /* Check if we're PXE booting or not */
733 if ((*AppEntryDevice
)->DeviceType
== UdpDevice
)
736 Status
= STATUS_NOT_IMPLEMENTED
;
737 EarlyPrint(L
"UDP Boot not supported!\n");
741 /* Convert the local file path into a BCD option */
742 Status
= EfiInitpConvertEfiFilePath(FilePath
,
743 BcdLibraryString_ApplicationPath
,
748 /* Bail out on failure */
749 if (!NT_SUCCESS(Status
))
751 EarlyPrint(L
"Failed to convert file path: %lx\n", Status
);
755 /* The next option is right after this one */
756 Entry
->BcdData
.NextEntryOffset
= TotalOptionSize
;
758 /* Now compute the size of the next option, and add to the rolling sum */
759 Size
= BlGetBootOptionSize(Option
);
760 TotalOptionSize
+= Size
;
762 /* Remember the previous option so we can update its next offset */
763 PreviousOption
= Option
;
765 /* Consume the option from the buffer */
766 RemainingSize
-= Size
;
768 /* Calculate where the next option should go */
769 Option
= (PVOID
)((ULONG_PTR
)Option
+ Size
);
771 /* Check if we were using binary options without a BCD GUID */
772 if ((HaveBinaryOptions
) && !(HaveGuid
))
774 /* Then this means we have to convert the OS paths to BCD too */
775 WindowsOptions
= (PBL_WINDOWS_LOAD_OPTIONS
)LoadOptions
;
776 OsPath
= (PVOID
)((ULONG_PTR
)WindowsOptions
+ WindowsOptions
->OsPathOffset
);
778 /* IS the OS path in EFI format? */
779 if ((OsPath
->Length
> (ULONG
)FIELD_OFFSET(BL_FILE_PATH_DESCRIPTOR
, Path
)) &&
780 (OsPath
->PathType
== EfiPath
))
782 /* Convert the device portion */
783 OsDevicePath
= (EFI_DEVICE_PATH
*)OsPath
->Path
;
784 Status
= EfiInitpConvertEfiDevicePath(OsDevicePath
,
785 BcdOSLoaderDevice_OSDevice
,
788 if (!NT_SUCCESS(Status
))
790 EarlyPrint(L
"Failed to convert OS device path: %lx\n", Status
);
794 /* Update the offset of the previous option */
795 PreviousOption
->NextEntryOffset
= (ULONG_PTR
)Option
- (ULONG_PTR
)&Entry
->BcdData
;
797 /* Now compute the size of the next option, and add to the rolling sum */
798 Size
= BlGetBootOptionSize(Option
);
799 TotalOptionSize
+= Size
;
801 /* Remember the previous option so we can update its next offset */
802 PreviousOption
= Option
;
804 /* Consume the option from the buffer */
805 RemainingSize
-= Size
;
807 /* Calculate where the next option should go */
808 Option
= (PVOID
)((ULONG_PTR
)Option
+ Size
);
810 /* Convert the path oprtion */
811 Status
= EfiInitpConvertEfiFilePath(OsDevicePath
,
812 BcdOSLoaderString_SystemRoot
,
815 if (!NT_SUCCESS(Status
))
817 EarlyPrint(L
"Failed to convert OS file path: %lx\n", Status
);
821 /* Update the offset of the previous option */
822 PreviousOption
->NextEntryOffset
= (ULONG_PTR
)Option
- (ULONG_PTR
)&Entry
->BcdData
;
824 /* Now compute the size of the next option, and add to the rolling sum */
825 Size
= BlGetBootOptionSize(Option
);
826 TotalOptionSize
+= Size
;
828 /* Remember the previous option so we can update its next offset */
829 PreviousOption
= Option
;
831 /* Consume the option from the buffer */
832 RemainingSize
-= Size
;
834 /* Calculate where the next option should go */
835 Option
= (PVOID
)((ULONG_PTR
)Option
+ Size
);
839 /* Now convert everything else */
840 AhCreateLoadOptionsList(CommandLine
,
848 /* Return the final size */
849 *ResultLength
= HeaderSize
+ TotalOptionSize
;
853 * @name EfiInitCreateInputParametersEx
855 * The EfiInitCreateInputParametersEx routine converts UEFI entrypoint
856 * parameters to the ones expected by Windows Boot Applications
859 * UEFI Image Handle for the current loaded application.
862 * Pointer to the UEFI System Table.
864 * @return A PBOOT_APPLICATION_PARAMETER_BLOCK structure containing the data
865 * from UEFI, translated to the Boot Library-compatible format.
868 PBOOT_APPLICATION_PARAMETER_BLOCK
869 EfiInitCreateInputParametersEx (
870 _In_ EFI_HANDLE ImageHandle
,
871 _In_ EFI_SYSTEM_TABLE
*SystemTable
874 EFI_BOOT_SERVICES
* BootServices
;
875 EFI_LOADED_IMAGE_PROTOCOL
*LoadedImage
;
876 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
877 PBL_FIRMWARE_DESCRIPTOR FirmwareData
;
878 PBL_RETURN_ARGUMENTS ReturnArguments
;
879 ULONG FirmwareOffset
, ConsumedSize
;
880 PBL_DEVICE_DESCRIPTOR AppDevice
;
883 /* Initialize the header with the signature and version */
884 EfiInitScratch
.Signature
[0] = BOOT_APPLICATION_SIGNATURE_1
;
885 EfiInitScratch
.Signature
[1] = BOOT_APPLICATION_SIGNATURE_2
;
886 EfiInitScratch
.Version
= BOOT_APPLICATION_VERSION
;
888 /* Set the image type to x86 */
889 EfiInitScratch
.ImageType
= EFI_IMAGE_MACHINE_IA32
;
891 /* Set the translation type to physical */
892 EfiInitScratch
.MemoryTranslationType
= BOOT_MEMORY_TRANSLATION_TYPE_PHYSICAL
;
894 /* Indicate that the data was converted from EFI */
895 BlpApplicationFlags
|= BL_APPLICATION_FLAG_CONVERTED_FROM_EFI
;
897 /* Grab the loaded image protocol, which has our base and size */
898 BootServices
= SystemTable
->BootServices
;
899 Status
= BootServices
->HandleProtocol(ImageHandle
,
900 &EfiLoadedImageProtocol
,
901 (VOID
**)&LoadedImage
);
902 if (Status
!= EFI_SUCCESS
)
904 EarlyPrint(L
"Loaded image failed: %lx\n", Status
);
908 /* Capture it in the boot application parameters */
909 EfiInitScratch
.ImageBase
= (ULONG_PTR
)LoadedImage
->ImageBase
;
910 EfiInitScratch
.ImageSize
= (ULONG
)LoadedImage
->ImageSize
;
912 /* Now grab our device path protocol, so we can convert the path later on */
913 Status
= BootServices
->HandleProtocol(LoadedImage
->DeviceHandle
,
914 &EfiDevicePathProtocol
,
915 (VOID
**)&DevicePath
);
916 if (Status
!= EFI_SUCCESS
)
918 EarlyPrint(L
"Device Path failed: %lx\n", Status
);
922 /* The built-in boot memory data comes right after our block */
923 EfiInitScratch
.MemoryDataOffset
=
924 FIELD_OFFSET(BOOT_APPLICATION_PARAMETER_BLOCK_SCRATCH
, BootMemoryData
);
926 /* Build the boot memory data structure, with 1 descriptor */
927 EfiInitScratch
.BootMemoryData
.Version
= BL_MEMORY_DATA_VERSION
;
928 EfiInitScratch
.BootMemoryData
.MdListOffset
=
929 FIELD_OFFSET(BOOT_APPLICATION_PARAMETER_BLOCK_SCRATCH
, MemEntry
) -
930 EfiInitScratch
.MemoryDataOffset
;
931 EfiInitScratch
.BootMemoryData
.DescriptorSize
= sizeof(BL_MEMORY_DESCRIPTOR
);
932 EfiInitScratch
.BootMemoryData
.DescriptorCount
= 1;
933 EfiInitScratch
.BootMemoryData
.DescriptorOffset
= FIELD_OFFSET(BL_MEMORY_DESCRIPTOR
, BasePage
);
935 /* Build the memory entry descriptor for this image itself */
936 EfiInitScratch
.MemEntry
.Flags
= BlMemoryWriteBack
;
937 EfiInitScratch
.MemEntry
.Type
= BlLoaderMemory
;
938 EfiInitScratch
.MemEntry
.BasePage
= EfiInitScratch
.ImageBase
>> PAGE_SHIFT
;
939 EfiInitScratch
.MemEntry
.PageCount
= ALIGN_UP_BY(EfiInitScratch
.ImageSize
, PAGE_SIZE
) >> PAGE_SHIFT
;
941 /* The built-in application entry comes right after the memory descriptor*/
942 EfiInitScratch
.AppEntryOffset
=
943 FIELD_OFFSET(BOOT_APPLICATION_PARAMETER_BLOCK_SCRATCH
, AppEntry
);
945 /* Go and build it */
946 EfiInitpCreateApplicationEntry(SystemTable
,
947 (PBL_APPLICATION_ENTRY
)&EfiInitScratch
.AppEntry
,
948 sizeof(EfiInitScratch
.AppEntry
),
950 LoadedImage
->FilePath
,
951 LoadedImage
->LoadOptions
,
952 LoadedImage
->LoadOptionsSize
,
953 EfiInitScratch
.MemEntry
.PageCount
,
957 /* Boot device information comes right after the application entry */
958 EfiInitScratch
.BootDeviceOffset
= ConsumedSize
+ EfiInitScratch
.AppEntryOffset
;
960 /* Check if we have a boot device */
961 if (AppDevice
!= NULL
)
963 /* We do -- copy it */
964 RtlCopyMemory(EfiInitScratch
.AppEntry
+ ConsumedSize
,
968 /* Firmware data follows right after the boot device entry */
969 FirmwareOffset
= AppDevice
->Size
+ EfiInitScratch
.BootDeviceOffset
;
973 /* We do not, so zero out the space where a full boot device structure would fit */
974 RtlZeroMemory(EfiInitScratch
.AppEntry
+ ConsumedSize
,
975 sizeof(BL_DEVICE_DESCRIPTOR
));
977 /* And start the firmware data past that */
978 FirmwareOffset
= EfiInitScratch
.BootDeviceOffset
+ sizeof(BL_DEVICE_DESCRIPTOR
);
981 /* Set the computed firmware data offset */
982 EfiInitScratch
.FirmwareParametersOffset
= FirmwareOffset
;
984 /* Fill out the firmware data that's there */
985 FirmwareData
= (PVOID
)((ULONG_PTR
)&EfiInitScratch
+ EfiInitScratch
.FirmwareParametersOffset
);
986 FirmwareData
->Version
= BL_FIRMWARE_DESCRIPTOR_VERSION
;
987 FirmwareData
->ImageHandle
= ImageHandle
;
988 FirmwareData
->SystemTable
= SystemTable
;
990 /* Finally, set the return argument offset */
991 EfiInitScratch
.ReturnArgumentsOffset
= FirmwareOffset
+ sizeof(BL_FIRMWARE_DESCRIPTOR
);
993 /* And fill out the return argument data */
994 ReturnArguments
= (PVOID
)((ULONG_PTR
)&EfiInitScratch
+ EfiInitScratch
.ReturnArgumentsOffset
);
995 ReturnArguments
->Version
= BL_RETURN_ARGUMENTS_VERSION
;
997 /* We're done, compute the final size and return the block */
998 EfiInitScratch
.Size
= EfiInitScratch
.ReturnArgumentsOffset
+ sizeof(BL_RETURN_ARGUMENTS
);
999 return (PBOOT_APPLICATION_PARAMETER_BLOCK
)&EfiInitScratch
;
1005 * The EfiEntry routine implements the UEFI entrypoint for the application.
1007 * @param ImageHandle
1008 * UEFI Image Handle for the current loaded application.
1010 * @param SystemTable
1011 * Pointer to the UEFI System Table.
1013 * @return EFI_SUCCESS if the image was loaded correctly, relevant error code
1020 _In_ EFI_HANDLE ImageHandle
,
1021 _In_ EFI_SYSTEM_TABLE
*SystemTable
1025 PBOOT_APPLICATION_PARAMETER_BLOCK BootParameters
;
1026 extern EFI_SYSTEM_TABLE
*g_SystemTable
;
1028 /* Temporary debugging string */
1029 g_SystemTable
= SystemTable
;
1031 /* Convert EFI parameters to Windows Boot Application parameters */
1032 BootParameters
= EfiInitCreateInputParametersEx(ImageHandle
, SystemTable
);
1033 if (BootParameters
!= NULL
)
1035 /* Conversion was good -- call the Boot Manager Entrypoint */
1036 Status
= BmMain(BootParameters
);
1040 /* Conversion failed, bail out */
1041 EarlyPrint(L
"EFI Input Conversion failed\n");
1042 Status
= STATUS_INVALID_PARAMETER
;
1045 /* Convert the NT status code to an EFI code */
1046 return EfiGetEfiStatusCode(Status
);