1 /* 2 * COPYRIGHT: See COPYING.ARM in the top level directory 3 * PROJECT: ReactOS UEFI Boot Manager 4 * FILE: boot/environ/app/bootmgr/efiemu.c 5 * PURPOSE: UEFI Entrypoint for Boot Manager 6 * PROGRAMMER: Alex Ionescu (alex.ionescu@reactos.org) 7 */ 8 9 /* INCLUDES ******************************************************************/ 10 11 #include "bootmgr.h" 12 13 /* DATA STRUCTURES ***********************************************************/ 14 15 typedef struct _BOOT_APPLICATION_PARAMETER_BLOCK_SCRATCH 16 { 17 BOOT_APPLICATION_PARAMETER_BLOCK; 18 BL_MEMORY_DATA BootMemoryData; 19 BL_MEMORY_DESCRIPTOR MemEntry; 20 UCHAR AppEntry[788]; 21 } BOOT_APPLICATION_PARAMETER_BLOCK_SCRATCH; 22 23 /* DATA VARIABLES ************************************************************/ 24 25 BOOT_APPLICATION_PARAMETER_BLOCK_SCRATCH EfiInitScratch; 26 27 /* FUNCTIONS *****************************************************************/ 28 29 /*++ 30 * @name AhCreateLoadOptionsList 31 * 32 * The AhCreateLoadOptionsList routine 33 * 34 * @param CommandLine 35 * UEFI Image Handle for the current loaded application. 36 * 37 * @param BootOptions 38 * Pointer to the UEFI System Table. 39 * 40 * @param MaximumLength 41 * Pointer to the UEFI System Table. 42 * 43 * @param OptionSize 44 * Pointer to the UEFI System Table. 45 * 46 * @param PreviousOption 47 * Pointer to the UEFI System Table. 48 * 49 * @param PreviousOptionSize 50 * Pointer to the UEFI System Table. 51 * 52 * @return None 53 * 54 *--*/ 55 NTSTATUS 56 AhCreateLoadOptionsList ( 57 _In_ PWCHAR CommandLine, 58 _In_ PBL_BCD_OPTION BootOptions, 59 _In_ ULONG MaximumLength, 60 _Out_ PULONG OptionSize, 61 _In_ PBL_BCD_OPTION* PreviousOption, 62 _In_ PULONG PreviousOptionSize 63 ) 64 { 65 return STATUS_NOT_IMPLEMENTED; 66 } 67 68 /*++ 69 * @name EfiInitpAppendPathString 70 * 71 * The EfiInitpAppendPathString routine 72 * 73 * @param DestinationPath 74 * UEFI Image Handle for the current loaded application. 75 * 76 * @param RemainingSize 77 * Pointer to the UEFI System Table. 78 * 79 * @param AppendPath 80 * Pointer to the UEFI System Table. 81 * 82 * @param AppendLength 83 * Pointer to the UEFI System Table. 84 * 85 * @param BytesAppended 86 * Pointer to the UEFI System Table. 87 * 88 * @return None 89 * 90 *--*/ 91 NTSTATUS 92 EfiInitpAppendPathString ( 93 _In_ PWCHAR PathString, 94 _In_ ULONG MaximumLength, 95 _In_ PWCHAR NewPathString, 96 _In_ ULONG NewPathLength, 97 _Out_ PULONG ResultLength 98 ) 99 { 100 NTSTATUS Status; 101 ULONG FinalPathLength; 102 103 /* We deal in Unicode, validate the length */ 104 if (NewPathLength & 1) 105 { 106 return STATUS_INVALID_PARAMETER; 107 } 108 109 /* Is the new element at least a character? */ 110 Status = STATUS_SUCCESS; 111 if (NewPathLength >= sizeof(WCHAR)) 112 { 113 /* Is the last character already a NULL character? */ 114 if (NewPathString[(NewPathLength - sizeof(WCHAR)) / sizeof(WCHAR)] == 115 UNICODE_NULL) 116 { 117 /* Then we won't need to count it */ 118 NewPathLength -= sizeof(UNICODE_NULL); 119 } 120 121 /* Was it more than just a NULL character? */ 122 if (NewPathLength >= sizeof(WCHAR)) 123 { 124 /* Yep -- but does it have a separator? */ 125 if (*NewPathString == OBJ_NAME_PATH_SEPARATOR) 126 { 127 /* Skip it, we'll add our own later */ 128 NewPathString++; 129 NewPathLength -= sizeof(OBJ_NAME_PATH_SEPARATOR); 130 } 131 132 /* Was it more than just a separator? */ 133 if (NewPathLength >= sizeof(WCHAR)) 134 { 135 /* Yep -- but does it end with a separator? */ 136 if (NewPathString[(NewPathLength - sizeof(WCHAR)) / sizeof(WCHAR)] == 137 OBJ_NAME_PATH_SEPARATOR) 138 { 139 /* That's something else we won't need for now */ 140 NewPathLength -= sizeof(OBJ_NAME_PATH_SEPARATOR); 141 } 142 } 143 } 144 } 145 146 /* Check if anything needs to be appended after all */ 147 if (NewPathLength != 0) 148 { 149 /* We will append the length of the new path element, plus a separator */ 150 FinalPathLength = NewPathLength + sizeof(OBJ_NAME_PATH_SEPARATOR); 151 if (MaximumLength >= FinalPathLength) 152 { 153 /* Add a separator to the existing path*/ 154 *PathString = OBJ_NAME_PATH_SEPARATOR; 155 156 /* Followed by the new path element */ 157 RtlCopyMemory(PathString + 1, NewPathString, NewPathLength); 158 159 /* Return the number of bytes appended */ 160 *ResultLength = FinalPathLength; 161 } 162 else 163 { 164 /* There's not enough space to do this */ 165 Status = STATUS_BUFFER_TOO_SMALL; 166 } 167 } 168 else 169 { 170 /* Nothing to append */ 171 *ResultLength = 0; 172 } 173 174 return Status; 175 } 176 177 /*++ 178 * @name EfiInitpConvertEfiDevicePath 179 * 180 * The EfiInitpConvertEfiDevicePath routine 181 * 182 * @param DevicePath 183 * UEFI Image Handle for the current loaded application. 184 * 185 * @param DeviceType 186 * Pointer to the UEFI System Table. 187 * 188 * @param Option 189 * Pointer to the UEFI System Table. 190 * 191 * @param MaximumLength 192 * Pointer to the UEFI System Table. 193 * 194 * @return None 195 * 196 *--*/ 197 NTSTATUS 198 EfiInitpConvertEfiFilePath ( 199 _In_ EFI_DEVICE_PATH_PROTOCOL *DevicePath, 200 _In_ ULONG PathType, 201 _In_ PBL_BCD_OPTION Option, 202 _In_ ULONG MaximumLength 203 ) 204 { 205 ULONG BytesAppended, DataSize, StringLength; 206 PWCHAR StringEntry, PathString; 207 FILEPATH_DEVICE_PATH *FilePath; 208 NTSTATUS Status; 209 210 /* Make sure we have enough space for the option */ 211 if (MaximumLength < sizeof(*Option)) 212 { 213 return STATUS_INVALID_PARAMETER; 214 } 215 216 /* Set the initial size of the option, and consume from our buffer */ 217 DataSize = sizeof(*Option); 218 MaximumLength -= sizeof(*Option); 219 220 /* Zero out and fill the option header */ 221 RtlZeroMemory(Option, DataSize); 222 Option->Type = PathType; 223 Option->DataOffset = sizeof(*Option); 224 225 /* Extract the string option */ 226 StringEntry = (PWCHAR)(Option + 1); 227 PathString = StringEntry; 228 229 /* Start parsing the device path */ 230 FilePath = (FILEPATH_DEVICE_PATH*)DevicePath; 231 while (IsDevicePathEndType(FilePath) == FALSE) 232 { 233 /* Is this a file path? */ 234 if ((FilePath->Header.Type == MEDIA_DEVICE_PATH) && 235 (FilePath->Header.SubType == MEDIA_FILEPATH_DP)) 236 { 237 /* Get the length of the file path string, avoiding overflow */ 238 StringLength = DevicePathNodeLength(FilePath) - 239 FIELD_OFFSET(FILEPATH_DEVICE_PATH, PathName); 240 if (StringLength < (ULONG)FIELD_OFFSET(FILEPATH_DEVICE_PATH, PathName)) 241 { 242 Status = STATUS_INTEGER_OVERFLOW; 243 goto Quickie; 244 } 245 246 /* Append this path string to the current path string */ 247 Status = EfiInitpAppendPathString(PathString, 248 MaximumLength, 249 FilePath->PathName, 250 StringLength, 251 &BytesAppended); 252 if (!NT_SUCCESS(Status)) 253 { 254 return Status; 255 } 256 257 /* Increase the size of the data, consume buffer space */ 258 DataSize += BytesAppended; 259 MaximumLength -= BytesAppended; 260 261 /* Move to the next path string */ 262 PathString = (PWCHAR)((ULONG_PTR)PathString + BytesAppended); 263 } 264 265 /* Move to the next path node */ 266 FilePath = (FILEPATH_DEVICE_PATH*)NextDevicePathNode(FilePath); 267 } 268 269 /* Check if we still have space for a NULL-terminator */ 270 if (MaximumLength < sizeof(UNICODE_NULL)) 271 { 272 Status = STATUS_INVALID_PARAMETER; 273 goto Quickie; 274 } 275 276 /* We do -- NULL-terminate the string */ 277 *PathString = UNICODE_NULL; 278 DataSize += sizeof(UNICODE_NULL); 279 280 /* Check if all of this has amounted to a single NULL-char */ 281 if (PathString == StringEntry) 282 { 283 /* Then this option is empty */ 284 Option->Empty = TRUE; 285 } 286 287 /* Set the final size of the option */ 288 Option->DataSize = DataSize; 289 290 Quickie: 291 return STATUS_SUCCESS; 292 } 293 294 /*++ 295 * @name EfiInitpGetDeviceNode 296 * 297 * The EfiInitpGetDeviceNode routine 298 * 299 * @param DevicePath 300 * UEFI Image Handle for the current loaded application. 301 * 302 * @return None 303 * 304 *--*/ 305 EFI_DEVICE_PATH_PROTOCOL* 306 EfiInitpGetDeviceNode ( 307 _In_ EFI_DEVICE_PATH_PROTOCOL *DevicePath 308 ) 309 { 310 EFI_DEVICE_PATH_PROTOCOL* NextPath; 311 312 /* Check if we hit the end terminator */ 313 if (IsDevicePathEndType(DevicePath)) 314 { 315 return DevicePath; 316 } 317 318 /* Loop each device path, until we get to the end or to a file path device node */ 319 for ((NextPath = NextDevicePathNode(DevicePath)); 320 !(IsDevicePathEndType(NextPath)) && ((NextPath->Type != MEDIA_DEVICE_PATH) || 321 (NextPath->SubType != MEDIA_FILEPATH_DP)); 322 (NextPath = NextDevicePathNode(NextPath))) 323 { 324 /* Keep iterating down */ 325 DevicePath = NextPath; 326 } 327 328 /* Return the path found */ 329 return DevicePath; 330 } 331 332 /*++ 333 * @name EfiInitTranslateDevicePath 334 * 335 * The EfiInitTranslateDevicePath routine 336 * 337 * @param DevicePath 338 * UEFI Image Handle for the current loaded application. 339 * 340 * @param DeviceEntry 341 * Pointer to the UEFI System Table. 342 * 343 * @return None 344 * 345 *--*/ 346 NTSTATUS 347 EfiInitTranslateDevicePath ( 348 _In_ EFI_DEVICE_PATH_PROTOCOL *DevicePath, 349 _In_ PBL_DEVICE_DESCRIPTOR DeviceEntry 350 ) 351 { 352 NTSTATUS Status; 353 EFI_DEVICE_PATH_PROTOCOL* DeviceNode; 354 MEMMAP_DEVICE_PATH* MemDevicePath; 355 ACPI_HID_DEVICE_PATH *AcpiPath; 356 HARDDRIVE_DEVICE_PATH *DiskPath; 357 358 /* Assume failure */ 359 Status = STATUS_UNSUCCESSFUL; 360 361 /* Set size first */ 362 DeviceEntry->Size = sizeof(*DeviceEntry); 363 364 /* Check if we are booting from a RAM Disk */ 365 if ((DevicePath->Type == HARDWARE_DEVICE_PATH) && 366 (DevicePath->SubType == HW_MEMMAP_DP)) 367 { 368 /* Get the EFI data structure matching this */ 369 MemDevicePath = (MEMMAP_DEVICE_PATH*)DevicePath; 370 371 /* Set the boot library specific device types */ 372 DeviceEntry->DeviceType = LocalDevice; 373 DeviceEntry->Local.Type = RamDiskDevice; 374 375 /* Extract the base, size, and offset */ 376 DeviceEntry->Local.RamDisk.ImageBase.QuadPart = MemDevicePath->StartingAddress; 377 DeviceEntry->Local.RamDisk.ImageSize.QuadPart = MemDevicePath->EndingAddress - 378 MemDevicePath->StartingAddress; 379 DeviceEntry->Local.RamDisk.ImageOffset = 0; 380 return STATUS_SUCCESS; 381 } 382 383 /* Otherwise, check what kind of device node this is */ 384 DeviceNode = EfiInitpGetDeviceNode(DevicePath); 385 switch (DeviceNode->Type) 386 { 387 /* ACPI */ 388 case ACPI_DEVICE_PATH: 389 390 /* We only support floppy drives */ 391 AcpiPath = (ACPI_HID_DEVICE_PATH*)DeviceNode; 392 if ((AcpiPath->HID != EISA_PNP_ID(0x604)) && 393 (AcpiPath->HID != EISA_PNP_ID(0x700))) 394 { 395 return Status; 396 } 397 398 /* Set the boot library specific device types */ 399 DeviceEntry->DeviceType = LocalDevice; 400 DeviceEntry->Local.Type = FloppyDevice; 401 402 /* The ACPI UID is the drive number */ 403 DeviceEntry->Local.FloppyDisk.DriveNumber = AcpiPath->UID; 404 return STATUS_SUCCESS; 405 406 /* Network, ATAPI, SCSI, USB */ 407 case MESSAGING_DEVICE_PATH: 408 409 /* Check if it's network */ 410 if ((DeviceNode->SubType == MSG_MAC_ADDR_DP) || 411 (DeviceNode->SubType == MSG_IPv4_DP)) 412 { 413 /* Set the boot library specific device types */ 414 DeviceEntry->DeviceType = UdpDevice; 415 DeviceEntry->Remote.Unknown = 256; 416 return STATUS_SUCCESS; 417 } 418 419 /* Other types should come in as MEDIA_DEVICE_PATH -- Windows assumes this is a floppy */ 420 DeviceEntry->DeviceType = DiskDevice; 421 DeviceEntry->Local.Type = FloppyDevice; 422 DeviceEntry->Local.FloppyDisk.DriveNumber = 0; 423 return STATUS_SUCCESS; 424 425 /* Disk or CDROM */ 426 case MEDIA_DEVICE_PATH: 427 428 /* Extract the disk path and check if it's a physical disk */ 429 DiskPath = (HARDDRIVE_DEVICE_PATH*)DeviceNode; 430 if (DeviceNode->SubType == MEDIA_HARDDRIVE_DP) 431 { 432 /* Check if this is an MBR partition */ 433 if (DiskPath->SignatureType == SIGNATURE_TYPE_MBR) 434 { 435 /* Set that this is a local partition */ 436 DeviceEntry->DeviceType = LegacyPartitionDevice; 437 DeviceEntry->Partition.Disk.Type = LocalDevice; 438 439 DeviceEntry->Partition.Disk.HardDisk.PartitionType = MbrPartition; 440 DeviceEntry->Partition.Disk.HardDisk.Mbr.PartitionSignature = 441 *(PULONG)&DiskPath->Signature[0]; 442 DeviceEntry->Partition.Mbr.PartitionNumber = DiskPath->PartitionNumber; 443 return STATUS_SUCCESS; 444 } 445 446 /* Check if it's a GPT partition */ 447 if (DiskPath->SignatureType == SIGNATURE_TYPE_GUID) 448 { 449 /* Set that this is a local disk */ 450 DeviceEntry->DeviceType = PartitionDevice; 451 DeviceEntry->Partition.Disk.Type = LocalDevice; 452 453 /* Set GPT partition ID */ 454 DeviceEntry->Partition.Disk.HardDisk.PartitionType = GptPartition; 455 456 /* Copy the signature GUID */ 457 RtlCopyMemory(&DeviceEntry->Partition.Gpt.PartitionGuid, 458 DiskPath->Signature, 459 sizeof(GUID)); 460 461 DeviceEntry->Flags |= 4u; 462 return STATUS_SUCCESS; 463 } 464 465 /* Otherwise, raw boot is not supported */ 466 DeviceEntry->DeviceType = PartitionDevice; 467 DeviceEntry->Partition.Disk.Type = LocalDevice; 468 DeviceEntry->Partition.Disk.HardDisk.PartitionType = RawPartition; 469 DeviceEntry->Partition.Disk.HardDisk.Raw.DiskNumber = 0; 470 } 471 else if (DeviceNode->SubType == MEDIA_CDROM_DP) 472 { 473 /* Set the right type for a CDROM */ 474 DeviceEntry->DeviceType = DiskDevice; 475 DeviceEntry->Local.Type = CdRomDevice; 476 477 /* Set the drive number to zero */ 478 DeviceEntry->Local.FloppyDisk.DriveNumber = 0; 479 return STATUS_SUCCESS; 480 } 481 482 /* Fail anything else */ 483 default: 484 break; 485 } 486 487 /* Return here only on failure */ 488 return Status; 489 } 490 491 /*++ 492 * @name EfiInitpConvertEfiDevicePath 493 * 494 * The EfiInitpConvertEfiDevicePath routine 495 * 496 * @param DevicePath 497 * UEFI Image Handle for the current loaded application. 498 * 499 * @param DeviceType 500 * Pointer to the UEFI System Table. 501 * 502 * @param Option 503 * Pointer to the UEFI System Table. 504 * 505 * @param MaximumLength 506 * Pointer to the UEFI System Table. 507 * 508 * @return None 509 * 510 *--*/ 511 NTSTATUS 512 EfiInitpConvertEfiDevicePath ( 513 _In_ EFI_DEVICE_PATH_PROTOCOL *DevicePath, 514 _In_ ULONG DeviceType, 515 _In_ PBL_BCD_OPTION Option, 516 _In_ ULONG MaximumLength 517 ) 518 { 519 PBCD_DEVICE_OPTION BcdDevice; 520 NTSTATUS Status; 521 522 /* Make sure we have enough space for the option */ 523 if (MaximumLength < sizeof(*Option)) 524 { 525 Status = STATUS_INVALID_PARAMETER; 526 goto Quickie; 527 } 528 529 /* Zero out the option */ 530 RtlZeroMemory(Option, sizeof(*Option)); 531 532 /* Make sure we have enough space for the device entry */ 533 if ((MaximumLength - sizeof(*Option)) < 534 (ULONG)FIELD_OFFSET(BCD_DEVICE_OPTION, DeviceDescriptor)) 535 { 536 Status = STATUS_INVALID_PARAMETER; 537 goto Quickie; 538 } 539 540 /* Fill it out */ 541 BcdDevice = (PBCD_DEVICE_OPTION)(Option + 1); 542 Status = EfiInitTranslateDevicePath(DevicePath, 543 &BcdDevice->DeviceDescriptor); 544 if (!NT_SUCCESS(Status)) 545 { 546 goto Quickie; 547 } 548 549 /* Fill out the rest of the option structure */ 550 Option->DataOffset = sizeof(*Option); 551 Option->Type = DeviceType; 552 Option->DataSize = FIELD_OFFSET(BCD_DEVICE_OPTION, DeviceDescriptor) + 553 BcdDevice->DeviceDescriptor.Size; 554 Status = STATUS_SUCCESS; 555 556 Quickie: 557 return Status; 558 } 559 560 /*++ 561 * @name EfiInitpCreateApplicationEntry 562 * 563 * The EfiInitpCreateApplicationEntry routine 564 * 565 * @param SystemTable 566 * UEFI Image Handle for the current loaded application. 567 * 568 * @param Entry 569 * Pointer to the UEFI System Table. 570 * 571 * @param MaximumLength 572 * Pointer to the UEFI System Table. 573 * 574 * @param DevicePath 575 * Pointer to the UEFI System Table. 576 * 577 * @param FilePath 578 * Pointer to the UEFI System Table. 579 * 580 * @param LoadOptions 581 * Pointer to the UEFI System Table. 582 * 583 * @param LoadOptionsSize 584 * Pointer to the UEFI System Table. 585 * 586 * @param Flags 587 * Pointer to the UEFI System Table. 588 * 589 * @param ResultLength 590 * Pointer to the UEFI System Table. 591 * 592 * @param AppEntryDevice 593 * Pointer to the UEFI System Table. 594 * 595 * @return None 596 * 597 *--*/ 598 VOID 599 EfiInitpCreateApplicationEntry ( 600 __in EFI_SYSTEM_TABLE *SystemTable, 601 __in PBL_APPLICATION_ENTRY Entry, 602 __in ULONG MaximumLength, 603 __in EFI_DEVICE_PATH *DevicePath, 604 __in EFI_DEVICE_PATH *FilePath, 605 __in PWCHAR LoadOptions, 606 __in ULONG LoadOptionsSize, 607 __in ULONG Flags, 608 __out PULONG ResultLength, 609 __out PBL_DEVICE_DESCRIPTOR *AppEntryDevice 610 ) 611 { 612 PBL_WINDOWS_LOAD_OPTIONS WindowsOptions; 613 PWCHAR ObjectString, CommandLine; 614 PBL_BCD_OPTION Option, PreviousOption; 615 ULONG HeaderSize, TotalOptionSize, Size, CommandLineSize, RemainingSize; 616 NTSTATUS Status; 617 UNICODE_STRING GuidString; 618 GUID ObjectGuid; 619 PBCD_DEVICE_OPTION BcdDevice; 620 BOOLEAN HaveBinaryOptions, HaveGuid; 621 PBL_FILE_PATH_DESCRIPTOR OsPath; 622 EFI_DEVICE_PATH *OsDevicePath; 623 624 /* Initialize everything */ 625 TotalOptionSize = 0; 626 *AppEntryDevice = NULL; 627 HeaderSize = 0; 628 629 /* Check if the load options are in binary Windows format */ 630 WindowsOptions = (PBL_WINDOWS_LOAD_OPTIONS)LoadOptions; 631 if ((WindowsOptions != NULL) && 632 (LoadOptionsSize >= sizeof(BL_WINDOWS_LOAD_OPTIONS)) && 633 (WindowsOptions->Length >= sizeof(BL_WINDOWS_LOAD_OPTIONS)) && 634 !(strncmp(WindowsOptions->Signature, "WINDOWS", 7))) 635 { 636 /* They are, so firmware must have loaded us -- extract arguments */ 637 CommandLine = WindowsOptions->LoadOptions; 638 CommandLineSize = LoadOptionsSize - FIELD_OFFSET(BL_WINDOWS_LOAD_OPTIONS, 639 LoadOptions); 640 641 /* Remember that we used binary options */ 642 HaveBinaryOptions = TRUE; 643 } 644 else 645 { 646 /* Nope -- so treat them as raw command-line options */ 647 CommandLine = LoadOptions; 648 CommandLineSize = LoadOptionsSize; 649 650 /* No binary options */ 651 HaveBinaryOptions = FALSE; 652 } 653 654 /* EFI uses UTF-16LE, like NT, so convert to characters */ 655 CommandLineSize /= sizeof(WCHAR); 656 if (CommandLineSize != 0) 657 { 658 /* And check if the options are not NULL-terminated */ 659 if (wcsnlen(CommandLine, CommandLineSize) == CommandLineSize) 660 { 661 /* NULL-terminate them */ 662 CommandLine[CommandLineSize - 1] = UNICODE_NULL; 663 } 664 } 665 666 /* Begin by making sure we at least have space for the app entry header */ 667 RemainingSize = MaximumLength; 668 if (RemainingSize < sizeof(BL_APPLICATION_ENTRY)) 669 { 670 Status = STATUS_INVALID_PARAMETER; 671 goto Quickie; 672 } 673 674 /* On exit, return that we've at least consumed this much */ 675 HeaderSize = FIELD_OFFSET(BL_APPLICATION_ENTRY, BcdData); 676 677 /* Zero out the header, and write down the signature */ 678 RtlZeroMemory(Entry, sizeof(BL_APPLICATION_ENTRY)); 679 RtlCopyMemory(Entry->Signature, BL_APP_ENTRY_SIGNATURE, 7); 680 681 /* Check if a BCD object was passed on the command-line */ 682 ObjectString = wcsstr(CommandLine, L"BCDOBJECT="); 683 if (ObjectString != NULL) 684 { 685 /* Convert the BCD object to a GUID */ 686 RtlInitUnicodeString(&GuidString, ObjectString + 10); 687 RtlGUIDFromString(&GuidString, &ObjectGuid); 688 689 /* Store it in the application entry */ 690 Entry->Guid = ObjectGuid; 691 692 /* Remember one was passed */ 693 HaveGuid = TRUE; 694 } 695 else 696 { 697 /* Remember that no identifier was passed */ 698 Entry->Flags |= BL_APPLICATION_ENTRY_FLAG_NO_GUID; 699 HaveGuid = FALSE; 700 } 701 702 /* At this point, the header is consumed, and we must now handle BCD options */ 703 RemainingSize -= FIELD_OFFSET(BL_APPLICATION_ENTRY, BcdData); 704 705 /* Convert the device path into a BCD option */ 706 Status = EfiInitpConvertEfiDevicePath(DevicePath, 707 BcdLibraryDevice_ApplicationDevice, 708 &Entry->BcdData, 709 RemainingSize); 710 if (!NT_SUCCESS(Status)) 711 { 712 /* We failed, so mark the option as such and return an empty one */ 713 Entry->BcdData.Empty = TRUE; 714 TotalOptionSize = sizeof(BL_BCD_OPTION); 715 goto Quickie; 716 } 717 718 /* Extract the device descriptor and return it */ 719 BcdDevice = (PVOID)((ULONG_PTR)&Entry->BcdData + Entry->BcdData.DataOffset); 720 *AppEntryDevice = &BcdDevice->DeviceDescriptor; 721 722 /* Calculate how big this option was and consume that from the buffer */ 723 TotalOptionSize = BlGetBootOptionSize(&Entry->BcdData); 724 RemainingSize -= TotalOptionSize; 725 726 /* Calculate where the next option should go */ 727 Option = (PVOID)((ULONG_PTR)&Entry->BcdData + TotalOptionSize); 728 729 /* Check if we're PXE booting or not */ 730 if ((*AppEntryDevice)->DeviceType == UdpDevice) 731 { 732 /* lol */ 733 Status = STATUS_NOT_IMPLEMENTED; 734 } 735 else 736 { 737 /* Convert the local file path into a BCD option */ 738 Status = EfiInitpConvertEfiFilePath(FilePath, 739 BcdLibraryString_ApplicationPath, 740 Option, 741 RemainingSize); 742 } 743 744 /* Bail out on failure */ 745 if (!NT_SUCCESS(Status)) 746 { 747 goto Quickie; 748 } 749 750 /* The next option is right after this one */ 751 Entry->BcdData.NextEntryOffset = TotalOptionSize; 752 753 /* Now compute the size of the next option, and add to the rolling sum */ 754 Size = BlGetBootOptionSize(Option); 755 TotalOptionSize += Size; 756 757 /* Remember the previous option so we can update its next offset */ 758 PreviousOption = Option; 759 760 /* Consume the option from the buffer */ 761 RemainingSize -= Size; 762 763 /* Calculate where the next option should go */ 764 Option = (PVOID)((ULONG_PTR)Option + Size); 765 766 /* Check if we were using binary options without a BCD GUID */ 767 if ((HaveBinaryOptions) && !(HaveGuid)) 768 { 769 /* Then this means we have to convert the OS paths to BCD too */ 770 WindowsOptions = (PBL_WINDOWS_LOAD_OPTIONS)LoadOptions; 771 OsPath = (PVOID)((ULONG_PTR)WindowsOptions + WindowsOptions->OsPathOffset); 772 773 /* IS the OS path in EFI format? */ 774 if ((OsPath->Length > (ULONG)FIELD_OFFSET(BL_FILE_PATH_DESCRIPTOR, Path)) && 775 (OsPath->PathType == EfiPath)) 776 { 777 /* Convert the device portion */ 778 OsDevicePath = (EFI_DEVICE_PATH*)OsPath->Path; 779 Status = EfiInitpConvertEfiDevicePath(OsDevicePath, 780 BcdOSLoaderDevice_OSDevice, 781 Option, 782 RemainingSize); 783 if (!NT_SUCCESS(Status)) 784 { 785 goto Quickie; 786 } 787 788 /* Update the offset of the previous option */ 789 PreviousOption->NextEntryOffset = (ULONG_PTR)Option - (ULONG_PTR)&Entry->BcdData; 790 791 /* Now compute the size of the next option, and add to the rolling sum */ 792 Size = BlGetBootOptionSize(Option); 793 TotalOptionSize += Size; 794 795 /* Remember the previous option so we can update its next offset */ 796 PreviousOption = Option; 797 798 /* Consume the option from the buffer */ 799 RemainingSize -= Size; 800 801 /* Calculate where the next option should go */ 802 Option = (PVOID)((ULONG_PTR)Option + Size); 803 804 /* Convert the path option */ 805 Status = EfiInitpConvertEfiFilePath(OsDevicePath, 806 BcdOSLoaderString_SystemRoot, 807 Option, 808 RemainingSize); 809 if (!NT_SUCCESS(Status)) 810 { 811 goto Quickie; 812 } 813 814 /* Update the offset of the previous option */ 815 PreviousOption->NextEntryOffset = (ULONG_PTR)Option - (ULONG_PTR)&Entry->BcdData; 816 817 /* Now compute the size of the next option, and add to the rolling sum */ 818 Size = BlGetBootOptionSize(Option); 819 TotalOptionSize += Size; 820 821 /* Remember the previous option so we can update its next offset */ 822 PreviousOption = Option; 823 824 /* Consume the option from the buffer */ 825 RemainingSize -= Size; 826 827 /* Calculate where the next option should go */ 828 Option = (PVOID)((ULONG_PTR)Option + Size); 829 } 830 } 831 832 /* Now convert everything else */ 833 AhCreateLoadOptionsList(CommandLine, 834 &Entry->BcdData, 835 RemainingSize, 836 &TotalOptionSize, 837 &PreviousOption, 838 &Size); 839 840 Quickie: 841 /* Return the final size */ 842 *ResultLength = HeaderSize + TotalOptionSize; 843 } 844 845 /*++ 846 * @name EfiInitCreateInputParametersEx 847 * 848 * The EfiInitCreateInputParametersEx routine converts UEFI entrypoint 849 * parameters to the ones expected by Windows Boot Applications 850 * 851 * @param ImageHandle 852 * UEFI Image Handle for the current loaded application. 853 * 854 * @param SystemTable 855 * Pointer to the UEFI System Table. 856 * 857 * @return A PBOOT_APPLICATION_PARAMETER_BLOCK structure containing the data 858 * from UEFI, translated to the Boot Library-compatible format. 859 * 860 *--*/ 861 PBOOT_APPLICATION_PARAMETER_BLOCK 862 EfiInitCreateInputParametersEx ( 863 _In_ EFI_HANDLE ImageHandle, 864 _In_ EFI_SYSTEM_TABLE *SystemTable 865 ) 866 { 867 EFI_BOOT_SERVICES* BootServices; 868 EFI_LOADED_IMAGE_PROTOCOL *LoadedImage; 869 EFI_DEVICE_PATH_PROTOCOL *DevicePath; 870 PBL_FIRMWARE_DESCRIPTOR FirmwareData; 871 PBL_RETURN_ARGUMENTS ReturnArguments; 872 ULONG FirmwareOffset, ConsumedSize; 873 PBL_DEVICE_DESCRIPTOR AppDevice; 874 EFI_STATUS Status; 875 876 /* Initialize the header with the signature and version */ 877 EfiInitScratch.Signature[0] = BOOT_APPLICATION_SIGNATURE_1; 878 EfiInitScratch.Signature[1] = BOOT_APPLICATION_SIGNATURE_2; 879 EfiInitScratch.Version = BOOT_APPLICATION_VERSION; 880 881 /* Set the image type to x86 */ 882 EfiInitScratch.ImageType = EFI_IMAGE_MACHINE_IA32; 883 884 /* Set the translation type to physical */ 885 EfiInitScratch.MemoryTranslationType = BOOT_MEMORY_TRANSLATION_TYPE_PHYSICAL; 886 887 /* Indicate that the data was converted from EFI */ 888 BlpApplicationFlags |= BL_APPLICATION_FLAG_CONVERTED_FROM_EFI; 889 890 /* Grab the loaded image protocol, which has our base and size */ 891 BootServices = SystemTable->BootServices; 892 Status = BootServices->HandleProtocol(ImageHandle, 893 &EfiLoadedImageProtocol, 894 (VOID**)&LoadedImage); 895 if (Status != EFI_SUCCESS) 896 { 897 return NULL; 898 } 899 900 /* Capture it in the boot application parameters */ 901 EfiInitScratch.ImageBase = (ULONG_PTR)LoadedImage->ImageBase; 902 EfiInitScratch.ImageSize = (ULONG)LoadedImage->ImageSize; 903 904 /* Now grab our device path protocol, so we can convert the path later on */ 905 Status = BootServices->HandleProtocol(LoadedImage->DeviceHandle, 906 &EfiDevicePathProtocol, 907 (VOID**)&DevicePath); 908 if (Status != EFI_SUCCESS) 909 { 910 return NULL; 911 } 912 913 /* The built-in boot memory data comes right after our block */ 914 EfiInitScratch.MemoryDataOffset = 915 FIELD_OFFSET(BOOT_APPLICATION_PARAMETER_BLOCK_SCRATCH, BootMemoryData); 916 917 /* Build the boot memory data structure, with 1 descriptor */ 918 EfiInitScratch.BootMemoryData.Version = BL_MEMORY_DATA_VERSION; 919 EfiInitScratch.BootMemoryData.MdListOffset = 920 FIELD_OFFSET(BOOT_APPLICATION_PARAMETER_BLOCK_SCRATCH, MemEntry) - 921 EfiInitScratch.MemoryDataOffset; 922 EfiInitScratch.BootMemoryData.DescriptorSize = sizeof(BL_MEMORY_DESCRIPTOR); 923 EfiInitScratch.BootMemoryData.DescriptorCount = 1; 924 EfiInitScratch.BootMemoryData.DescriptorOffset = FIELD_OFFSET(BL_MEMORY_DESCRIPTOR, BasePage); 925 926 /* Build the memory entry descriptor for this image itself */ 927 EfiInitScratch.MemEntry.Flags = BlMemoryWriteBack; 928 EfiInitScratch.MemEntry.Type = BlLoaderMemory; 929 EfiInitScratch.MemEntry.BasePage = EfiInitScratch.ImageBase >> PAGE_SHIFT; 930 EfiInitScratch.MemEntry.PageCount = ALIGN_UP_BY(EfiInitScratch.ImageSize, PAGE_SIZE) >> PAGE_SHIFT; 931 932 /* The built-in application entry comes right after the memory descriptor*/ 933 EfiInitScratch.AppEntryOffset = 934 FIELD_OFFSET(BOOT_APPLICATION_PARAMETER_BLOCK_SCRATCH, AppEntry); 935 936 /* Go and build it */ 937 EfiInitpCreateApplicationEntry(SystemTable, 938 (PBL_APPLICATION_ENTRY)&EfiInitScratch.AppEntry, 939 sizeof(EfiInitScratch.AppEntry), 940 DevicePath, 941 LoadedImage->FilePath, 942 LoadedImage->LoadOptions, 943 LoadedImage->LoadOptionsSize, 944 EfiInitScratch.MemEntry.PageCount, 945 &ConsumedSize, 946 &AppDevice); 947 948 /* Boot device information comes right after the application entry */ 949 EfiInitScratch.BootDeviceOffset = ConsumedSize + EfiInitScratch.AppEntryOffset; 950 951 /* Check if we have a boot device */ 952 if (AppDevice != NULL) 953 { 954 /* We do -- copy it */ 955 RtlCopyMemory(EfiInitScratch.AppEntry + ConsumedSize, 956 AppDevice, 957 AppDevice->Size); 958 959 /* Firmware data follows right after the boot device entry */ 960 FirmwareOffset = AppDevice->Size + EfiInitScratch.BootDeviceOffset; 961 } 962 else 963 { 964 /* We do not, so zero out the space where a full boot device structure would fit */ 965 RtlZeroMemory(EfiInitScratch.AppEntry + ConsumedSize, 966 sizeof(BL_DEVICE_DESCRIPTOR)); 967 968 /* And start the firmware data past that */ 969 FirmwareOffset = EfiInitScratch.BootDeviceOffset + sizeof(BL_DEVICE_DESCRIPTOR); 970 } 971 972 /* Set the computed firmware data offset */ 973 EfiInitScratch.FirmwareParametersOffset = FirmwareOffset; 974 975 /* Fill out the firmware data that's there */ 976 FirmwareData = (PVOID)((ULONG_PTR)&EfiInitScratch + EfiInitScratch.FirmwareParametersOffset); 977 FirmwareData->Version = BL_FIRMWARE_DESCRIPTOR_VERSION; 978 FirmwareData->ImageHandle = ImageHandle; 979 FirmwareData->SystemTable = SystemTable; 980 981 /* Finally, set the return argument offset */ 982 EfiInitScratch.ReturnArgumentsOffset = FirmwareOffset + sizeof(BL_FIRMWARE_DESCRIPTOR); 983 984 /* And fill out the return argument data */ 985 ReturnArguments = (PVOID)((ULONG_PTR)&EfiInitScratch + EfiInitScratch.ReturnArgumentsOffset); 986 ReturnArguments->Version = BL_RETURN_ARGUMENTS_VERSION; 987 988 /* We're done, compute the final size and return the block */ 989 EfiInitScratch.Size = EfiInitScratch.ReturnArgumentsOffset + sizeof(BL_RETURN_ARGUMENTS); 990 return (PBOOT_APPLICATION_PARAMETER_BLOCK)&EfiInitScratch; 991 } 992 993 /*++ 994 * @name EfiEntry 995 * 996 * The EfiEntry routine implements the UEFI entrypoint for the application. 997 * 998 * @param ImageHandle 999 * UEFI Image Handle for the current loaded application. 1000 * 1001 * @param SystemTable 1002 * Pointer to the UEFI System Table. 1003 * 1004 * @return EFI_SUCCESS if the image was loaded correctly, relevant error code 1005 * otherwise. 1006 * 1007 *--*/ 1008 EFI_STATUS 1009 EFIAPI 1010 EfiEntry ( 1011 _In_ EFI_HANDLE ImageHandle, 1012 _In_ EFI_SYSTEM_TABLE *SystemTable 1013 ) 1014 { 1015 NTSTATUS Status; 1016 PBOOT_APPLICATION_PARAMETER_BLOCK BootParameters; 1017 1018 /* Convert EFI parameters to Windows Boot Application parameters */ 1019 BootParameters = EfiInitCreateInputParametersEx(ImageHandle, SystemTable); 1020 if (BootParameters != NULL) 1021 { 1022 /* Conversion was good -- call the Boot Manager Entrypoint */ 1023 Status = BmMain(BootParameters); 1024 } 1025 else 1026 { 1027 /* Conversion failed, bail out */ 1028 Status = STATUS_INVALID_PARAMETER; 1029 } 1030 1031 /* Convert the NT status code to an EFI code */ 1032 return EfiGetEfiStatusCode(Status); 1033 } 1034 1035