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
< 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
->Failed
= 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 Status
= STATUS_INVALID_PARAMETER
;
675 /* On exit, return that we've at least consumed this much */
676 HeaderSize
= FIELD_OFFSET(BL_APPLICATION_ENTRY
, BcdData
);
678 /* Zero out the header, and write down the signature */
679 RtlZeroMemory(Entry
, sizeof(BL_APPLICATION_ENTRY
));
680 RtlCopyMemory(Entry
->Signature
, BL_APP_ENTRY_SIGNATURE
, 7);
682 /* Check if a BCD object was passed on the command-line */
683 ObjectString
= wcsstr(CommandLine
, L
"BCDOBJECT=");
684 if (ObjectString
!= NULL
)
686 /* Convert the BCD object to a GUID */
687 RtlInitUnicodeString(&GuidString
, ObjectString
+ 10);
688 RtlGUIDFromString(&GuidString
, &ObjectGuid
);
690 /* Store it in the application entry */
691 Entry
->Guid
= ObjectGuid
;
693 /* Remember one was passed */
698 /* Remember that no identifier was passed */
699 Entry
->Flags
|= BL_APPLICATION_ENTRY_FLAG_NO_GUID
;
703 /* At this point, the header is consumed, and we must now handle BCD options */
704 RemainingSize
-= FIELD_OFFSET(BL_APPLICATION_ENTRY
, BcdData
);
706 /* Convert the device path into a BCD option */
707 Status
= EfiInitpConvertEfiDevicePath(DevicePath
,
708 BcdLibraryDevice_ApplicationDevice
,
711 if (!NT_SUCCESS(Status
))
713 /* We failed, so mark the option as such and return an empty one */
714 Entry
->BcdData
.Failed
= TRUE
;
715 TotalOptionSize
= sizeof(BL_BCD_OPTION
);
719 /* Extract the device descriptor and return it */
720 BcdDevice
= (PVOID
)((ULONG_PTR
)&Entry
->BcdData
+ Entry
->BcdData
.DataOffset
);
721 *AppEntryDevice
= &BcdDevice
->Device
;
723 /* Calculate how big this option was and consume that from the buffer */
724 TotalOptionSize
= BlGetBootOptionSize(&Entry
->BcdData
);
725 RemainingSize
-= TotalOptionSize
;
727 /* Calculate where the next option should go */
728 Option
= (PVOID
)((ULONG_PTR
)&Entry
->BcdData
+ TotalOptionSize
);
730 /* Check if we're PXE booting or not */
731 if ((*AppEntryDevice
)->DeviceType
== UdpDevice
)
734 Status
= STATUS_NOT_IMPLEMENTED
;
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
))
751 /* The next option is right after this one */
752 Entry
->BcdData
.NextEntryOffset
= TotalOptionSize
;
754 /* Now compute the size of the next option, and add to the rolling sum */
755 Size
= BlGetBootOptionSize(Option
);
756 TotalOptionSize
+= Size
;
758 /* Remember the previous option so we can update its next offset */
759 PreviousOption
= Option
;
761 /* Consume the option from the buffer */
762 RemainingSize
-= Size
;
764 /* Calculate where the next option should go */
765 Option
= (PVOID
)((ULONG_PTR
)Option
+ Size
);
767 /* Check if we were using binary options without a BCD GUID */
768 if ((HaveBinaryOptions
) && !(HaveGuid
))
770 /* Then this means we have to convert the OS paths to BCD too */
771 WindowsOptions
= (PBL_WINDOWS_LOAD_OPTIONS
)LoadOptions
;
772 OsPath
= (PVOID
)((ULONG_PTR
)WindowsOptions
+ WindowsOptions
->OsPathOffset
);
774 /* IS the OS path in EFI format? */
775 if ((OsPath
->Length
> (ULONG
)FIELD_OFFSET(BL_FILE_PATH_DESCRIPTOR
, Path
)) &&
776 (OsPath
->PathType
== EfiPath
))
778 /* Convert the device portion */
779 OsDevicePath
= (EFI_DEVICE_PATH
*)OsPath
->Path
;
780 Status
= EfiInitpConvertEfiDevicePath(OsDevicePath
,
781 BcdOSLoaderDevice_OSDevice
,
784 if (!NT_SUCCESS(Status
))
789 /* Update the offset of the previous option */
790 PreviousOption
->NextEntryOffset
= (ULONG_PTR
)Option
- (ULONG_PTR
)&Entry
->BcdData
;
792 /* Now compute the size of the next option, and add to the rolling sum */
793 Size
= BlGetBootOptionSize(Option
);
794 TotalOptionSize
+= Size
;
796 /* Remember the previous option so we can update its next offset */
797 PreviousOption
= Option
;
799 /* Consume the option from the buffer */
800 RemainingSize
-= Size
;
802 /* Calculate where the next option should go */
803 Option
= (PVOID
)((ULONG_PTR
)Option
+ Size
);
805 /* Convert the path oprtion */
806 Status
= EfiInitpConvertEfiFilePath(OsDevicePath
,
807 BcdOSLoaderString_SystemRoot
,
810 if (!NT_SUCCESS(Status
))
815 /* Update the offset of the previous option */
816 PreviousOption
->NextEntryOffset
= (ULONG_PTR
)Option
- (ULONG_PTR
)&Entry
->BcdData
;
818 /* Now compute the size of the next option, and add to the rolling sum */
819 Size
= BlGetBootOptionSize(Option
);
820 TotalOptionSize
+= Size
;
822 /* Remember the previous option so we can update its next offset */
823 PreviousOption
= Option
;
825 /* Consume the option from the buffer */
826 RemainingSize
-= Size
;
828 /* Calculate where the next option should go */
829 Option
= (PVOID
)((ULONG_PTR
)Option
+ Size
);
833 /* Now convert everything else */
834 AhCreateLoadOptionsList(CommandLine
,
842 /* Return the final size */
843 *ResultLength
= HeaderSize
+ TotalOptionSize
;
847 * @name EfiInitCreateInputParametersEx
849 * The EfiInitCreateInputParametersEx routine converts UEFI entrypoint
850 * parameters to the ones expected by Windows Boot Applications
853 * UEFI Image Handle for the current loaded application.
856 * Pointer to the UEFI System Table.
858 * @return A PBOOT_APPLICATION_PARAMETER_BLOCK structure containing the data
859 * from UEFI, translated to the Boot Library-compatible format.
862 PBOOT_APPLICATION_PARAMETER_BLOCK
863 EfiInitCreateInputParametersEx (
864 _In_ EFI_HANDLE ImageHandle
,
865 _In_ EFI_SYSTEM_TABLE
*SystemTable
868 EFI_BOOT_SERVICES
* BootServices
;
869 EFI_LOADED_IMAGE_PROTOCOL
*LoadedImage
;
870 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
871 PBL_FIRMWARE_DESCRIPTOR FirmwareData
;
872 PBL_RETURN_ARGUMENTS ReturnArguments
;
873 ULONG FirmwareOffset
, ConsumedSize
;
874 PBL_DEVICE_DESCRIPTOR AppDevice
;
877 /* Initialize the header with the signature and version */
878 EfiInitScratch
.Signature
[0] = BOOT_APPLICATION_SIGNATURE_1
;
879 EfiInitScratch
.Signature
[1] = BOOT_APPLICATION_SIGNATURE_2
;
880 EfiInitScratch
.Version
= BOOT_APPLICATION_VERSION
;
882 /* Set the image type to x86 */
883 EfiInitScratch
.ImageType
= EFI_IMAGE_MACHINE_IA32
;
885 /* Set the translation type to physical */
886 EfiInitScratch
.MemoryTranslationType
= BOOT_MEMORY_TRANSLATION_TYPE_PHYSICAL
;
888 /* Indicate that the data was converted from EFI */
889 BlpApplicationFlags
|= BL_APPLICATION_FLAG_CONVERTED_FROM_EFI
;
891 /* Grab the loaded image protocol, which has our base and size */
892 BootServices
= SystemTable
->BootServices
;
893 Status
= BootServices
->HandleProtocol(ImageHandle
,
894 &EfiLoadedImageProtocol
,
895 (VOID
**)&LoadedImage
);
896 if (Status
!= EFI_SUCCESS
)
898 SystemTable
->ConOut
->OutputString(SystemTable
->ConsoleOutHandle
,
899 L
"Loaded image failed\n");
903 /* Capture it in the boot application parameters */
904 EfiInitScratch
.ImageBase
= (ULONG_PTR
)LoadedImage
->ImageBase
;
905 EfiInitScratch
.ImageSize
= (ULONG
)LoadedImage
->ImageSize
;
907 /* Now grab our device path protocol, so we can convert the path later on */
908 Status
= BootServices
->HandleProtocol(ImageHandle
,
909 &EfiDevicePathProtocol
,
910 (VOID
**)&DevicePath
);
911 if (Status
!= EFI_SUCCESS
)
913 SystemTable
->ConOut
->OutputString(SystemTable
->ConsoleOutHandle
,
914 L
"Device path failed\n");
918 /* The built-in boot memory data comes right after our block */
919 EfiInitScratch
.MemoryDataOffset
=
920 FIELD_OFFSET(BOOT_APPLICATION_PARAMETER_BLOCK_SCRATCH
, BootMemoryData
);
922 /* Build the boot memory data structure, with 1 descriptor */
923 EfiInitScratch
.BootMemoryData
.Version
= BL_MEMORY_DATA_VERSION
;
924 EfiInitScratch
.BootMemoryData
.MdListOffset
=
925 FIELD_OFFSET(BOOT_APPLICATION_PARAMETER_BLOCK_SCRATCH
, MemEntry
) -
926 EfiInitScratch
.MemoryDataOffset
;
927 EfiInitScratch
.BootMemoryData
.DescriptorSize
= sizeof(BL_MEMORY_DESCRIPTOR
);
928 EfiInitScratch
.BootMemoryData
.DescriptorCount
= 1;
929 EfiInitScratch
.BootMemoryData
.Unknown
= 8;
931 /* Build the memory entry descriptor for this image itself */
932 EfiInitScratch
.MemEntry
.Flags
= 8;
933 EfiInitScratch
.MemEntry
.Type
= BlLoaderMemory
;
934 EfiInitScratch
.MemEntry
.BasePage
= EfiInitScratch
.ImageBase
>> PAGE_SHIFT
;
935 EfiInitScratch
.MemEntry
.PageCount
= ALIGN_UP_BY(EfiInitScratch
.ImageSize
, PAGE_SIZE
) >> PAGE_SHIFT
;
937 /* The built-in application entry comes right after the memory descriptor*/
938 EfiInitScratch
.AppEntryOffset
=
939 FIELD_OFFSET(BOOT_APPLICATION_PARAMETER_BLOCK_SCRATCH
, AppEntry
);
941 /* Go and build it */
942 EfiInitpCreateApplicationEntry(SystemTable
,
943 (PBL_APPLICATION_ENTRY
)&EfiInitScratch
.AppEntry
,
944 sizeof(EfiInitScratch
.AppEntry
),
946 LoadedImage
->FilePath
,
947 LoadedImage
->LoadOptions
,
948 LoadedImage
->LoadOptionsSize
,
949 EfiInitScratch
.MemEntry
.PageCount
,
953 /* Boot device information comes right after the application entry */
954 EfiInitScratch
.BootDeviceOffset
= ConsumedSize
+ EfiInitScratch
.AppEntryOffset
;
956 /* Check if we have a boot device */
957 if (AppDevice
!= NULL
)
959 /* We do -- copy it */
960 RtlCopyMemory(EfiInitScratch
.AppEntry
+ ConsumedSize
,
964 /* Firmware data follows right after the boot device entry */
965 FirmwareOffset
= AppDevice
->Size
+ EfiInitScratch
.BootDeviceOffset
;
969 /* We do not, so zero out the space where a full boot device structure would fit */
970 RtlZeroMemory(EfiInitScratch
.AppEntry
+ ConsumedSize
,
971 sizeof(BL_DEVICE_DESCRIPTOR
));
973 /* And start the firmware data past that */
974 FirmwareOffset
= EfiInitScratch
.BootDeviceOffset
+ sizeof(BL_DEVICE_DESCRIPTOR
);
977 /* Set the computed firmware data offset */
978 EfiInitScratch
.FirmwareParametersOffset
= FirmwareOffset
;
980 /* Fill out the firmware data that's there */
981 FirmwareData
= (PVOID
)((ULONG_PTR
)&EfiInitScratch
+ EfiInitScratch
.FirmwareParametersOffset
);
982 FirmwareData
->Version
= BL_FIRMWARE_DESCRIPTOR_VERSION
;
983 FirmwareData
->ImageHandle
= ImageHandle
;
984 FirmwareData
->SystemTable
= SystemTable
;
986 /* Finally, set the return argument offset */
987 EfiInitScratch
.ReturnArgumentsOffset
= FirmwareOffset
+ sizeof(BL_FIRMWARE_DESCRIPTOR
);
989 /* And fill out the return argument data */
990 ReturnArguments
= (PVOID
)((ULONG_PTR
)&EfiInitScratch
+ EfiInitScratch
.ReturnArgumentsOffset
);
991 ReturnArguments
->Version
= BL_RETURN_ARGUMENTS_VERSION
;
993 /* We're done, compute the final size and return the block */
994 EfiInitScratch
.Size
= EfiInitScratch
.ReturnArgumentsOffset
+ sizeof(BL_RETURN_ARGUMENTS
);
995 return (PBOOT_APPLICATION_PARAMETER_BLOCK
)&EfiInitScratch
;
1001 * The EfiEntry routine implements the UEFI entrypoint for the application.
1003 * @param ImageHandle
1004 * UEFI Image Handle for the current loaded application.
1006 * @param SystemTable
1007 * Pointer to the UEFI System Table.
1009 * @return EFI_SUCCESS if the image was loaded correctly, relevant error code
1015 _In_ EFI_HANDLE ImageHandle
,
1016 _In_ EFI_SYSTEM_TABLE
*SystemTable
1020 PBOOT_APPLICATION_PARAMETER_BLOCK BootParameters
;
1022 /* Temporary debugging string */
1023 SystemTable
->ConOut
->OutputString(SystemTable
->ConsoleOutHandle
, L
"Hello from EFI\n");
1025 /* Convert EFI parameters to Windows Boot Application parameters */
1026 BootParameters
= EfiInitCreateInputParametersEx(ImageHandle
, SystemTable
);
1027 if (BootParameters
!= NULL
)
1029 /* Conversion was good -- call the Boot Manager Entrypoint */
1030 SystemTable
->ConOut
->OutputString(SystemTable
->ConsoleOutHandle
, L
"EFI input OK!\n");
1031 Status
= BmMain(BootParameters
);
1035 /* Conversion failed, bail out */
1036 SystemTable
->ConOut
->OutputString(SystemTable
->ConsoleOutHandle
, L
"EFI input failed\n");
1037 Status
= STATUS_INVALID_PARAMETER
;
1040 /* Convert the NT status code to an EFI code */
1041 return EfiGetEfiStatusCode(Status
);