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
)) return Status
;
258 /* Increase the size of the data, consume buffer space */
259 DataSize
+= BytesAppended
;
260 MaximumLength
-= BytesAppended
;
262 /* Move to the next path string */
263 PathString
= (PWCHAR
)((ULONG_PTR
)PathString
+ BytesAppended
);
266 /* Move to the next path node */
267 FilePath
= (FILEPATH_DEVICE_PATH
*)NextDevicePathNode(FilePath
);
270 /* Check if we still have space for a NULL-terminator */
271 if (MaximumLength
< sizeof(UNICODE_NULL
))
273 Status
= STATUS_INVALID_PARAMETER
;
277 /* We do -- NULL-terminate the string */
278 *PathString
= UNICODE_NULL
;
279 DataSize
+= sizeof(UNICODE_NULL
);
281 /* Check if all of this has amounted to a single NULL-char */
282 if (PathString
== StringEntry
->String
)
284 /* Then this option is empty */
285 Option
->Empty
= TRUE
;
288 /* Set the final size of the option */
289 Option
->DataSize
= DataSize
;
292 return STATUS_SUCCESS
;
296 * @name EfiInitpGetDeviceNode
298 * The EfiInitpGetDeviceNode routine
301 * UEFI Image Handle for the current loaded application.
306 EFI_DEVICE_PATH_PROTOCOL
*
307 EfiInitpGetDeviceNode (
308 _In_ EFI_DEVICE_PATH_PROTOCOL
*DevicePath
311 EFI_DEVICE_PATH_PROTOCOL
* NextPath
;
313 /* Check if we hit the end terminator */
314 if (IsDevicePathEndType(DevicePath
))
319 /* Loop each device path, until we get to the end or to a file path device node */
320 for ((NextPath
= NextDevicePathNode(DevicePath
));
321 !(IsDevicePathEndType(NextPath
)) && ((NextPath
->Type
!= MEDIA_DEVICE_PATH
) &&
322 (NextPath
->SubType
!= MEDIA_FILEPATH_DP
));
323 (NextPath
= NextDevicePathNode(NextPath
)))
325 /* Keep iterating down */
326 DevicePath
= NextPath
;
329 /* Return the path found */
334 * @name EfiInitTranslateDevicePath
336 * The EfiInitTranslateDevicePath routine
339 * UEFI Image Handle for the current loaded application.
342 * Pointer to the UEFI System Table.
348 EfiInitTranslateDevicePath(
349 _In_ EFI_DEVICE_PATH_PROTOCOL
*DevicePath
,
350 _In_ PBL_DEVICE_DESCRIPTOR DeviceEntry
354 EFI_DEVICE_PATH_PROTOCOL
* DeviceNode
;
355 MEMMAP_DEVICE_PATH
* MemDevicePath
;
356 ACPI_HID_DEVICE_PATH
*AcpiPath
;
357 HARDDRIVE_DEVICE_PATH
*DiskPath
;
360 Status
= STATUS_UNSUCCESSFUL
;
363 DeviceEntry
->Size
= sizeof(*DeviceEntry
);
365 /* Check if we are booting from a RAM Disk */
366 if ((DevicePath
->Type
== HARDWARE_DEVICE_PATH
) &&
367 (DevicePath
->SubType
== HW_MEMMAP_DP
))
369 /* Get the EFI data structure matching this */
370 MemDevicePath
= (MEMMAP_DEVICE_PATH
*)DevicePath
;
372 /* Set the boot library specific device types */
373 DeviceEntry
->DeviceType
= LocalDevice
;
374 DeviceEntry
->Local
.Type
= RamDiskDevice
;
376 /* Extract the base, size, and offset */
377 DeviceEntry
->Local
.RamDisk
.ImageBase
.QuadPart
= MemDevicePath
->StartingAddress
;
378 DeviceEntry
->Local
.RamDisk
.ImageSize
.QuadPart
= MemDevicePath
->EndingAddress
-
379 MemDevicePath
->StartingAddress
;
380 DeviceEntry
->Local
.RamDisk
.ImageOffset
= 0;
381 return STATUS_SUCCESS
;
384 /* Otherwise, check what kind of device node this is */
385 DeviceNode
= EfiInitpGetDeviceNode(DevicePath
);
386 switch (DeviceNode
->Type
)
389 case ACPI_DEVICE_PATH
:
391 /* We only support floppy drives */
392 AcpiPath
= (ACPI_HID_DEVICE_PATH
*)DeviceNode
;
393 if ((AcpiPath
->HID
!= EISA_PNP_ID(0x604)) &&
394 (AcpiPath
->HID
!= EISA_PNP_ID(0x700)))
399 /* Set the boot library specific device types */
400 DeviceEntry
->DeviceType
= LocalDevice
;
401 DeviceEntry
->Local
.Type
= FloppyDevice
;
403 /* The ACPI UID is the drive number */
404 DeviceEntry
->Local
.FloppyDisk
.DriveNumber
= AcpiPath
->UID
;
405 return STATUS_SUCCESS
;
407 /* Network, ATAPI, SCSI, USB */
408 case MESSAGING_DEVICE_PATH
:
410 /* Check if it's network */
411 if ((DeviceNode
->SubType
== MSG_MAC_ADDR_DP
) ||
412 (DeviceNode
->SubType
== MSG_IPv4_DP
))
414 /* Set the boot library specific device types */
415 DeviceEntry
->DeviceType
= UdpDevice
;
416 DeviceEntry
->Remote
.Unknown
= 256;
417 return STATUS_SUCCESS
;
420 /* Other types should come in as MEDIA_DEVICE_PATH -- Windows assumes this is a floppy */
421 DeviceEntry
->DeviceType
= LocalDevice
;
422 DeviceEntry
->Local
.Type
= FloppyDevice
;
423 DeviceEntry
->Local
.FloppyDisk
.DriveNumber
= 0;
424 return STATUS_SUCCESS
;
427 case MEDIA_DEVICE_PATH
:
429 /* Extract the disk path and check if it's a physical disk */
430 DiskPath
= (HARDDRIVE_DEVICE_PATH
*)DeviceNode
;
431 if (DeviceNode
->SubType
== MEDIA_HARDDRIVE_DP
)
433 /* Check if this is an MBR partition */
434 if (DiskPath
->SignatureType
== SIGNATURE_TYPE_MBR
)
436 /* Set that this is a local partition */
437 DeviceEntry
->DeviceType
= PartitionDevice
;
438 DeviceEntry
->Partition
.Disk
.Type
= LocalDevice
;
440 DeviceEntry
->Partition
.Disk
.HardDisk
.PartitionType
= MbrPartition
;
441 DeviceEntry
->Partition
.Disk
.HardDisk
.Mbr
.PartitionSignature
=
442 *(PULONG
)&DiskPath
->Signature
[0];
443 DeviceEntry
->Partition
.Mbr
.PartitionNumber
= DiskPath
->PartitionNumber
;
444 return STATUS_SUCCESS
;
447 /* Check if it's a GPT partition */
448 if (DiskPath
->SignatureType
== SIGNATURE_TYPE_GUID
)
450 /* Set that this is a local disk */
451 DeviceEntry
->DeviceType
= HardDiskDevice
;
452 DeviceEntry
->Partition
.Disk
.Type
= LocalDevice
;
454 /* Set GPT partition ID */
455 DeviceEntry
->Partition
.Disk
.HardDisk
.PartitionType
= GptPartition
;
457 /* Copy the signature GUID */
458 RtlCopyMemory(&DeviceEntry
->Partition
.Gpt
.PartitionGuid
,
462 DeviceEntry
->Flags
|= 4u;
463 return STATUS_SUCCESS
;
466 /* Othertwise, raw boot is not supported */
467 DeviceEntry
->DeviceType
= HardDiskDevice
;
468 DeviceEntry
->Partition
.Disk
.HardDisk
.PartitionType
= RawPartition
;
469 DeviceEntry
->Partition
.Disk
.HardDisk
.Raw
.DiskNumber
= 0;
471 else if (DeviceNode
->SubType
== MEDIA_CDROM_DP
)
473 /* Set the right type for a CDROM */
474 DeviceEntry
->DeviceType
= LocalDevice
;
475 DeviceEntry
->Local
.Type
= CdRomDevice
;
477 /* Set the drive number to zero */
478 DeviceEntry
->Local
.FloppyDisk
.DriveNumber
= 0;
479 return STATUS_SUCCESS
;
482 /* Fail anything else */
487 /* Return here only on failure */
492 * @name EfiInitpConvertEfiDevicePath
494 * The EfiInitpConvertEfiDevicePath routine
497 * UEFI Image Handle for the current loaded application.
500 * Pointer to the UEFI System Table.
503 * Pointer to the UEFI System Table.
505 * @param MaximumLength
506 * Pointer to the UEFI System Table.
512 EfiInitpConvertEfiDevicePath (
513 _In_ EFI_DEVICE_PATH_PROTOCOL
*DevicePath
,
514 _In_ ULONG DeviceType
,
515 _In_ PBL_BCD_OPTION Option
,
516 _In_ ULONG MaximumLength
519 PBCDE_DEVICE DeviceEntry
;
522 /* Make sure we have enough space for the option */
523 if (MaximumLength
< sizeof(*Option
))
525 Status
= STATUS_INVALID_PARAMETER
;
529 /* Zero out the option */
530 RtlZeroMemory(Option
, sizeof(*Option
));
532 /* Make sure we have enough space for the device entry */
533 if ((MaximumLength
- sizeof(*Option
)) < (ULONG
)FIELD_OFFSET(BCDE_DEVICE
, Device
))
535 Status
= STATUS_INVALID_PARAMETER
;
540 DeviceEntry
= (PBCDE_DEVICE
)(Option
+ 1);
541 Status
= EfiInitTranslateDevicePath(DevicePath
, &DeviceEntry
->Device
);
542 if (!NT_SUCCESS(Status
))
547 /* Fill out the rest of the option structure */
548 Option
->DataOffset
= sizeof(*Option
);
549 Option
->Type
= DeviceType
;
550 Option
->DataSize
= FIELD_OFFSET(BCDE_DEVICE
, Device
) +
551 DeviceEntry
->Device
.Size
;
552 Status
= STATUS_SUCCESS
;
559 * @name EfiInitpCreateApplicationEntry
561 * The EfiInitpCreateApplicationEntry routine
564 * UEFI Image Handle for the current loaded application.
567 * Pointer to the UEFI System Table.
569 * @param MaximumLength
570 * Pointer to the UEFI System Table.
573 * Pointer to the UEFI System Table.
576 * Pointer to the UEFI System Table.
579 * Pointer to the UEFI System Table.
581 * @param LoadOptionsSize
582 * Pointer to the UEFI System Table.
585 * Pointer to the UEFI System Table.
587 * @param ResultLength
588 * Pointer to the UEFI System Table.
590 * @param AppEntryDevice
591 * Pointer to the UEFI System Table.
597 EfiInitpCreateApplicationEntry (
598 __in EFI_SYSTEM_TABLE
*SystemTable
,
599 __in PBL_APPLICATION_ENTRY Entry
,
600 __in ULONG MaximumLength
,
601 __in EFI_DEVICE_PATH
*DevicePath
,
602 __in EFI_DEVICE_PATH
*FilePath
,
603 __in PWCHAR LoadOptions
,
604 __in ULONG LoadOptionsSize
,
606 __out PULONG ResultLength
,
607 __out PBL_DEVICE_DESCRIPTOR
*AppEntryDevice
610 PBL_WINDOWS_LOAD_OPTIONS WindowsOptions
;
611 PWCHAR ObjectString
, CommandLine
;
612 PBL_BCD_OPTION Option
, PreviousOption
;
613 ULONG HeaderSize
, TotalOptionSize
, Size
, CommandLineSize
, RemainingSize
;
615 UNICODE_STRING GuidString
;
617 PBCDE_DEVICE BcdDevice
;
618 BOOLEAN HaveBinaryOptions
, HaveGuid
;
619 PBL_FILE_PATH_DESCRIPTOR OsPath
;
620 EFI_DEVICE_PATH
*OsDevicePath
;
622 /* Initialize everything */
624 *AppEntryDevice
= NULL
;
627 /* Check if the load options are in binary Windows format */
628 WindowsOptions
= (PBL_WINDOWS_LOAD_OPTIONS
)LoadOptions
;
629 if ((WindowsOptions
!= NULL
) &&
630 (LoadOptionsSize
>= sizeof(BL_WINDOWS_LOAD_OPTIONS
)) &&
631 (WindowsOptions
->Length
>= sizeof(BL_WINDOWS_LOAD_OPTIONS
)) &&
632 !(strncmp(WindowsOptions
->Signature
, "WINDOWS", 7)))
634 /* They are, so firmware must have loaded us -- extract arguments */
635 CommandLine
= WindowsOptions
->LoadOptions
;
636 CommandLineSize
= LoadOptionsSize
- FIELD_OFFSET(BL_WINDOWS_LOAD_OPTIONS
,
639 /* Remember that we used binary options */
640 HaveBinaryOptions
= TRUE
;
644 /* Nope -- so treat them as raw command-line options */
645 CommandLine
= LoadOptions
;
646 CommandLineSize
= LoadOptionsSize
;
648 /* No binary options */
649 HaveBinaryOptions
= FALSE
;
652 /* EFI uses UTF-16LE, like NT, so convert to characters */
653 CommandLineSize
/= sizeof(WCHAR
);
654 if (CommandLineSize
!= 0)
656 /* And check if the options are not NULL-terminated */
657 if (wcsnlen(CommandLine
, CommandLineSize
) == CommandLineSize
)
659 /* NULL-terminate them */
660 CommandLine
[CommandLineSize
- 1] = UNICODE_NULL
;
664 /* Begin by making sure we at least have space for the app entry header */
665 RemainingSize
= MaximumLength
;
666 if (RemainingSize
< sizeof(BL_APPLICATION_ENTRY
))
668 EarlyPrint(L
"Remaining size too small!\n");
669 Status
= STATUS_INVALID_PARAMETER
;
673 /* On exit, return that we've at least consumed this much */
674 HeaderSize
= FIELD_OFFSET(BL_APPLICATION_ENTRY
, BcdData
);
676 /* Zero out the header, and write down the signature */
677 RtlZeroMemory(Entry
, sizeof(BL_APPLICATION_ENTRY
));
678 RtlCopyMemory(Entry
->Signature
, BL_APP_ENTRY_SIGNATURE
, 7);
680 /* Check if a BCD object was passed on the command-line */
681 ObjectString
= wcsstr(CommandLine
, L
"BCDOBJECT=");
682 if (ObjectString
!= NULL
)
684 /* Convert the BCD object to a GUID */
685 RtlInitUnicodeString(&GuidString
, ObjectString
+ 10);
686 RtlGUIDFromString(&GuidString
, &ObjectGuid
);
688 /* Store it in the application entry */
689 Entry
->Guid
= ObjectGuid
;
691 /* Remember one was passed */
696 /* Remember that no identifier was passed */
697 Entry
->Flags
|= BL_APPLICATION_ENTRY_FLAG_NO_GUID
;
701 /* At this point, the header is consumed, and we must now handle BCD options */
702 RemainingSize
-= FIELD_OFFSET(BL_APPLICATION_ENTRY
, BcdData
);
704 /* Convert the device path into a BCD option */
705 Status
= EfiInitpConvertEfiDevicePath(DevicePath
,
706 BcdLibraryDevice_ApplicationDevice
,
709 if (!NT_SUCCESS(Status
))
711 /* We failed, so mark the option as such and return an empty one */
712 EarlyPrint(L
"Failed to convert device path: %lx\n", Status
);
713 Entry
->BcdData
.Empty
= TRUE
;
714 TotalOptionSize
= sizeof(BL_BCD_OPTION
);
718 /* Extract the device descriptor and return it */
719 BcdDevice
= (PVOID
)((ULONG_PTR
)&Entry
->BcdData
+ Entry
->BcdData
.DataOffset
);
720 *AppEntryDevice
= &BcdDevice
->Device
;
722 /* Calculate how big this option was and consume that from the buffer */
723 TotalOptionSize
= BlGetBootOptionSize(&Entry
->BcdData
);
724 RemainingSize
-= TotalOptionSize
;
726 /* Calculate where the next option should go */
727 Option
= (PVOID
)((ULONG_PTR
)&Entry
->BcdData
+ TotalOptionSize
);
729 /* Check if we're PXE booting or not */
730 if ((*AppEntryDevice
)->DeviceType
== UdpDevice
)
733 Status
= STATUS_NOT_IMPLEMENTED
;
734 EarlyPrint(L
"UDP Boot not supported!\n");
738 /* Convert the local file path into a BCD option */
739 Status
= EfiInitpConvertEfiFilePath(FilePath
,
740 BcdLibraryString_ApplicationPath
,
745 /* Bail out on failure */
746 if (!NT_SUCCESS(Status
))
748 EarlyPrint(L
"Failed to convert file path: %lx\n", 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
))
787 EarlyPrint(L
"Failed to convert OS device path: %lx\n", Status
);
791 /* Update the offset of the previous option */
792 PreviousOption
->NextEntryOffset
= (ULONG_PTR
)Option
- (ULONG_PTR
)&Entry
->BcdData
;
794 /* Now compute the size of the next option, and add to the rolling sum */
795 Size
= BlGetBootOptionSize(Option
);
796 TotalOptionSize
+= Size
;
798 /* Remember the previous option so we can update its next offset */
799 PreviousOption
= Option
;
801 /* Consume the option from the buffer */
802 RemainingSize
-= Size
;
804 /* Calculate where the next option should go */
805 Option
= (PVOID
)((ULONG_PTR
)Option
+ Size
);
807 /* Convert the path oprtion */
808 Status
= EfiInitpConvertEfiFilePath(OsDevicePath
,
809 BcdOSLoaderString_SystemRoot
,
812 if (!NT_SUCCESS(Status
))
814 EarlyPrint(L
"Failed to convert OS file path: %lx\n", Status
);
818 /* Update the offset of the previous option */
819 PreviousOption
->NextEntryOffset
= (ULONG_PTR
)Option
- (ULONG_PTR
)&Entry
->BcdData
;
821 /* Now compute the size of the next option, and add to the rolling sum */
822 Size
= BlGetBootOptionSize(Option
);
823 TotalOptionSize
+= Size
;
825 /* Remember the previous option so we can update its next offset */
826 PreviousOption
= Option
;
828 /* Consume the option from the buffer */
829 RemainingSize
-= Size
;
831 /* Calculate where the next option should go */
832 Option
= (PVOID
)((ULONG_PTR
)Option
+ Size
);
836 /* Now convert everything else */
837 AhCreateLoadOptionsList(CommandLine
,
845 /* Return the final size */
846 *ResultLength
= HeaderSize
+ TotalOptionSize
;
850 * @name EfiInitCreateInputParametersEx
852 * The EfiInitCreateInputParametersEx routine converts UEFI entrypoint
853 * parameters to the ones expected by Windows Boot Applications
856 * UEFI Image Handle for the current loaded application.
859 * Pointer to the UEFI System Table.
861 * @return A PBOOT_APPLICATION_PARAMETER_BLOCK structure containing the data
862 * from UEFI, translated to the Boot Library-compatible format.
865 PBOOT_APPLICATION_PARAMETER_BLOCK
866 EfiInitCreateInputParametersEx (
867 _In_ EFI_HANDLE ImageHandle
,
868 _In_ EFI_SYSTEM_TABLE
*SystemTable
871 EFI_BOOT_SERVICES
* BootServices
;
872 EFI_LOADED_IMAGE_PROTOCOL
*LoadedImage
;
873 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
874 PBL_FIRMWARE_DESCRIPTOR FirmwareData
;
875 PBL_RETURN_ARGUMENTS ReturnArguments
;
876 ULONG FirmwareOffset
, ConsumedSize
;
877 PBL_DEVICE_DESCRIPTOR AppDevice
;
880 /* Initialize the header with the signature and version */
881 EfiInitScratch
.Signature
[0] = BOOT_APPLICATION_SIGNATURE_1
;
882 EfiInitScratch
.Signature
[1] = BOOT_APPLICATION_SIGNATURE_2
;
883 EfiInitScratch
.Version
= BOOT_APPLICATION_VERSION
;
885 /* Set the image type to x86 */
886 EfiInitScratch
.ImageType
= EFI_IMAGE_MACHINE_IA32
;
888 /* Set the translation type to physical */
889 EfiInitScratch
.MemoryTranslationType
= BOOT_MEMORY_TRANSLATION_TYPE_PHYSICAL
;
891 /* Indicate that the data was converted from EFI */
892 BlpApplicationFlags
|= BL_APPLICATION_FLAG_CONVERTED_FROM_EFI
;
894 /* Grab the loaded image protocol, which has our base and size */
895 BootServices
= SystemTable
->BootServices
;
896 Status
= BootServices
->HandleProtocol(ImageHandle
,
897 &EfiLoadedImageProtocol
,
898 (VOID
**)&LoadedImage
);
899 if (Status
!= EFI_SUCCESS
)
901 EarlyPrint(L
"Loaded image failed: %lx\n", Status
);
905 /* Capture it in the boot application parameters */
906 EfiInitScratch
.ImageBase
= (ULONG_PTR
)LoadedImage
->ImageBase
;
907 EfiInitScratch
.ImageSize
= (ULONG
)LoadedImage
->ImageSize
;
909 /* Now grab our device path protocol, so we can convert the path later on */
910 Status
= BootServices
->HandleProtocol(LoadedImage
->DeviceHandle
,
911 &EfiDevicePathProtocol
,
912 (VOID
**)&DevicePath
);
913 if (Status
!= EFI_SUCCESS
)
915 EarlyPrint(L
"Device Path failed: %lx\n", Status
);
919 /* The built-in boot memory data comes right after our block */
920 EfiInitScratch
.MemoryDataOffset
=
921 FIELD_OFFSET(BOOT_APPLICATION_PARAMETER_BLOCK_SCRATCH
, BootMemoryData
);
923 /* Build the boot memory data structure, with 1 descriptor */
924 EfiInitScratch
.BootMemoryData
.Version
= BL_MEMORY_DATA_VERSION
;
925 EfiInitScratch
.BootMemoryData
.MdListOffset
=
926 FIELD_OFFSET(BOOT_APPLICATION_PARAMETER_BLOCK_SCRATCH
, MemEntry
) -
927 EfiInitScratch
.MemoryDataOffset
;
928 EfiInitScratch
.BootMemoryData
.DescriptorSize
= sizeof(BL_MEMORY_DESCRIPTOR
);
929 EfiInitScratch
.BootMemoryData
.DescriptorCount
= 1;
930 EfiInitScratch
.BootMemoryData
.DescriptorOffset
= FIELD_OFFSET(BL_MEMORY_DESCRIPTOR
, BasePage
);
932 /* Build the memory entry descriptor for this image itself */
933 EfiInitScratch
.MemEntry
.Flags
= BlMemoryWriteBack
;
934 EfiInitScratch
.MemEntry
.Type
= BlLoaderMemory
;
935 EfiInitScratch
.MemEntry
.BasePage
= EfiInitScratch
.ImageBase
>> PAGE_SHIFT
;
936 EfiInitScratch
.MemEntry
.PageCount
= ALIGN_UP_BY(EfiInitScratch
.ImageSize
, PAGE_SIZE
) >> PAGE_SHIFT
;
938 /* The built-in application entry comes right after the memory descriptor*/
939 EfiInitScratch
.AppEntryOffset
=
940 FIELD_OFFSET(BOOT_APPLICATION_PARAMETER_BLOCK_SCRATCH
, AppEntry
);
942 /* Go and build it */
943 EfiInitpCreateApplicationEntry(SystemTable
,
944 (PBL_APPLICATION_ENTRY
)&EfiInitScratch
.AppEntry
,
945 sizeof(EfiInitScratch
.AppEntry
),
947 LoadedImage
->FilePath
,
948 LoadedImage
->LoadOptions
,
949 LoadedImage
->LoadOptionsSize
,
950 EfiInitScratch
.MemEntry
.PageCount
,
954 /* Boot device information comes right after the application entry */
955 EfiInitScratch
.BootDeviceOffset
= ConsumedSize
+ EfiInitScratch
.AppEntryOffset
;
957 /* Check if we have a boot device */
958 if (AppDevice
!= NULL
)
960 /* We do -- copy it */
961 RtlCopyMemory(EfiInitScratch
.AppEntry
+ ConsumedSize
,
965 /* Firmware data follows right after the boot device entry */
966 FirmwareOffset
= AppDevice
->Size
+ EfiInitScratch
.BootDeviceOffset
;
970 /* We do not, so zero out the space where a full boot device structure would fit */
971 RtlZeroMemory(EfiInitScratch
.AppEntry
+ ConsumedSize
,
972 sizeof(BL_DEVICE_DESCRIPTOR
));
974 /* And start the firmware data past that */
975 FirmwareOffset
= EfiInitScratch
.BootDeviceOffset
+ sizeof(BL_DEVICE_DESCRIPTOR
);
978 /* Set the computed firmware data offset */
979 EfiInitScratch
.FirmwareParametersOffset
= FirmwareOffset
;
981 /* Fill out the firmware data that's there */
982 FirmwareData
= (PVOID
)((ULONG_PTR
)&EfiInitScratch
+ EfiInitScratch
.FirmwareParametersOffset
);
983 FirmwareData
->Version
= BL_FIRMWARE_DESCRIPTOR_VERSION
;
984 FirmwareData
->ImageHandle
= ImageHandle
;
985 FirmwareData
->SystemTable
= SystemTable
;
987 /* Finally, set the return argument offset */
988 EfiInitScratch
.ReturnArgumentsOffset
= FirmwareOffset
+ sizeof(BL_FIRMWARE_DESCRIPTOR
);
990 /* And fill out the return argument data */
991 ReturnArguments
= (PVOID
)((ULONG_PTR
)&EfiInitScratch
+ EfiInitScratch
.ReturnArgumentsOffset
);
992 ReturnArguments
->Version
= BL_RETURN_ARGUMENTS_VERSION
;
994 /* We're done, compute the final size and return the block */
995 EfiInitScratch
.Size
= EfiInitScratch
.ReturnArgumentsOffset
+ sizeof(BL_RETURN_ARGUMENTS
);
996 return (PBOOT_APPLICATION_PARAMETER_BLOCK
)&EfiInitScratch
;
1002 * The EfiEntry routine implements the UEFI entrypoint for the application.
1004 * @param ImageHandle
1005 * UEFI Image Handle for the current loaded application.
1007 * @param SystemTable
1008 * Pointer to the UEFI System Table.
1010 * @return EFI_SUCCESS if the image was loaded correctly, relevant error code
1017 _In_ EFI_HANDLE ImageHandle
,
1018 _In_ EFI_SYSTEM_TABLE
*SystemTable
1022 PBOOT_APPLICATION_PARAMETER_BLOCK BootParameters
;
1023 extern EFI_SYSTEM_TABLE
*g_SystemTable
;
1025 /* Temporary debugging string */
1026 g_SystemTable
= SystemTable
;
1028 /* Convert EFI parameters to Windows Boot Application parameters */
1029 BootParameters
= EfiInitCreateInputParametersEx(ImageHandle
, SystemTable
);
1030 if (BootParameters
!= NULL
)
1032 /* Conversion was good -- call the Boot Manager Entrypoint */
1033 Status
= BmMain(BootParameters
);
1037 /* Conversion failed, bail out */
1038 EarlyPrint(L
"EFI Input Conversion failed\n");
1039 Status
= STATUS_INVALID_PARAMETER
;
1042 /* Convert the NT status code to an EFI code */
1043 return EfiGetEfiStatusCode(Status
);