1 /* 2 * COPYRIGHT: See COPYING.ARM in the top level directory 3 * PROJECT: ReactOS UEFI Boot Library 4 * FILE: boot/environ/lib/misc/image.c 5 * PURPOSE: Boot Library Image Routines 6 * PROGRAMMER: Alex Ionescu (alex.ionescu@reactos.org) 7 */ 8 9 /* INCLUDES ******************************************************************/ 10 11 #include "bl.h" 12 #include <bcd.h> 13 14 /* DATA VARIABLES ************************************************************/ 15 16 ULONG IapAllocatedTableEntries; 17 ULONG IapTableEntries; 18 PVOID* IapImageTable; 19 20 #ifndef _M_ARM 21 KDESCRIPTOR GdtRegister; 22 KDESCRIPTOR IdtRegister; 23 KDESCRIPTOR BootAppGdtRegister; 24 KDESCRIPTOR BootAppIdtRegister; 25 PVOID BootApp32EntryRoutine; 26 PBOOT_APPLICATION_PARAMETER_BLOCK BootApp32Parameters; 27 PVOID BootApp32Stack; 28 #endif 29 30 /* FUNCTIONS *****************************************************************/ 31 32 NTSTATUS 33 ImgpGetFileSize ( 34 _In_ PBL_IMG_FILE File, 35 _Out_ PULONG FileSize 36 ) 37 { 38 NTSTATUS Status; 39 ULONG Size; 40 BL_FILE_INFORMATION FileInformation; 41 42 /* Check if the file was memory mapped */ 43 if (File->Flags & BL_IMG_MEMORY_FILE) 44 { 45 /* Just read the size of the mapping */ 46 Size = File->FileSize; 47 } 48 else 49 { 50 /* Do file I/O to get the file size */ 51 Status = BlFileGetInformation(File->FileId, 52 &FileInformation); 53 if (!NT_SUCCESS(Status)) 54 { 55 return Status; 56 } 57 58 /* We only support files less than 4GB in the Image Mapped */ 59 Size = FileInformation.Size; 60 if (FileInformation.Size > ULONG_MAX) 61 { 62 return STATUS_NOT_SUPPORTED; 63 } 64 } 65 66 /* Return the size and success */ 67 *FileSize = Size; 68 return STATUS_SUCCESS; 69 } 70 71 NTSTATUS 72 ImgpReadAtFileOffset ( 73 _In_ PBL_IMG_FILE File, 74 _In_ ULONG Size, 75 _In_ ULONGLONG ByteOffset, 76 _In_ PVOID Buffer, 77 _Out_ PULONG BytesReturned 78 ) 79 { 80 NTSTATUS Status; 81 82 /* Check what if this is a mapped file or not */ 83 if (File->Flags & BL_IMG_MEMORY_FILE) 84 { 85 /* Check if the boundaries are within the file size */ 86 if ((ByteOffset + Size) <= File->FileSize) 87 { 88 /* Yep, copy into the caller-supplied buffer */ 89 RtlCopyMemory(Buffer, 90 (PVOID)((ULONG_PTR)File->BaseAddress + (ULONG_PTR)ByteOffset), 91 Size); 92 93 /* If caller wanted to know, return the size copied */ 94 if (BytesReturned) 95 { 96 *BytesReturned = Size; 97 } 98 99 /* All good */ 100 Status = STATUS_SUCCESS; 101 } 102 else 103 { 104 /* Doesn't fit */ 105 Status = STATUS_INVALID_PARAMETER; 106 } 107 } 108 else 109 { 110 /* Issue the file I/O instead */ 111 Status = BlFileReadAtOffsetEx(File->FileId, 112 Size, 113 ByteOffset, 114 Buffer, 115 BytesReturned, 116 0); 117 } 118 119 /* Return the final status */ 120 return Status; 121 } 122 123 NTSTATUS 124 ImgpOpenFile ( 125 _In_ ULONG DeviceId, 126 _In_ PWCHAR FileName, 127 _In_ ULONG Flags, 128 _Out_ PBL_IMG_FILE NewFile 129 ) 130 { 131 NTSTATUS Status; 132 ULONG FileSize; 133 ULONGLONG RemoteFileSize; 134 PVOID RemoteFileAddress; 135 ULONG FileId; 136 137 /* First, try to see if BD has this file remotely */ 138 Status = BlBdPullRemoteFile(FileName, 139 &RemoteFileAddress, 140 &RemoteFileSize); 141 if (NT_SUCCESS(Status)) 142 { 143 /* Yep, get the file size and make sure it's < 4GB */ 144 FileSize = RemoteFileSize; 145 if (RemoteFileSize <= ULONG_MAX) 146 { 147 /* Remember this is a memory mapped remote file */ 148 NewFile->Flags |= (BL_IMG_MEMORY_FILE | BL_IMG_REMOTE_FILE); 149 NewFile->FileSize = FileSize; 150 NewFile->BaseAddress = RemoteFileAddress; 151 goto Quickie; 152 } 153 } 154 155 /* Use File I/O instead */ 156 Status = BlFileOpen(DeviceId, 157 FileName, 158 BL_FILE_READ_ACCESS, 159 &FileId); 160 if (!NT_SUCCESS(Status)) 161 { 162 /* Bail out on failure */ 163 return Status; 164 } 165 166 /* Make sure nobody thinks this is a memory file */ 167 NewFile->Flags &= ~BL_IMG_MEMORY_FILE; 168 NewFile->FileId = FileId; 169 170 Quickie: 171 /* Set common data for both memory and I/O based file */ 172 NewFile->Flags |= BL_IMG_VALID_FILE; 173 NewFile->FileName = FileName; 174 return Status; 175 } 176 177 NTSTATUS 178 ImgpCloseFile ( 179 _In_ PBL_IMG_FILE File 180 ) 181 { 182 NTSTATUS Status; 183 184 /* Make sure this is a valid file, otherwise no-op */ 185 Status = STATUS_SUCCESS; 186 if (File->Flags & BL_IMG_VALID_FILE) 187 { 188 /* Is this a memory mapped file? */ 189 if (!(File->Flags & BL_IMG_MEMORY_FILE)) 190 { 191 /* Nope, close the file handle */ 192 return BlFileClose(File->FileId); 193 } 194 195 /* Is this a remote file? */ 196 if (File->Flags & BL_IMG_REMOTE_FILE) 197 { 198 /* Then only free the memory in that scenario */ 199 return MmPapFreePages(File->BaseAddress, BL_MM_INCLUDE_MAPPED_ALLOCATED); 200 } 201 } 202 203 /* Return the final status */ 204 return Status; 205 } 206 207 NTSTATUS 208 BlImgUnallocateImageBuffer ( 209 _In_ PVOID ImageBase, 210 _In_ ULONG ImageSize, 211 _In_ ULONG ImageFlags 212 ) 213 { 214 PHYSICAL_ADDRESS PhysicalAddress; 215 NTSTATUS Status; 216 217 /* Make sure required parameters are present */ 218 if (!(ImageBase) || !(ImageSize)) 219 { 220 return STATUS_INVALID_PARAMETER; 221 } 222 223 /* Check if this was a physical allocation */ 224 if (!(ImageFlags & BL_LOAD_IMG_VIRTUAL_BUFFER)) 225 { 226 return MmPapFreePages(ImageBase, BL_MM_INCLUDE_MAPPED_ALLOCATED); 227 } 228 229 /* It's virtual, so translate it first */ 230 if (!BlMmTranslateVirtualAddress(ImageBase, &PhysicalAddress)) 231 { 232 return STATUS_INVALID_PARAMETER; 233 } 234 235 /* Unmap the virtual mapping */ 236 Status = BlMmUnmapVirtualAddressEx(ImageBase, ROUND_TO_PAGES(ImageSize)); 237 if (NT_SUCCESS(Status)) 238 { 239 /* Now free the physical pages */ 240 Status = BlMmFreePhysicalPages(PhysicalAddress); 241 } 242 243 /* All done */ 244 return Status; 245 } 246 247 NTSTATUS 248 BlImgAllocateImageBuffer ( 249 _Inout_ PVOID* ImageBuffer, 250 _In_ ULONG MemoryType, 251 _In_ ULONGLONG ImageSize, 252 _In_ ULONG Flags 253 ) 254 { 255 ULONG Attributes; 256 ULONGLONG Pages, Size; 257 PVOID MappedBase, CurrentBuffer; 258 NTSTATUS Status; 259 PHYSICAL_ADDRESS PhysicalAddress; 260 261 /* Read and reset the current buffer address */ 262 CurrentBuffer = *ImageBuffer; 263 *ImageBuffer = NULL; 264 265 /* Align the image size to page */ 266 Size = ROUND_TO_PAGES(ImageSize); 267 268 /* Not sure what this attribute does yet */ 269 Attributes = 0; 270 if (Flags & BL_LOAD_IMG_UNKNOWN_BUFFER_FLAG) 271 { 272 Attributes = 0x10000; 273 } 274 275 /* Check if the caller wants a virtual buffer */ 276 if (Flags & BL_LOAD_IMG_VIRTUAL_BUFFER) 277 { 278 /* Set the physical address to the current buffer */ 279 PhysicalAddress.QuadPart = (ULONG_PTR)CurrentBuffer; 280 Pages = Size >> PAGE_SHIFT; 281 282 /* Allocate the physical pages */ 283 Status = BlMmAllocatePhysicalPages(&PhysicalAddress, 284 Pages, 285 MemoryType, 286 Attributes, 287 0); 288 if (!NT_SUCCESS(Status)) 289 { 290 /* If that failed, remove allocation attributes */ 291 PhysicalAddress.QuadPart = 0; 292 Attributes &= ~BlMemoryValidAllocationAttributeMask, 293 Status = BlMmAllocatePhysicalPages(&PhysicalAddress, 294 Pages, 295 MemoryType, 296 Attributes, 297 0); 298 } 299 300 /* Check if either attempts succeeded */ 301 if (!NT_SUCCESS(Status)) 302 { 303 return Status; 304 } 305 306 /* Now map the physical buffer at the address requested */ 307 MappedBase = PhysicalAddressToPtr(PhysicalAddress); 308 Status = BlMmMapPhysicalAddressEx(&MappedBase, 309 BlMemoryFixed, 310 Size, 311 PhysicalAddress); 312 if (!NT_SUCCESS(Status)) 313 { 314 /* Free on failure if needed */ 315 BlMmFreePhysicalPages(PhysicalAddress); 316 return Status; 317 } 318 } 319 else 320 { 321 /* Otherwise, allocate raw physical pages */ 322 MappedBase = CurrentBuffer; 323 Pages = Size >> PAGE_SHIFT; 324 Status = MmPapAllocatePagesInRange(&MappedBase, 325 MemoryType, 326 Pages, 327 Attributes, 328 0, 329 NULL, 330 0); 331 if (!NT_SUCCESS(Status)) 332 { 333 /* If that failed, try without allocation attributes */ 334 MappedBase = NULL; 335 Attributes &= ~BlMemoryValidAllocationAttributeMask, 336 Status = MmPapAllocatePagesInRange(&MappedBase, 337 MemoryType, 338 Pages, 339 Attributes, 340 0, 341 NULL, 342 0); 343 } 344 345 /* Check if either attempts succeeded */ 346 if (!NT_SUCCESS(Status)) 347 { 348 return Status; 349 } 350 } 351 352 /* Success path, returned allocated address */ 353 *ImageBuffer = MappedBase; 354 return STATUS_SUCCESS; 355 } 356 357 NTSTATUS 358 BlImgLoadImageWithProgress2 ( 359 _In_ ULONG DeviceId, 360 _In_ BL_MEMORY_TYPE MemoryType, 361 _In_ PWCHAR FileName, 362 _Inout_ PVOID* MappedBase, 363 _Inout_ PULONG MappedSize, 364 _In_ ULONG ImageFlags, 365 _In_ BOOLEAN ShowProgress, 366 _Out_opt_ PUCHAR* HashBuffer, 367 _Out_opt_ PULONG HashSize 368 ) 369 { 370 NTSTATUS Status; 371 PVOID BaseAddress, Buffer; 372 ULONG RemainingLength, CurrentSize, ImageSize, ReadSize; 373 BOOLEAN ComputeSignature, ComputeHash, Completed; 374 BL_IMG_FILE FileHandle; 375 ULONGLONG ByteOffset; 376 PHYSICAL_ADDRESS PhysicalAddress; 377 378 /* Initialize variables */ 379 BaseAddress = 0; 380 ImageSize = 0; 381 Completed = FALSE; 382 RtlZeroMemory(&FileHandle, sizeof(FileHandle)); 383 384 /* Check for missing parameters */ 385 if (!MappedBase) 386 { 387 Status = STATUS_INVALID_PARAMETER; 388 goto Quickie; 389 } 390 if (!FileName) 391 { 392 Status = STATUS_INVALID_PARAMETER; 393 goto Quickie; 394 } 395 if (!MappedSize) 396 { 397 Status = STATUS_INVALID_PARAMETER; 398 goto Quickie; 399 } 400 401 /* Check if the image buffer is being provided */ 402 if (ImageFlags & BL_LOAD_IMG_EXISTING_BUFFER) 403 { 404 /* An existing base must already exist */ 405 if (!(*MappedBase)) 406 { 407 Status = STATUS_INVALID_PARAMETER; 408 goto Quickie; 409 } 410 } 411 412 /* Check of a hash is being requested */ 413 if (ImageFlags & BL_LOAD_IMG_COMPUTE_HASH) 414 { 415 /* Make sure we can return the hash */ 416 if (!HashBuffer) 417 { 418 Status = STATUS_INVALID_PARAMETER; 419 goto Quickie; 420 } 421 if (!HashSize) 422 { 423 Status = STATUS_INVALID_PARAMETER; 424 goto Quickie; 425 } 426 } 427 428 /* Check for invalid combination of parameters */ 429 if ((ImageFlags & BL_LOAD_IMG_COMPUTE_HASH) && (ImageFlags & 0x270)) 430 { 431 Status = STATUS_INVALID_PARAMETER; 432 goto Quickie; 433 } 434 435 /* Initialize hash if requested by caller */ 436 if (HashBuffer) 437 { 438 *HashBuffer = 0; 439 } 440 441 /* Do the same for the hash size */ 442 if (HashSize) 443 { 444 *HashSize = 0; 445 } 446 447 /* Open the image file */ 448 Status = ImgpOpenFile(DeviceId, FileName, DeviceId, &FileHandle); 449 if (!NT_SUCCESS(Status)) 450 { 451 EfiPrintf(L"Error opening file: %lx\r\n", Status); 452 goto Quickie; 453 } 454 455 /* Get the size of the image */ 456 Status = ImgpGetFileSize(&FileHandle, &ImageSize); 457 if (!NT_SUCCESS(Status)) 458 { 459 EfiPrintf(L"Error getting file size: %lx\r\n", Status); 460 goto Quickie; 461 } 462 463 /* Read the current base address */ 464 BaseAddress = *MappedBase; 465 if (ImageFlags & BL_LOAD_IMG_EXISTING_BUFFER) 466 { 467 /* Check if the current buffer is too small */ 468 if (*MappedSize < ImageSize) 469 { 470 /* Return the required size of the buffer */ 471 *MappedSize = ImageSize; 472 Status = STATUS_BUFFER_TOO_SMALL; 473 } 474 } 475 else 476 { 477 /* A buffer was not provided, allocate one ourselves */ 478 Status = BlImgAllocateImageBuffer(&BaseAddress, 479 MemoryType, 480 ImageSize, 481 ImageFlags); 482 } 483 484 /* Bail out if allocation failed */ 485 if (!NT_SUCCESS(Status)) 486 { 487 goto Quickie; 488 } 489 490 /* Set the initial byte offset and length to read */ 491 RemainingLength = ImageSize; 492 ByteOffset = 0; 493 Buffer = BaseAddress; 494 495 /* Update the initial progress */ 496 Completed = FALSE; 497 if (ShowProgress) 498 { 499 BlUtlUpdateProgress(0, &Completed); 500 ShowProgress &= (Completed != 0) - 1; 501 } 502 503 /* Set the chunk size for each read */ 504 ReadSize = 0x100000; 505 if (ReadSize > ImageSize) 506 { 507 ReadSize = ImageSize; 508 } 509 510 /* Check if we should compute hash and/or signatures */ 511 ComputeSignature = ImageFlags & BL_LOAD_IMG_COMPUTE_SIGNATURE; 512 ComputeHash = FALSE; 513 if ((ComputeSignature) || (ImageFlags & BL_LOAD_IMG_COMPUTE_HASH)) 514 { 515 ComputeHash = TRUE; 516 // todo: crypto is hard 517 } 518 519 /* Begin the read loop */ 520 while (RemainingLength) 521 { 522 /* Check if we've got more than a chunk left to read */ 523 if (RemainingLength > ReadSize) 524 { 525 /* Read a chunk*/ 526 CurrentSize = ReadSize; 527 } 528 else 529 { 530 /* Read only what's left */ 531 CurrentSize = RemainingLength; 532 } 533 534 /* Read the chunk */ 535 Status = ImgpReadAtFileOffset(&FileHandle, 536 CurrentSize, 537 ByteOffset, 538 Buffer, 539 0); 540 if (!NT_SUCCESS(Status)) 541 { 542 goto Quickie; 543 } 544 545 /* Check if we need to compute the hash of this chunk */ 546 if (ComputeHash) 547 { 548 // todo: crypto is hard 549 } 550 551 /* Update our position and read information */ 552 Buffer = (PVOID)((ULONG_PTR)Buffer + CurrentSize); 553 RemainingLength -= CurrentSize; 554 ByteOffset += CurrentSize; 555 556 /* Check if we should update the progress bar */ 557 if (ShowProgress) 558 { 559 /* Compute new percentage completed, check if we're done */ 560 BlUtlUpdateProgress(100 - 100 * RemainingLength / ImageSize, 561 &Completed); 562 ShowProgress &= (Completed != 0) - 1; 563 } 564 } 565 566 /* Is the read fully complete? We need to finalize the hash if requested */ 567 if (ComputeHash) 568 { 569 // todo: CRYPTO IS HARD 570 } 571 572 /* Success path, return back the buffer and the size of the image */ 573 *MappedBase = BaseAddress; 574 *MappedSize = ImageSize; 575 576 Quickie: 577 /* Close the file handle */ 578 ImgpCloseFile(&FileHandle); 579 580 /* Check if we failed and had allocated a buffer */ 581 if (!(NT_SUCCESS(Status)) && 582 (BaseAddress) && 583 !(ImageFlags & BL_LOAD_IMG_EXISTING_BUFFER)) 584 { 585 /* Check what kind of buffer we had allocated */ 586 if (ImageFlags & BL_LOAD_IMG_VIRTUAL_BUFFER) 587 { 588 /* Unmap and free the virtual buffer */ 589 PhysicalAddress.QuadPart = (ULONG_PTR)BaseAddress; 590 BlMmUnmapVirtualAddressEx(BaseAddress, ImageSize); 591 BlMmFreePhysicalPages(PhysicalAddress); 592 } 593 else 594 { 595 /* Free the physical buffer */ 596 MmPapFreePages(BaseAddress, BL_MM_INCLUDE_MAPPED_ALLOCATED); 597 } 598 } 599 600 /* If we hadn't gotten to 100% yet, do it now */ 601 if (ShowProgress) 602 { 603 BlUtlUpdateProgress(100, &Completed); 604 } 605 606 /* Return the final status */ 607 return Status; 608 } 609 610 PIMAGE_SECTION_HEADER 611 BlImgFindSection ( 612 _In_ PVOID ImageBase, 613 _In_ ULONG ImageSize 614 ) 615 { 616 PIMAGE_SECTION_HEADER FoundSection; 617 ULONG i; 618 PIMAGE_SECTION_HEADER SectionHeader; 619 PIMAGE_NT_HEADERS NtHeader; 620 NTSTATUS Status; 621 622 /* Assume failure */ 623 FoundSection = NULL; 624 625 /* Make sure the image is valid */ 626 Status = RtlImageNtHeaderEx(0, ImageBase, ImageSize, &NtHeader); 627 if (NT_SUCCESS(Status)) 628 { 629 /* Get the first section and loop through them all */ 630 SectionHeader = IMAGE_FIRST_SECTION(NtHeader); 631 for (i = 0; i < NtHeader->FileHeader.NumberOfSections; i++) 632 { 633 /* Check if this is the resource section */ 634 if (!_stricmp((PCCH)SectionHeader->Name, ".rsrc")) 635 { 636 /* Yep, we're done */ 637 FoundSection = SectionHeader; 638 break; 639 } 640 641 /* Nope, keep going */ 642 SectionHeader++; 643 } 644 } 645 646 /* Return the matching section */ 647 return FoundSection; 648 } 649 650 VOID 651 BlImgQueryCodeIntegrityBootOptions ( 652 _In_ PBL_LOADED_APPLICATION_ENTRY ApplicationEntry, 653 _Out_ PBOOLEAN IntegrityChecksDisabled, 654 _Out_ PBOOLEAN TestSigning 655 ) 656 { 657 658 NTSTATUS Status; 659 BOOLEAN Value; 660 661 /* Check if /DISABLEINTEGRITYCHECKS is on */ 662 Status = BlGetBootOptionBoolean(ApplicationEntry->BcdData, 663 BcdLibraryBoolean_DisableIntegrityChecks, 664 &Value); 665 *IntegrityChecksDisabled = NT_SUCCESS(Status) && (Value); 666 667 /* Check if /TESTSIGNING is on */ 668 Status = BlGetBootOptionBoolean(ApplicationEntry->BcdData, 669 BcdLibraryBoolean_AllowPrereleaseSignatures, 670 &Value); 671 *TestSigning = NT_SUCCESS(Status) && (Value); 672 } 673 674 NTSTATUS 675 BlImgUnLoadImage ( 676 _In_ PVOID ImageBase, 677 _In_ ULONG ImageSize, 678 _In_ ULONG ImageFlags 679 ) 680 { 681 /* Check for missing parameters */ 682 if (!(ImageSize) || !(ImageBase)) 683 { 684 /* Bail out */ 685 return STATUS_INVALID_PARAMETER; 686 } 687 688 /* Unallocate the image buffer */ 689 return BlImgUnallocateImageBuffer(ImageBase, ImageSize, ImageFlags); 690 } 691 692 NTSTATUS 693 ImgpLoadPEImage ( 694 _In_ PBL_IMG_FILE ImageFile, 695 _In_ BL_MEMORY_TYPE MemoryType, 696 _Inout_ PVOID* ImageBase, 697 _Out_opt_ PULONG ImageSize, 698 _Inout_opt_ PVOID Hash, 699 _In_ ULONG Flags 700 ) 701 { 702 NTSTATUS Status; 703 ULONG FileSize, HeaderSize; 704 BL_IMG_FILE LocalFileBuffer; 705 PBL_IMG_FILE LocalFile; 706 PVOID VirtualAddress, PreferredBase, ImageBuffer, CertBuffer, HashBuffer; 707 ULONGLONG VirtualSize; 708 PIMAGE_DATA_DIRECTORY CertDirectory; 709 PHYSICAL_ADDRESS PhysicalAddress; 710 PIMAGE_NT_HEADERS NtHeaders; 711 USHORT SectionCount, CheckSum, PartialSum, FinalSum; 712 PIMAGE_SECTION_HEADER Section; 713 ULONG_PTR EndOfHeaders, SectionStart, Slack, SectionEnd; 714 ULONG i, SectionSize, RawSize, BytesRead, RemainingLength, Offset, AlignSize; 715 BOOLEAN First, ImageHashValid; 716 UCHAR LocalBuffer[1024]; 717 UCHAR TrustedBootInformation[52]; 718 ULONG WorkaroundForBinutils; 719 720 /* Initialize locals */ 721 WorkaroundForBinutils = 0; 722 LocalFile = NULL; 723 ImageBuffer = NULL; 724 FileSize = 0; 725 First = FALSE; 726 VirtualAddress = NULL; 727 CertBuffer = NULL; 728 CertDirectory = NULL; 729 HashBuffer = NULL; 730 Offset = 0; 731 VirtualSize = 0; 732 ImageHashValid = FALSE; 733 RtlZeroMemory(&TrustedBootInformation, sizeof(TrustedBootInformation)); 734 735 /* Get the size of the image */ 736 Status = ImgpGetFileSize(ImageFile, &FileSize); 737 if (!NT_SUCCESS(Status)) 738 { 739 return STATUS_FILE_INVALID; 740 } 741 742 /* Allocate a flat buffer for it */ 743 Status = BlImgAllocateImageBuffer(&ImageBuffer, BlLoaderData, FileSize, 0); 744 if (!NT_SUCCESS(Status)) 745 { 746 goto Quickie; 747 } 748 749 /* Read the whole file flat for now */ 750 Status = ImgpReadAtFileOffset(ImageFile, FileSize, 0, ImageBuffer, NULL); 751 if (!NT_SUCCESS(Status)) 752 { 753 goto Quickie; 754 } 755 756 /* Build a local file handle */ 757 LocalFile = &LocalFileBuffer; 758 LocalFileBuffer.FileName = ImageFile->FileName; 759 LocalFileBuffer.Flags = BL_IMG_MEMORY_FILE | BL_IMG_VALID_FILE; 760 LocalFileBuffer.BaseAddress = ImageBuffer; 761 LocalFileBuffer.FileSize = FileSize; 762 763 /* Get the NT headers of the file */ 764 Status = RtlImageNtHeaderEx(0, ImageBuffer, FileSize, &NtHeaders); 765 if (!NT_SUCCESS(Status)) 766 { 767 goto Quickie; 768 } 769 770 /* Check if we should validate the machine type */ 771 if (Flags & BL_LOAD_PE_IMG_CHECK_MACHINE) 772 { 773 /* Is it different than our current machine type? */ 774 #if _M_AMD64 775 if (NtHeaders->FileHeader.Machine != IMAGE_FILE_MACHINE_AMD64) 776 #else 777 if (NtHeaders->FileHeader.Machine != IMAGE_FILE_MACHINE_I386) 778 #endif 779 { 780 /* Is it x86 (implying we are x64) ? */ 781 if (NtHeaders->FileHeader.Machine == IMAGE_FILE_MACHINE_I386) 782 { 783 /* Return special error code */ 784 Status = STATUS_INVALID_IMAGE_WIN_32; 785 } 786 else if (NtHeaders->FileHeader.Machine == IMAGE_FILE_MACHINE_AMD64) 787 { 788 /* Otherwise, it's x64 but we are x86 */ 789 Status = STATUS_INVALID_IMAGE_WIN_64; 790 } 791 else 792 { 793 /* Or it's ARM or something... */ 794 Status = STATUS_INVALID_IMAGE_FORMAT; 795 } 796 797 /* Return with the distinguished error code */ 798 goto Quickie; 799 } 800 } 801 802 /* Check if we should validate the subsystem */ 803 if (Flags & BL_LOAD_PE_IMG_CHECK_SUBSYSTEM) 804 { 805 /* It must be a Windows boot Application */ 806 if (NtHeaders->OptionalHeader.Subsystem != 807 IMAGE_SUBSYSTEM_WINDOWS_BOOT_APPLICATION) 808 { 809 Status = STATUS_INVALID_IMAGE_FORMAT; 810 goto Quickie; 811 } 812 } 813 814 /* Check if we should validate the /INTEGRITYCHECK flag */ 815 if (Flags & BL_LOAD_PE_IMG_CHECK_FORCED_INTEGRITY) 816 { 817 /* Check if it's there */ 818 if (!(NtHeaders->OptionalHeader.DllCharacteristics & 819 IMAGE_DLLCHARACTERISTICS_FORCE_INTEGRITY)) 820 { 821 /* Nope, fail otherwise */ 822 Status = STATUS_INVALID_IMAGE_FORMAT; 823 goto Quickie; 824 } 825 } 826 827 /* Check if we should compute the image hash */ 828 if ((Flags & BL_LOAD_PE_IMG_COMPUTE_HASH) || (Hash)) 829 { 830 EfiPrintf(L"No hash support\r\n"); 831 } 832 833 /* Read the current base address, if any */ 834 VirtualAddress = *ImageBase; 835 836 /* Get the virtual size of the image */ 837 VirtualSize = NtHeaders->OptionalHeader.SizeOfImage; 838 839 /* Safely align the virtual size to a page */ 840 Status = RtlULongLongAdd(VirtualSize, 841 PAGE_SIZE - 1, 842 &VirtualSize); 843 if (!NT_SUCCESS(Status)) 844 { 845 goto Quickie; 846 } 847 VirtualSize = ALIGN_DOWN_BY(VirtualSize, PAGE_SIZE); 848 849 /* Make sure the image isn't larger than 4GB */ 850 if (VirtualSize > ULONG_MAX) 851 { 852 Status = STATUS_INVALID_IMAGE_FORMAT; 853 goto Quickie; 854 } 855 856 /* Check if we have a buffer already */ 857 if (Flags & BL_LOAD_IMG_EXISTING_BUFFER) 858 { 859 /* Check if it's too small */ 860 if (*ImageSize < VirtualSize) 861 { 862 /* Fail, letting the caller know how big to make it */ 863 *ImageSize = VirtualSize; 864 Status = STATUS_BUFFER_TOO_SMALL; 865 } 866 } 867 else 868 { 869 /* Allocate the buffer with the flags and type the caller wants */ 870 Status = BlImgAllocateImageBuffer(&VirtualAddress, 871 MemoryType, 872 VirtualSize, 873 Flags); 874 } 875 876 /* Bail out if allocation failed, or existing buffer is too small */ 877 if (!NT_SUCCESS(Status)) 878 { 879 goto Quickie; 880 } 881 882 /* Read the size of the headers */ 883 HeaderSize = NtHeaders->OptionalHeader.SizeOfHeaders; 884 if (VirtualSize < HeaderSize) 885 { 886 /* Bail out if they're bigger than the image! */ 887 Status = STATUS_INVALID_IMAGE_FORMAT; 888 goto Quickie; 889 } 890 891 /* Now read the header into the buffer */ 892 Status = ImgpReadAtFileOffset(LocalFile, HeaderSize, 0, VirtualAddress, NULL); 893 if (!NT_SUCCESS(Status)) 894 { 895 goto Quickie; 896 } 897 898 /* Get the NT headers of the file */ 899 Status = RtlImageNtHeaderEx(0, VirtualAddress, HeaderSize, &NtHeaders); 900 if (!NT_SUCCESS(Status)) 901 { 902 goto Quickie; 903 } 904 905 First = FALSE; 906 907 /* Record how many sections we have */ 908 SectionCount = NtHeaders->FileHeader.NumberOfSections; 909 910 /* Capture the current checksum and reset it */ 911 CheckSum = NtHeaders->OptionalHeader.CheckSum; 912 NtHeaders->OptionalHeader.CheckSum = 0; 913 914 /* Calculate the checksum of the header, and restore the original one */ 915 PartialSum = BlUtlCheckSum(0, 916 VirtualAddress, 917 HeaderSize, 918 BL_UTL_CHECKSUM_COMPLEMENT | 919 BL_UTL_CHECKSUM_USHORT_BUFFER); 920 NtHeaders->OptionalHeader.CheckSum = CheckSum; 921 922 /* Record our current position (right after the headers) */ 923 EndOfHeaders = (ULONG_PTR)VirtualAddress + HeaderSize; 924 925 /* Get the first section and iterate through each one */ 926 Section = IMAGE_FIRST_SECTION(NtHeaders); 927 for (i = 0; i < SectionCount; i++) 928 { 929 /* Compute where this section starts */ 930 SectionStart = (ULONG_PTR)VirtualAddress + Section->VirtualAddress; 931 932 /* Make sure that the section fits within the image */ 933 if ((VirtualSize < Section->VirtualAddress) || 934 ((PVOID)SectionStart < VirtualAddress)) 935 { 936 EfiPrintf(L"fail 1\r\n"); 937 Status = STATUS_INVALID_IMAGE_FORMAT; 938 goto Quickie; 939 } 940 941 /* Check if there's slack space between header end and the section */ 942 if (!(First) && (EndOfHeaders < SectionStart)) 943 { 944 /* Zero it out */ 945 Slack = SectionStart - EndOfHeaders; 946 RtlZeroMemory((PVOID)EndOfHeaders, Slack); 947 } 948 949 /* Get the section virtual size and the raw size */ 950 SectionSize = Section->Misc.VirtualSize; 951 RawSize = Section->SizeOfRawData; 952 953 /* Safely align the raw size by 2 */ 954 Status = RtlULongAdd(RawSize, 1, &AlignSize); 955 if (!NT_SUCCESS(Status)) 956 { 957 goto Quickie; 958 } 959 AlignSize = ALIGN_DOWN_BY(AlignSize, 2); 960 961 /* IF we don't have a virtual size, use the raw size */ 962 if (!SectionSize) 963 { 964 SectionSize = RawSize; 965 } 966 967 /* If we don't have raw data, ignore the raw size */ 968 if (!Section->PointerToRawData) 969 { 970 RawSize = 0; 971 } 972 else if (SectionSize < RawSize) 973 { 974 /* And if the virtual size is smaller, use it as the final size */ 975 RawSize = SectionSize; 976 } 977 978 /* Make sure that the section doesn't overflow in memory */ 979 Status = RtlULongPtrAdd(Section->VirtualAddress, 980 SectionSize, 981 &SectionEnd); 982 if (!NT_SUCCESS(Status)) 983 { 984 EfiPrintf(L"fail 21\r\n"); 985 Status = STATUS_INVALID_IMAGE_FORMAT; 986 goto Quickie; 987 } 988 989 /* Make sure that it fits within the image */ 990 if (VirtualSize < SectionEnd) 991 { 992 Status = STATUS_INVALID_IMAGE_FORMAT; 993 goto Quickie; 994 } 995 996 /* Make sure it doesn't overflow on disk */ 997 Status = RtlULongPtrAdd(Section->VirtualAddress, 998 AlignSize, 999 &SectionEnd); 1000 if (!NT_SUCCESS(Status)) 1001 { 1002 EfiPrintf(L"fail 31\r\n"); 1003 Status = STATUS_INVALID_IMAGE_FORMAT; 1004 goto Quickie; 1005 } 1006 1007 /* Make sure that it fits within the disk image as well */ 1008 if (VirtualSize < SectionEnd) 1009 { 1010 Status = STATUS_INVALID_IMAGE_FORMAT; 1011 goto Quickie; 1012 } 1013 1014 /* So does this section have a valid size after all? */ 1015 if (RawSize) 1016 { 1017 /* Are we in the first iteration? */ 1018 if (!First) 1019 { 1020 /* FUCK YOU BINUTILS */ 1021 if (NtHeaders->OptionalHeader.MajorLinkerVersion < 7) 1022 { 1023 if ((*(PULONG)&Section->Name == 'ler.') && (RawSize < AlignSize)) 1024 { 1025 /* Piece of shit won't build relocations when you tell it to, 1026 * either by using --emit-relocs or --dynamicbase. People online 1027 * have found out that by using -pie-executable you can get this 1028 * to happen, but then it turns out that the .reloc section is 1029 * incorrectly sized, and results in a corrupt PE. However, they 1030 * still compute the checksum using the correct value. What idiots. 1031 */ 1032 WorkaroundForBinutils = AlignSize - RawSize; 1033 AlignSize -= WorkaroundForBinutils; 1034 } 1035 } 1036 1037 /* Yes, read the section data */ 1038 Status = ImgpReadAtFileOffset(LocalFile, 1039 AlignSize, 1040 Section->PointerToRawData, 1041 (PVOID)SectionStart, 1042 NULL); 1043 if (!NT_SUCCESS(Status)) 1044 { 1045 goto Quickie; 1046 } 1047 1048 /* Update our current offset */ 1049 Offset = AlignSize + Section->PointerToRawData; 1050 1051 /* Update the checksum to include this section */ 1052 PartialSum = BlUtlCheckSum(PartialSum, 1053 (PUCHAR)SectionStart, 1054 AlignSize, 1055 BL_UTL_CHECKSUM_COMPLEMENT | 1056 BL_UTL_CHECKSUM_USHORT_BUFFER); 1057 AlignSize += WorkaroundForBinutils; 1058 } 1059 } 1060 1061 /* Are we in the first iteration? */ 1062 if (!First) 1063 { 1064 /* Is there space at the end of the section? */ 1065 if (RawSize < SectionSize) 1066 { 1067 /* Zero out the slack space that's there */ 1068 Slack = SectionSize - RawSize; 1069 RtlZeroMemory((PVOID)(SectionStart + RawSize), Slack); 1070 } 1071 1072 /* Update our tail offset */ 1073 EndOfHeaders = SectionStart + SectionSize; 1074 } 1075 1076 /* Move to the next section */ 1077 Section++; 1078 } 1079 1080 /* Are we in the first iteration? */ 1081 if (!First) 1082 { 1083 /* Go to the end of the file */ 1084 SectionStart = (ULONG_PTR)VirtualAddress + VirtualSize; 1085 1086 /* Is there still some slack space left? */ 1087 if (EndOfHeaders < SectionStart) 1088 { 1089 /* Zero it out */ 1090 Slack = SectionStart - EndOfHeaders; 1091 RtlZeroMemory((PVOID)EndOfHeaders, Slack); 1092 } 1093 } 1094 1095 /* Did the first iteration complete OK? */ 1096 if ((NT_SUCCESS(Status)) && !(First)) 1097 { 1098 /* Check how many non-image bytes are left in the file */ 1099 RemainingLength = FileSize - Offset; 1100 while (RemainingLength) 1101 { 1102 /* See if the read will fit into our local buffer */ 1103 if (RemainingLength >= sizeof(LocalBuffer)) 1104 { 1105 /* Nope, cap it */ 1106 BytesRead = sizeof(LocalBuffer); 1107 } 1108 else 1109 { 1110 /* Yes, but there's less to read */ 1111 BytesRead = RemainingLength; 1112 } 1113 1114 /* Read 1024 bytes into the local buffer */ 1115 Status = ImgpReadAtFileOffset(LocalFile, 1116 BytesRead, 1117 Offset, 1118 LocalBuffer, 1119 &BytesRead); 1120 if (!(NT_SUCCESS(Status)) || !(BytesRead)) 1121 { 1122 Status = STATUS_FILE_INVALID; 1123 goto Quickie; 1124 } 1125 1126 /* Advance the offset and reduce the length */ 1127 RemainingLength -= BytesRead; 1128 Offset += BytesRead; 1129 1130 /* Compute the checksum of this leftover space */ 1131 PartialSum = BlUtlCheckSum(PartialSum, 1132 LocalBuffer, 1133 BytesRead, 1134 BL_UTL_CHECKSUM_COMPLEMENT | 1135 BL_UTL_CHECKSUM_USHORT_BUFFER); 1136 } 1137 1138 /* Finally, calculate the final checksum and compare it */ 1139 FinalSum = FileSize + PartialSum + WorkaroundForBinutils; 1140 if ((FinalSum != CheckSum) && (PartialSum == 0xFFFF)) 1141 { 1142 /* It hit overflow, so set it to the file size */ 1143 FinalSum = FileSize; 1144 } 1145 1146 /* If the checksum doesn't match, and caller is enforcing, bail out */ 1147 if ((FinalSum != CheckSum) && 1148 !(Flags & BL_LOAD_PE_IMG_IGNORE_CHECKSUM_MISMATCH)) 1149 { 1150 Status = STATUS_IMAGE_CHECKSUM_MISMATCH; 1151 goto Quickie; 1152 } 1153 } 1154 1155 /* Check if the .rsrc section should be checked with the filename */ 1156 if (Flags & BL_LOAD_PE_IMG_VALIDATE_ORIGINAL_FILENAME) 1157 { 1158 EfiPrintf(L"Not yet supported\r\n"); 1159 Status = 0xC0430007; // STATUS_SECUREBOOT_FILE_REPLACED 1160 goto Quickie; 1161 } 1162 1163 /* Check if we should relocate */ 1164 if (!(Flags & BL_LOAD_PE_IMG_SKIP_RELOCATIONS)) 1165 { 1166 /* Check if we loaded at a different address */ 1167 PreferredBase = (PVOID)NtHeaders->OptionalHeader.ImageBase; 1168 if (VirtualAddress != PreferredBase) 1169 { 1170 /* Yep -- do relocations */ 1171 Status = LdrRelocateImage(VirtualAddress, 1172 "Boot Environment Library", 1173 STATUS_SUCCESS, 1174 STATUS_UNSUCCESSFUL, 1175 STATUS_INVALID_IMAGE_FORMAT); 1176 if (!NT_SUCCESS(Status)) 1177 { 1178 /* That's bad */ 1179 goto Quickie; 1180 } 1181 } 1182 } 1183 1184 #if BL_TPM_SUPPORT 1185 /* Check if the image hash was valid */ 1186 if (!ImageHashValid) 1187 { 1188 /* Send a TPM/SI notification without a context */ 1189 BlEnNotifyEvent(0x10000002, NULL); 1190 } 1191 1192 /* Now send a TPM/SI notification with the hash of the loaded image */ 1193 BlMmTranslateVirtualAddress(VirtualAddress, &Context.ImageBase); 1194 Context.HashAlgorithm = HashAlgorithm; 1195 Context.HashSize = HashSize; 1196 Context.FileName = ImageFile->FileName; 1197 Context.ImageSize = VirtualSize; 1198 Context.HashValid = ImageHashValid; 1199 Context.Hash = Hash; 1200 BlEnNotifyEvent(0x10000002, &Context); 1201 #endif 1202 1203 /* Return the loaded address to the caller */ 1204 *ImageBase = VirtualAddress; 1205 1206 /* If the caller wanted the image size, return it too */ 1207 if (ImageSize) 1208 { 1209 *ImageSize = VirtualSize; 1210 } 1211 1212 Quickie: 1213 /* Check if we computed the image hash OK */ 1214 if (ImageHashValid) 1215 { 1216 /* Then free the information that ImgpValidateImageHash set up */ 1217 EfiPrintf(L"leadking trusted boot\r\n"); 1218 //ImgpDestroyTrustedBootInformation(&TrustedBootInformation); 1219 } 1220 1221 /* Check if we had a hash buffer */ 1222 if (HashBuffer) 1223 { 1224 /* Free it */ 1225 MmPapFreePages(HashBuffer, BL_MM_INCLUDE_MAPPED_ALLOCATED); 1226 } 1227 1228 /* Check if we have a certificate directory */ 1229 if ((CertBuffer) && (CertDirectory)) 1230 { 1231 /* Free it */ 1232 BlImgUnallocateImageBuffer(CertBuffer, CertDirectory->Size, 0); 1233 } 1234 1235 /* Check if we had an image buffer allocated */ 1236 if ((ImageBuffer) && (FileSize)) 1237 { 1238 /* Free it */ 1239 BlImgUnallocateImageBuffer(ImageBuffer, FileSize, 0); 1240 } 1241 1242 /* Check if we had a local file handle */ 1243 if (LocalFile) 1244 { 1245 /* Close it */ 1246 ImgpCloseFile(LocalFile); 1247 } 1248 1249 /* Check if this is the failure path */ 1250 if (!NT_SUCCESS(Status)) 1251 { 1252 /* Check if we had started mapping in the image already */ 1253 if ((VirtualAddress) && !(Flags & BL_LOAD_PE_IMG_EXISTING_BUFFER)) 1254 { 1255 /* Into a virtual buffer? */ 1256 if (Flags & BL_LOAD_PE_IMG_VIRTUAL_BUFFER) 1257 { 1258 /* Unmap and free it */ 1259 BlMmUnmapVirtualAddressEx(VirtualAddress, VirtualSize); 1260 PhysicalAddress.QuadPart = (ULONG_PTR)VirtualAddress; 1261 BlMmFreePhysicalPages(PhysicalAddress); 1262 } 1263 else 1264 { 1265 /* Into a physical buffer -- free it */ 1266 MmPapFreePages(VirtualAddress, BL_MM_INCLUDE_MAPPED_ALLOCATED); 1267 } 1268 } 1269 } 1270 1271 /* Return back to caller */ 1272 return Status; 1273 } 1274 1275 NTSTATUS 1276 BlImgLoadPEImageEx ( 1277 _In_ ULONG DeviceId, 1278 _In_ BL_MEMORY_TYPE MemoryType, 1279 _In_ PWCHAR Path, 1280 _Out_ PVOID* ImageBase, 1281 _Out_ PULONG ImageSize, 1282 _Out_ PVOID Hash, 1283 _In_ ULONG Flags 1284 ) 1285 { 1286 BL_IMG_FILE ImageFile; 1287 NTSTATUS Status; 1288 1289 /* Initialize the image file structure */ 1290 ImageFile.Flags = 0; 1291 ImageFile.FileName = NULL; 1292 1293 /* Check if the required parameter are missing */ 1294 if (!(ImageBase) || !(Path)) 1295 { 1296 return STATUS_INVALID_PARAMETER; 1297 } 1298 1299 /* If we are loading a pre-allocated image, make sure we have it */ 1300 if ((Flags & BL_LOAD_IMG_EXISTING_BUFFER) && (!(*ImageBase) || !(ImageSize))) 1301 { 1302 return STATUS_INVALID_PARAMETER; 1303 } 1304 1305 /* Load the file from disk */ 1306 Status = ImgpOpenFile(DeviceId, Path, 0, &ImageFile); 1307 if (NT_SUCCESS(Status)) 1308 { 1309 /* If that worked, do the PE parsing */ 1310 Status = ImgpLoadPEImage(&ImageFile, 1311 MemoryType, 1312 ImageBase, 1313 ImageSize, 1314 Hash, 1315 Flags); 1316 } 1317 1318 /* Close the image file and return back to caller */ 1319 ImgpCloseFile(&ImageFile); 1320 return Status; 1321 } 1322 1323 NTSTATUS 1324 BlImgLoadBootApplication ( 1325 _In_ PBL_LOADED_APPLICATION_ENTRY BootEntry, 1326 _Out_ PULONG AppHandle 1327 ) 1328 { 1329 NTSTATUS Status; 1330 PULONGLONG AllowedList; 1331 ULONGLONG AllowedCount; 1332 ULONG i, DeviceId, ImageSize, Flags, ListSize; 1333 LARGE_INTEGER Frequency; 1334 PVOID UnlockCode, ImageBase; 1335 PBL_DEVICE_DESCRIPTOR Device, BitLockerDevice; 1336 PWCHAR Path; 1337 PBL_APPLICATION_ENTRY AppEntry; 1338 PBL_IMG_FILE ImageFile; 1339 BOOLEAN DisableIntegrity, TestSigning; 1340 UCHAR Hash[64]; 1341 PBL_IMAGE_APPLICATION_ENTRY ImageAppEntry; 1342 1343 /* Initialize all locals */ 1344 BitLockerDevice = NULL; 1345 UnlockCode = NULL; 1346 ImageFile = NULL; 1347 DeviceId = -1; 1348 Device = NULL; 1349 ImageAppEntry = NULL; 1350 AppEntry = NULL; 1351 Path = NULL; 1352 ImageSize = 0; 1353 ImageBase = NULL; 1354 1355 /* Check for "allowed in-memory settings" */ 1356 Status = BlpGetBootOptionIntegerList(BootEntry->BcdData, 1357 BcdLibraryIntegerList_AllowedInMemorySettings, 1358 &AllowedList, 1359 &AllowedCount, 1360 TRUE); 1361 if (Status == STATUS_SUCCESS) 1362 { 1363 /* Loop through the list of allowed setting */ 1364 for (i = 0; i < AllowedCount; i++) 1365 { 1366 /* Find the super undocumented one */ 1367 if (AllowedList[i] == BcdLibraryInteger_UndocumentedMagic) 1368 { 1369 /* If it's present, append the current perf frequence to it */ 1370 BlTimeQueryPerformanceCounter(&Frequency); 1371 BlAppendBootOptionInteger(BootEntry, 1372 BcdLibraryInteger_UndocumentedMagic, 1373 Frequency.QuadPart); 1374 } 1375 } 1376 } 1377 1378 #if BL_BITLOCKER_SUPPORT 1379 /* Do bitlocker stuff */ 1380 Status = BlFveSecureBootUnlockBootDevice(BootEntry, &BitLockerDevice, &UnlockCode); 1381 if (!NT_SUCCESS(Status)) 1382 { 1383 goto Quickie; 1384 } 1385 #endif 1386 1387 /* Get the device on which this application is on*/ 1388 Status = BlGetBootOptionDevice(BootEntry->BcdData, 1389 BcdLibraryDevice_ApplicationDevice, 1390 &Device, 1391 NULL); 1392 if (!NT_SUCCESS(Status)) 1393 { 1394 goto Quickie; 1395 } 1396 1397 /* Get the path of the application */ 1398 Status = BlGetBootOptionString(BootEntry->BcdData, 1399 BcdLibraryString_ApplicationPath, 1400 &Path); 1401 if (!NT_SUCCESS(Status)) 1402 { 1403 goto Quickie; 1404 } 1405 1406 /* Open the device */ 1407 Status = BlpDeviceOpen(Device, 1408 BL_DEVICE_READ_ACCESS, 1409 0, 1410 &DeviceId); 1411 if (!NT_SUCCESS(Status)) 1412 { 1413 goto Quickie; 1414 } 1415 1416 /* Check for integrity BCD options */ 1417 BlImgQueryCodeIntegrityBootOptions(BootEntry, 1418 &DisableIntegrity, 1419 &TestSigning); 1420 1421 #if BL_TPM_SUPPORT 1422 RtlZeroMemory(&Context, sizeof(Context); 1423 Context.BootEntry = BootEntry; 1424 BlEnNotifyEvent(0x10000003, &Context); 1425 #endif 1426 1427 /* Enable signing and hashing checks if integrity is enabled */ 1428 Flags = 0; 1429 if (!DisableIntegrity) 1430 { 1431 Flags = 0x8070; 1432 } 1433 1434 /* Now call the PE loader to load the image */ 1435 Status = BlImgLoadPEImageEx(DeviceId, 1436 BlLoaderMemory, 1437 Path, 1438 &ImageBase, 1439 &ImageSize, 1440 Hash, 1441 Flags); 1442 if (!NT_SUCCESS(Status)) 1443 { 1444 goto Quickie; 1445 } 1446 1447 #if BL_KD_SUPPORT 1448 /* Check if we should notify the debugger of load */ 1449 if (BdDebugTransitions) 1450 { 1451 /* Initialize it */ 1452 BdForceDebug = 1; 1453 Status = BlBdInitialize(); 1454 if (NT_SUCCESS(Status)) 1455 { 1456 /* Check if it's enabled */ 1457 if (BlBdDebuggerEnabled()) 1458 { 1459 /* Send it an image load notification */ 1460 BdDebuggerNotPresent = FALSE; 1461 RtlInitUnicodeString(&PathString, Path); 1462 BlBdLoadImageSymbols(&PathString, ImageBase); 1463 } 1464 } 1465 } 1466 #endif 1467 1468 #if BL_BITLOCKER_SUPPORT 1469 /* Do bitlocker stuff */ 1470 Status = BlSecureBootCheckPolicyOnFveDevice(BitLockerDevice); 1471 if (!NT_SUCCESS(Status)) 1472 { 1473 goto Quickie; 1474 } 1475 #endif 1476 1477 #if BL_BITLOCKER_SUPPORT 1478 /* Do bitlocker stuff */ 1479 Status = BlFveSecureBootCheckpointBootApp(BootEntry, BitLockerDevice, Hash, UnlockCode); 1480 if (!NT_SUCCESS(Status)) 1481 { 1482 goto Quickie; 1483 } 1484 #endif 1485 1486 /* Get the BCD option size */ 1487 ListSize = BlGetBootOptionListSize(BootEntry->BcdData); 1488 1489 /* Allocate an entry with all the BCD options */ 1490 AppEntry = BlMmAllocateHeap(ListSize + sizeof(*AppEntry)); 1491 if (!AppEntry) 1492 { 1493 Status = STATUS_NO_MEMORY; 1494 goto Quickie; 1495 } 1496 1497 /* Zero it out */ 1498 RtlZeroMemory(AppEntry, sizeof(*AppEntry)); 1499 1500 /* Initialize it */ 1501 strcpy(AppEntry->Signature, "BTAPENT"); 1502 AppEntry->Guid = BootEntry->Guid; 1503 AppEntry->Flags = BootEntry->Flags; 1504 1505 /* Copy the BCD options */ 1506 RtlCopyMemory(&AppEntry->BcdData, BootEntry->BcdData, ListSize); 1507 1508 /* Allocate the image entry */ 1509 ImageAppEntry = BlMmAllocateHeap(sizeof(*ImageAppEntry)); 1510 if (!ImageAppEntry) 1511 { 1512 Status = STATUS_NO_MEMORY; 1513 goto Quickie; 1514 } 1515 1516 /* Initialize it */ 1517 ImageAppEntry->ImageBase = ImageBase; 1518 ImageAppEntry->ImageSize = ImageSize; 1519 ImageAppEntry->AppEntry = AppEntry; 1520 1521 /* Check if this is the first entry */ 1522 if (!IapTableEntries) 1523 { 1524 /* Allocate two entries */ 1525 IapAllocatedTableEntries = 0; 1526 IapTableEntries = 2; 1527 IapImageTable = BlMmAllocateHeap(IapTableEntries * sizeof(PVOID)); 1528 if (!IapImageTable) 1529 { 1530 Status = STATUS_NO_MEMORY; 1531 goto Quickie; 1532 } 1533 1534 /* Zero out the entries for now */ 1535 RtlZeroMemory(IapImageTable, IapTableEntries * sizeof(PVOID)); 1536 } 1537 1538 /* Set this entry into the table */ 1539 Status = BlTblSetEntry(&IapImageTable, 1540 &IapTableEntries, 1541 ImageAppEntry, 1542 AppHandle, 1543 TblDoNotPurgeEntry); 1544 1545 Quickie: 1546 /* Is the device open? Close it if so */ 1547 if (DeviceId != 1) 1548 { 1549 BlDeviceClose(DeviceId); 1550 } 1551 1552 /* Is there an allocated device? Free it */ 1553 if (Device) 1554 { 1555 BlMmFreeHeap(Device); 1556 } 1557 1558 /* Is there an allocated path? Free it */ 1559 if (Path) 1560 { 1561 BlMmFreeHeap(Path); 1562 } 1563 1564 /* Is there a bitlocker device? Free it */ 1565 if (BitLockerDevice) 1566 { 1567 BlMmFreeHeap(BitLockerDevice); 1568 } 1569 1570 /* Is there a bitlocker unlock code? Free it */ 1571 if (UnlockCode) 1572 { 1573 BlMmFreeHeap(UnlockCode); 1574 } 1575 1576 /* Did we succeed in creating an entry? */ 1577 if (NT_SUCCESS(Status)) 1578 { 1579 /* Remember there's one more in the table */ 1580 IapAllocatedTableEntries++; 1581 1582 /* Return success */ 1583 return Status; 1584 } 1585 1586 /* Did we load an image after all? */ 1587 if (ImageBase) 1588 { 1589 /* Unload it */ 1590 BlImgUnLoadImage(ImageBase, ImageSize, 0); 1591 } 1592 1593 /* Did we allocate an app entry? Free it */ 1594 if (AppEntry) 1595 { 1596 BlMmFreeHeap(AppEntry); 1597 } 1598 1599 /* Do we have an image file entry? Free it */ 1600 if (ImageFile) 1601 { 1602 BlMmFreeHeap(ImageFile); 1603 } 1604 1605 /* Do we no longer have a single entry in the table? */ 1606 if (!(IapAllocatedTableEntries) && (IapImageTable)) 1607 { 1608 /* Free and destroy the table */ 1609 BlMmFreeHeap(IapImageTable); 1610 IapTableEntries = 0; 1611 IapImageTable = NULL; 1612 } 1613 1614 /* Return the failure code */ 1615 return Status; 1616 } 1617 1618 NTSTATUS 1619 BlpPdParseReturnArguments ( 1620 _In_ PBL_RETURN_ARGUMENTS ReturnArguments 1621 ) 1622 { 1623 /* Check if any custom data was returned */ 1624 if (ReturnArguments->DataPage == 0) 1625 { 1626 /* Nope, nothing to do */ 1627 return STATUS_SUCCESS; 1628 } 1629 1630 /* Yes, we have to parse it */ 1631 EfiPrintf(L"Return arguments not supported\r\n"); 1632 return STATUS_NOT_IMPLEMENTED; 1633 } 1634 1635 NTSTATUS 1636 ImgpCopyApplicationBootDevice ( 1637 __in PBL_DEVICE_DESCRIPTOR DestinationDevice, 1638 __in PBL_DEVICE_DESCRIPTOR SourceDevice 1639 ) 1640 { 1641 /* Is this a partition device? */ 1642 if (SourceDevice->DeviceType != PartitionDevice) 1643 { 1644 /* It's not -- a simple copy will do */ 1645 RtlCopyMemory(DestinationDevice, SourceDevice, SourceDevice->Size); 1646 return STATUS_SUCCESS; 1647 } 1648 1649 /* TODO */ 1650 EfiPrintf(L"Partition copy not supported\r\n"); 1651 return STATUS_NOT_IMPLEMENTED; 1652 1653 } 1654 1655 NTSTATUS 1656 ImgpInitializeBootApplicationParameters ( 1657 _In_ PBL_BUFFER_DESCRIPTOR ImageParameters, 1658 _In_ PBL_APPLICATION_ENTRY AppEntry, 1659 _In_ PVOID ImageBase, 1660 _In_ ULONG ImageSize 1661 ) 1662 { 1663 NTSTATUS Status; 1664 PIMAGE_NT_HEADERS NtHeaders; 1665 BL_BUFFER_DESCRIPTOR MemoryParameters; 1666 LIST_ENTRY MemoryList; 1667 PBL_FIRMWARE_DESCRIPTOR FirmwareParameters; 1668 PBL_DEVICE_DESCRIPTOR BootDevice; 1669 PBL_MEMORY_DATA MemoryData; 1670 PBL_APPLICATION_ENTRY BootAppEntry; 1671 PBL_RETURN_ARGUMENTS ReturnArguments; 1672 PBOOT_APPLICATION_PARAMETER_BLOCK ParameterBlock; 1673 ULONG EntrySize, BufferSize; 1674 1675 /* Get the image headers and validate it */ 1676 Status = RtlImageNtHeaderEx(0, ImageBase, ImageSize, &NtHeaders); 1677 if (!NT_SUCCESS(Status)) 1678 { 1679 return Status; 1680 } 1681 1682 /* Get the size of the entire non-firmware, allocated, memory map */ 1683 MemoryParameters.BufferSize = 0; 1684 Status = BlMmGetMemoryMap(&MemoryList, 1685 &MemoryParameters, 1686 BL_MM_INCLUDE_PERSISTENT_MEMORY | 1687 BL_MM_INCLUDE_MAPPED_ALLOCATED | 1688 BL_MM_INCLUDE_MAPPED_UNALLOCATED | 1689 BL_MM_INCLUDE_UNMAPPED_ALLOCATED | 1690 BL_MM_INCLUDE_RESERVED_ALLOCATED, 1691 0); 1692 if ((Status != STATUS_BUFFER_TOO_SMALL) && (Status != STATUS_SUCCESS)) 1693 { 1694 /* We failed due to an unknown reason -- bail out */ 1695 return Status; 1696 } 1697 1698 /* Compute the list of the BCD plus the application entry */ 1699 EntrySize = BlGetBootOptionListSize(&AppEntry->BcdData) + 1700 FIELD_OFFSET(BL_APPLICATION_ENTRY, BcdData); 1701 1702 /* Compute the total size required for the entire structure */ 1703 BufferSize = EntrySize + 1704 BlpBootDevice->Size + 1705 MemoryParameters.BufferSize + 1706 sizeof(*ReturnArguments) + 1707 sizeof(*MemoryData) + 1708 sizeof(*FirmwareParameters) + 1709 sizeof(*ParameterBlock); 1710 1711 /* Check if this gives us enough space */ 1712 if (ImageParameters->BufferSize < BufferSize) 1713 { 1714 /* It does not -- free the existing buffer */ 1715 if (ImageParameters->BufferSize) 1716 { 1717 BlMmFreeHeap(ImageParameters->Buffer); 1718 } 1719 1720 /* Allocate a new buffer of sufficient size */ 1721 ImageParameters->BufferSize = BufferSize; 1722 ImageParameters->Buffer = BlMmAllocateHeap(BufferSize); 1723 if (!ImageParameters->Buffer) 1724 { 1725 /* Bail out if we couldn't allocate it */ 1726 return STATUS_NO_MEMORY; 1727 } 1728 } 1729 1730 /* Zero out the parameter block */ 1731 ParameterBlock = (PBOOT_APPLICATION_PARAMETER_BLOCK)ImageParameters->Buffer; 1732 RtlZeroMemory(ParameterBlock, BufferSize); 1733 1734 /* Initialize it */ 1735 ParameterBlock->Version = BOOT_APPLICATION_VERSION; 1736 ParameterBlock->Size = BufferSize; 1737 ParameterBlock->Signature[0] = BOOT_APPLICATION_SIGNATURE_1; 1738 ParameterBlock->Signature[1] = BOOT_APPLICATION_SIGNATURE_2; 1739 ParameterBlock->MemoryTranslationType = MmTranslationType; 1740 ParameterBlock->ImageType = IMAGE_FILE_MACHINE_I386; 1741 ParameterBlock->ImageBase = (ULONG_PTR)ImageBase; 1742 ParameterBlock->ImageSize = NtHeaders->OptionalHeader.SizeOfImage; 1743 1744 /* Get the offset to the memory data */ 1745 ParameterBlock->MemoryDataOffset = sizeof(*ParameterBlock); 1746 1747 /* Fill it out */ 1748 MemoryData = (PBL_MEMORY_DATA)((ULONG_PTR)ParameterBlock + 1749 ParameterBlock->MemoryDataOffset); 1750 MemoryData->Version = BL_MEMORY_DATA_VERSION; 1751 MemoryData->MdListOffset = sizeof(*MemoryData); 1752 MemoryData->DescriptorSize = sizeof(BL_MEMORY_DESCRIPTOR); 1753 MemoryData->DescriptorOffset = FIELD_OFFSET(BL_MEMORY_DESCRIPTOR, BasePage); 1754 1755 /* And populate the memory map */ 1756 MemoryParameters.Buffer = MemoryData + 1; 1757 Status = BlMmGetMemoryMap(&MemoryList, 1758 &MemoryParameters, 1759 BL_MM_INCLUDE_PERSISTENT_MEMORY | 1760 BL_MM_INCLUDE_MAPPED_ALLOCATED | 1761 BL_MM_INCLUDE_MAPPED_UNALLOCATED | 1762 BL_MM_INCLUDE_UNMAPPED_ALLOCATED | 1763 BL_MM_INCLUDE_RESERVED_ALLOCATED, 1764 0); 1765 if (!NT_SUCCESS(Status)) 1766 { 1767 return Status; 1768 } 1769 1770 /* Now that we have the map, indicate the number of descriptors */ 1771 MemoryData->DescriptorCount = MemoryParameters.ActualSize / 1772 MemoryData->DescriptorSize; 1773 1774 /* Get the offset to the application entry */ 1775 ParameterBlock->AppEntryOffset = ParameterBlock->MemoryDataOffset + 1776 MemoryData->MdListOffset + 1777 MemoryParameters.BufferSize; 1778 1779 /* Fill it out */ 1780 BootAppEntry = (PBL_APPLICATION_ENTRY)((ULONG_PTR)ParameterBlock + 1781 ParameterBlock->AppEntryOffset); 1782 RtlCopyMemory(BootAppEntry, AppEntry, EntrySize); 1783 1784 /* Get the offset to the boot device */ 1785 ParameterBlock->BootDeviceOffset = ParameterBlock->AppEntryOffset + 1786 EntrySize; 1787 1788 /* Fill it out */ 1789 BootDevice = (PBL_DEVICE_DESCRIPTOR)((ULONG_PTR)ParameterBlock + 1790 ParameterBlock->BootDeviceOffset); 1791 Status = ImgpCopyApplicationBootDevice(BootDevice, BlpBootDevice); 1792 if (!NT_SUCCESS(Status)) 1793 { 1794 return Status; 1795 } 1796 1797 /* Get the offset to the firmware data */ 1798 ParameterBlock->FirmwareParametersOffset = ParameterBlock->BootDeviceOffset + 1799 BootDevice->Size; 1800 1801 /* Fill it out */ 1802 FirmwareParameters = (PBL_FIRMWARE_DESCRIPTOR)((ULONG_PTR)ParameterBlock + 1803 ParameterBlock-> 1804 FirmwareParametersOffset); 1805 Status = BlFwGetParameters(FirmwareParameters); 1806 if (!NT_SUCCESS(Status)) 1807 { 1808 return Status; 1809 } 1810 1811 /* Get the offset to the return arguments */ 1812 ParameterBlock->ReturnArgumentsOffset = ParameterBlock->FirmwareParametersOffset + 1813 sizeof(BL_FIRMWARE_DESCRIPTOR); 1814 1815 /* Fill them out */ 1816 ReturnArguments = (PBL_RETURN_ARGUMENTS)((ULONG_PTR)ParameterBlock + 1817 ParameterBlock-> 1818 ReturnArgumentsOffset); 1819 ReturnArguments->Version = BL_RETURN_ARGUMENTS_VERSION; 1820 ReturnArguments->DataPage = 0; 1821 ReturnArguments->DataSize = 0; 1822 1823 /* Structure complete */ 1824 ImageParameters->ActualSize = ParameterBlock->ReturnArgumentsOffset + 1825 sizeof(*ReturnArguments); 1826 return STATUS_SUCCESS; 1827 } 1828 1829 NTSTATUS 1830 ImgArchEfiStartBootApplication ( 1831 _In_ PBL_APPLICATION_ENTRY AppEntry, 1832 _In_ PVOID ImageBase, 1833 _In_ ULONG ImageSize, 1834 _In_ PBL_RETURN_ARGUMENTS ReturnArguments 1835 ) 1836 { 1837 #ifndef _M_ARM 1838 KDESCRIPTOR Gdt, Idt; 1839 ULONG BootSizeNeeded; 1840 NTSTATUS Status; 1841 PVOID BootData; 1842 PIMAGE_NT_HEADERS NtHeaders; 1843 PVOID NewStack, NewGdt, NewIdt; 1844 BL_BUFFER_DESCRIPTOR Parameters; 1845 1846 /* Read the current IDT and GDT */ 1847 _sgdt(&Gdt.Limit); 1848 __sidt(&Idt.Limit); 1849 1850 /* Allocate space for the IDT, GDT, and 24 pages of stack */ 1851 BootSizeNeeded = (ULONG_PTR)PAGE_ALIGN(Idt.Limit + Gdt.Limit + 1 + 25 * PAGE_SIZE); 1852 Status = MmPapAllocatePagesInRange(&BootData, 1853 BlLoaderArchData, 1854 BootSizeNeeded >> PAGE_SHIFT, 1855 0, 1856 0, 1857 NULL, 1858 0); 1859 if (!NT_SUCCESS(Status)) 1860 { 1861 goto Quickie; 1862 } 1863 1864 /* Zero the boot data */ 1865 RtlZeroMemory(BootData, BootSizeNeeded); 1866 1867 /* Set the new stack, GDT and IDT */ 1868 NewStack = (PVOID)((ULONG_PTR)BootData + (24 * PAGE_SIZE) - 8); 1869 NewGdt = (PVOID)((ULONG_PTR)BootData + (24 * PAGE_SIZE)); 1870 NewIdt = (PVOID)((ULONG_PTR)BootData + (24 * PAGE_SIZE) + Gdt.Limit + 1); 1871 1872 /* Copy the current (firmware) GDT and IDT */ 1873 RtlCopyMemory(NewGdt, (PVOID)Gdt.Base, Gdt.Limit + 1); 1874 RtlCopyMemory(NewIdt, (PVOID)Idt.Base, Idt.Limit + 1); 1875 1876 /* Read the NT headers so that we can get the entrypoint later on */ 1877 RtlImageNtHeaderEx(0, ImageBase, ImageSize, &NtHeaders); 1878 1879 /* Prepare the application parameters */ 1880 RtlZeroMemory(&Parameters, sizeof(Parameters)); 1881 Status = ImgpInitializeBootApplicationParameters(&Parameters, 1882 AppEntry, 1883 ImageBase, 1884 ImageSize); 1885 if (NT_SUCCESS(Status)) 1886 { 1887 /* Set the firmware GDT/IDT as the one the application will use */ 1888 BootAppGdtRegister = Gdt; 1889 BootAppIdtRegister = Idt; 1890 1891 /* Set the entrypoint, parameters, and stack */ 1892 BootApp32EntryRoutine = (PVOID)((ULONG_PTR)ImageBase + 1893 NtHeaders->OptionalHeader. 1894 AddressOfEntryPoint); 1895 BootApp32Parameters = Parameters.Buffer; 1896 BootApp32Stack = NewStack; 1897 1898 #if BL_KD_SUPPORT 1899 /* Disable the kernel debugger */ 1900 BlBdStop(); 1901 #endif 1902 /* Make it so */ 1903 Archx86TransferTo32BitApplicationAsm(); 1904 1905 /* Not yet implemented. This is the last step! */ 1906 EfiPrintf(L"EFI APPLICATION RETURNED!!!\r\n"); 1907 EfiStall(100000000); 1908 1909 #if BL_KD_SUPPORT 1910 /* Re-enable the kernel debugger */ 1911 BlBdStart(); 1912 #endif 1913 } 1914 1915 Quickie: 1916 /* Check if we had boot data allocated */ 1917 if (BootData) 1918 { 1919 /* Free it */ 1920 MmPapFreePages(BootData, BL_MM_INCLUDE_MAPPED_ALLOCATED); 1921 } 1922 #else 1923 EfiPrintf(L"ImgArchEfiStartBootApplication not implemented for this platform.\r\n"); 1924 #endif 1925 1926 /* All done */ 1927 return STATUS_NOT_IMPLEMENTED; 1928 } 1929 1930 NTSTATUS 1931 BlImgStartBootApplication ( 1932 _In_ ULONG AppHandle, 1933 _Inout_opt_ PBL_RETURN_ARGUMENTS ReturnArguments 1934 ) 1935 { 1936 PBL_IMAGE_APPLICATION_ENTRY ImageAppEntry; 1937 BL_RETURN_ARGUMENTS LocalReturnArgs; 1938 PBL_FILE_SYSTEM_ENTRY FileSystem; 1939 PLIST_ENTRY NextEntry, ListHead; 1940 NTSTATUS Status; 1941 1942 /* Check if we don't have an argument structure */ 1943 if (!ReturnArguments) 1944 { 1945 /* Initialize a local copy and use it instead */ 1946 LocalReturnArgs.Version = BL_RETURN_ARGUMENTS_VERSION; 1947 LocalReturnArgs.Status = STATUS_SUCCESS; 1948 LocalReturnArgs.Flags = 0; 1949 LocalReturnArgs.DataPage = 0; 1950 LocalReturnArgs.DataSize = 0; 1951 ReturnArguments = &LocalReturnArgs; 1952 } 1953 1954 /* Make sure the handle index is valid */ 1955 if (IapTableEntries <= AppHandle) 1956 { 1957 return STATUS_INVALID_PARAMETER; 1958 } 1959 1960 /* Get the entry for this handle, making sure it exists */ 1961 ImageAppEntry = IapImageTable[AppHandle]; 1962 if (!ImageAppEntry) 1963 { 1964 return STATUS_INVALID_PARAMETER; 1965 } 1966 1967 /* Loop the registered file systems */ 1968 ListHead = &RegisteredFileSystems; 1969 NextEntry = RegisteredFileSystems.Flink; 1970 while (NextEntry != ListHead) 1971 { 1972 /* Get the filesystem entry */ 1973 FileSystem = CONTAINING_RECORD(NextEntry, 1974 BL_FILE_SYSTEM_ENTRY, 1975 ListEntry); 1976 1977 /* See if it has a purge callback */ 1978 if (FileSystem->PurgeCallback) 1979 { 1980 /* Call it */ 1981 FileSystem->PurgeCallback(); 1982 } 1983 1984 /* Move to the next entry */ 1985 NextEntry = NextEntry->Flink; 1986 } 1987 1988 /* TODO -- flush the block I/O cache too */ 1989 //BlockIoPurgeCache(); 1990 1991 /* Call into EFI land to start the boot application */ 1992 Status = ImgArchEfiStartBootApplication(ImageAppEntry->AppEntry, 1993 ImageAppEntry->ImageBase, 1994 ImageAppEntry->ImageSize, 1995 ReturnArguments); 1996 1997 /* Parse any arguments we got on the way back */ 1998 BlpPdParseReturnArguments(ReturnArguments); 1999 2000 #if BL_BITLOCKER_SUPPORT 2001 /* Bitlocker stuff */ 2002 FvebpCheckAllPartitions(TRUE); 2003 #endif 2004 2005 #if BL_TPM_SUPPORT 2006 /* Notify a TPM/SI event */ 2007 BlEnNotifyEvent(0x10000005, NULL); 2008 #endif 2009 2010 /* Reset the display */ 2011 BlpDisplayReinitialize(); 2012 2013 /* TODO -- reset ETW */ 2014 //BlpLogInitialize(); 2015 2016 /* All done */ 2017 return Status; 2018 } 2019 2020 NTSTATUS 2021 BlImgUnloadBootApplication ( 2022 _In_ ULONG AppHandle 2023 ) 2024 { 2025 PBL_IMAGE_APPLICATION_ENTRY ImageAppEntry; 2026 NTSTATUS Status; 2027 2028 /* Make sure the handle index is valid */ 2029 if (IapTableEntries <= AppHandle) 2030 { 2031 return STATUS_INVALID_PARAMETER; 2032 } 2033 2034 /* Get the entry for this handle, making sure it exists */ 2035 ImageAppEntry = IapImageTable[AppHandle]; 2036 if (!ImageAppEntry) 2037 { 2038 return STATUS_INVALID_PARAMETER; 2039 } 2040 2041 /* Unload the image */ 2042 Status = BlImgUnLoadImage(ImageAppEntry->ImageBase, 2043 ImageAppEntry->ImageSize, 2044 0); 2045 if (NT_SUCCESS(Status)) 2046 { 2047 /* Normalize the success code */ 2048 Status = STATUS_SUCCESS; 2049 } 2050 else 2051 { 2052 /* Normalize the failure code */ 2053 Status = STATUS_MEMORY_NOT_ALLOCATED; 2054 } 2055 2056 /* Free the entry and the image entry as well */ 2057 BlMmFreeHeap(ImageAppEntry->AppEntry); 2058 BlMmFreeHeap(ImageAppEntry); 2059 2060 /* Clear the handle */ 2061 IapImageTable[AppHandle] = NULL; 2062 2063 /* Free one entry */ 2064 if (!(--IapAllocatedTableEntries)) 2065 { 2066 /* There are no more, so get rid of the table itself */ 2067 BlMmFreeHeap(IapImageTable); 2068 IapImageTable = NULL; 2069 IapTableEntries = 0; 2070 } 2071 2072 /* All good */ 2073 return Status; 2074 } 2075