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)
9 /* INCLUDES ******************************************************************/
14 /* DATA VARIABLES ************************************************************/
16 ULONG IapAllocatedTableEntries
;
17 ULONG IapTableEntries
;
20 /* FUNCTIONS *****************************************************************/
24 _In_ PBL_IMG_FILE File
,
30 BL_FILE_INFORMATION FileInformation
;
32 /* Check if the file was memory mapped */
33 if (File
->Flags
& BL_IMG_MEMORY_FILE
)
35 /* Just read the size of the mapping */
36 Size
= File
->FileSize
;
40 /* Do file I/O to get the file size */
41 Status
= BlFileGetInformation(File
->FileId
,
43 if (!NT_SUCCESS(Status
))
48 /* We only support files less than 4GB in the Image Mapped */
49 Size
= FileInformation
.Size
;
50 if (FileInformation
.Size
> ULONG_MAX
)
52 return STATUS_NOT_SUPPORTED
;
56 /* Return the size and success */
58 return STATUS_SUCCESS
;
62 ImgpReadAtFileOffset (
63 _In_ PBL_IMG_FILE File
,
65 _In_ ULONGLONG ByteOffset
,
67 _Out_ PULONG BytesReturned
72 /* Check what if this is a mapped file or not */
73 if (File
->Flags
& BL_IMG_MEMORY_FILE
)
75 /* Check if the boundaries are within the file size */
76 if ((ByteOffset
+ Size
) <= File
->FileSize
)
78 /* Yep, copy into the caller-supplied buffer */
80 (PVOID
)((ULONG_PTR
)File
->BaseAddress
+ (ULONG_PTR
)ByteOffset
),
83 /* If caller wanted to know, return the size copied */
86 *BytesReturned
= Size
;
90 Status
= STATUS_SUCCESS
;
95 Status
= STATUS_INVALID_PARAMETER
;
100 /* Issue the file I/O instead */
101 Status
= BlFileReadAtOffsetEx(File
->FileId
,
109 /* Return the final status */
116 _In_ PWCHAR FileName
,
118 _Out_ PBL_IMG_FILE NewFile
123 ULONGLONG RemoteFileSize
;
124 PVOID RemoteFileAddress
;
127 /* First, try to see if BD has this file remotely */
128 Status
= BlBdPullRemoteFile(FileName
,
131 if (NT_SUCCESS(Status
))
133 /* Yep, get the file size and make sure it's < 4GB */
134 FileSize
= RemoteFileSize
;
135 if (RemoteFileSize
<= ULONG_MAX
)
137 /* Remember this is a memory mapped remote file */
138 NewFile
->Flags
|= (BL_IMG_MEMORY_FILE
| BL_IMG_REMOTE_FILE
);
139 NewFile
->FileSize
= FileSize
;
140 NewFile
->BaseAddress
= RemoteFileAddress
;
145 /* Use File I/O instead */
146 Status
= BlFileOpen(DeviceId
,
150 if (!NT_SUCCESS(Status
))
152 /* Bail out on failure */
156 /* Make sure nobody thinks this is a memory file */
157 NewFile
->Flags
&= ~BL_IMG_MEMORY_FILE
;
158 NewFile
->FileId
= FileId
;
161 /* Set common data for both memory and I/O based file */
162 NewFile
->Flags
|= BL_IMG_VALID_FILE
;
163 NewFile
->FileName
= FileName
;
169 _In_ PBL_IMG_FILE File
174 /* Make sure this is a valid file, otherwise no-op */
175 Status
= STATUS_SUCCESS
;
176 if (File
->Flags
& BL_IMG_VALID_FILE
)
178 /* Is this a memory mapped file? */
179 if (!(File
->Flags
& BL_IMG_MEMORY_FILE
))
181 /* Nope, close the file handle */
182 return BlFileClose(File
->FileId
);
185 /* Is this a remote file? */
186 if (File
->Flags
& BL_IMG_REMOTE_FILE
)
188 /* Then only free the memory in that scenario */
189 EfiPrintf(L
"TODO\r\n");
190 //return MmPapFreePages(File->BaseAddress, TRUE);
194 /* Return the final status */
199 BlImgUnallocateImageBuffer (
200 _In_ PVOID ImageBase
,
201 _In_ ULONG ImageSize
,
202 _In_ ULONG ImageFlags
205 EfiPrintf(L
"leaking the shit out of %p\r\n", ImageBase
);
206 return STATUS_NOT_IMPLEMENTED
;
210 BlImgAllocateImageBuffer (
211 _Inout_ PVOID
* ImageBuffer
,
212 _In_ ULONG MemoryType
,
213 _In_ ULONGLONG ImageSize
,
218 ULONGLONG Pages
, Size
;
219 PVOID MappedBase
, CurrentBuffer
;
221 PHYSICAL_ADDRESS PhysicalAddress
;
223 /* Read and reset the current buffer address */
224 CurrentBuffer
= *ImageBuffer
;
227 /* Align the image size to page */
228 Size
= ROUND_TO_PAGES(ImageSize
);
230 /* Not sure what this attribute does yet */
232 if (Flags
& BL_LOAD_IMG_UNKNOWN_BUFFER_FLAG
)
234 Attributes
= 0x10000;
237 /* Check if the caller wants a virtual buffer */
238 if (Flags
& BL_LOAD_IMG_VIRTUAL_BUFFER
)
240 /* Set the physical address to the current buffer */
241 PhysicalAddress
.QuadPart
= (ULONG_PTR
)CurrentBuffer
;
242 Pages
= Size
>> PAGE_SHIFT
;
244 /* Allocate the physical pages */
245 Status
= BlMmAllocatePhysicalPages(&PhysicalAddress
,
250 if (!NT_SUCCESS(Status
))
252 /* If that failed, remove allocation attributes */
253 PhysicalAddress
.QuadPart
= 0;
254 Attributes
&= ~BlMemoryValidAllocationAttributeMask
,
255 Status
= BlMmAllocatePhysicalPages(&PhysicalAddress
,
262 /* Check if either attempts succeeded */
263 if (!NT_SUCCESS(Status
))
268 /* Now map the physical buffer at the address requested */
269 MappedBase
= (PVOID
)PhysicalAddress
.LowPart
;
270 Status
= BlMmMapPhysicalAddressEx(&MappedBase
,
274 if (!NT_SUCCESS(Status
))
276 /* Free on failure if needed */
277 BlMmFreePhysicalPages(PhysicalAddress
);
283 /* Otherwise, allocate raw physical pages */
284 MappedBase
= CurrentBuffer
;
285 Pages
= Size
>> PAGE_SHIFT
;
286 Status
= MmPapAllocatePagesInRange(&MappedBase
,
293 if (!NT_SUCCESS(Status
))
295 /* If that failed, try without allocation attributes */
297 Attributes
&= ~BlMemoryValidAllocationAttributeMask
,
298 Status
= MmPapAllocatePagesInRange(&MappedBase
,
307 /* Check if either attempts succeeded */
308 if (!NT_SUCCESS(Status
))
314 /* Success path, returned allocated address */
315 *ImageBuffer
= MappedBase
;
316 return STATUS_SUCCESS
;
320 BlImgLoadImageWithProgress2 (
322 _In_ BL_MEMORY_TYPE MemoryType
,
323 _In_ PWCHAR FileName
,
324 _Inout_ PVOID
* MappedBase
,
325 _Inout_ PULONG MappedSize
,
326 _In_ ULONG ImageFlags
,
327 _In_ BOOLEAN ShowProgress
,
328 _Out_opt_ PUCHAR
* HashBuffer
,
329 _Out_opt_ PULONG HashSize
333 PVOID BaseAddress
, Buffer
;
334 ULONG RemainingLength
, CurrentSize
, ImageSize
, ReadSize
;
335 BOOLEAN ComputeSignature
, ComputeHash
, Completed
;
336 BL_IMG_FILE FileHandle
;
337 ULONGLONG ByteOffset
;
338 PHYSICAL_ADDRESS PhysicalAddress
;
340 /* Initialize variables */
344 RtlZeroMemory(&FileHandle
, sizeof(FileHandle
));
346 /* Check for missing parameters */
349 Status
= STATUS_INVALID_PARAMETER
;
354 Status
= STATUS_INVALID_PARAMETER
;
359 Status
= STATUS_INVALID_PARAMETER
;
363 /* Check if the image buffer is being provided */
364 if (ImageFlags
& BL_LOAD_IMG_EXISTING_BUFFER
)
366 /* An existing base must already exist */
369 Status
= STATUS_INVALID_PARAMETER
;
374 /* Check of a hash is being requested */
375 if (ImageFlags
& BL_LOAD_IMG_COMPUTE_HASH
)
377 /* Make sure we can return the hash */
380 Status
= STATUS_INVALID_PARAMETER
;
385 Status
= STATUS_INVALID_PARAMETER
;
390 /* Check for invalid combination of parameters */
391 if ((ImageFlags
& BL_LOAD_IMG_COMPUTE_HASH
) && (ImageFlags
& 0x270))
393 Status
= STATUS_INVALID_PARAMETER
;
397 /* Initialize hash if requested by caller */
403 /* Do the same for the hash size */
409 /* Open the image file */
410 Status
= ImgpOpenFile(DeviceId
, FileName
, DeviceId
, &FileHandle
);
411 if (!NT_SUCCESS(Status
))
413 EfiPrintf(L
"Error opening file: %lx\r\n", Status
);
417 /* Get the size of the image */
418 Status
= ImgpGetFileSize(&FileHandle
, &ImageSize
);
419 if (!NT_SUCCESS(Status
))
421 EfiPrintf(L
"Error getting file size: %lx\r\n", Status
);
425 /* Read the current base address */
426 BaseAddress
= *MappedBase
;
427 if (ImageFlags
& BL_LOAD_IMG_EXISTING_BUFFER
)
429 /* Check if the current buffer is too small */
430 if (*MappedSize
< ImageSize
)
432 /* Return the required size of the buffer */
433 *MappedSize
= ImageSize
;
434 Status
= STATUS_BUFFER_TOO_SMALL
;
439 /* A buffer was not provided, allocate one ourselves */
440 Status
= BlImgAllocateImageBuffer(&BaseAddress
,
446 /* Bail out if allocation failed */
447 if (!NT_SUCCESS(Status
))
452 /* Set the initial byte offset and length to read */
453 RemainingLength
= ImageSize
;
455 Buffer
= BaseAddress
;
457 /* Update the initial progress */
461 BlUtlUpdateProgress(0, &Completed
);
462 ShowProgress
&= (Completed
!= 0) - 1;
465 /* Set the chunk size for each read */
467 if (ReadSize
> ImageSize
)
469 ReadSize
= ImageSize
;
472 /* Check if we should compute hash and/or signatures */
473 ComputeSignature
= ImageFlags
& BL_LOAD_IMG_COMPUTE_SIGNATURE
;
474 if ((ComputeSignature
) || (ImageFlags
& BL_LOAD_IMG_COMPUTE_HASH
))
477 // todo: crypto is hard
480 /* Begin the read loop */
481 while (RemainingLength
)
483 /* Check if we've got more than a chunk left to read */
484 if (RemainingLength
> ReadSize
)
487 CurrentSize
= ReadSize
;
491 /* Read only what's left */
492 CurrentSize
= RemainingLength
;
496 Status
= ImgpReadAtFileOffset(&FileHandle
,
501 if (!NT_SUCCESS(Status
))
506 /* Check if we need to compute the hash of this chunk */
509 // todo: crypto is hard
512 /* Update our position and read information */
513 Buffer
= (PVOID
)((ULONG_PTR
)Buffer
+ CurrentSize
);
514 RemainingLength
-= CurrentSize
;
515 ByteOffset
+= CurrentSize
;
517 /* Check if we should update the progress bar */
520 /* Compute new percentage completed, check if we're done */
521 BlUtlUpdateProgress(100 - 100 * RemainingLength
/ ImageSize
,
523 ShowProgress
&= (Completed
!= 0) - 1;
527 /* Is the read fully complete? We need to finalize the hash if requested */
528 if (ComputeHash
!= RemainingLength
)
530 // todo: CRYPTO IS HARD
533 /* Success path, return back the buffer and the size of the image */
534 *MappedBase
= BaseAddress
;
535 *MappedSize
= ImageSize
;
538 /* Close the file handle */
539 ImgpCloseFile(&FileHandle
);
541 /* Check if we failed and had allocated a buffer */
542 if (!(NT_SUCCESS(Status
)) &&
544 !(ImageFlags
& BL_LOAD_IMG_EXISTING_BUFFER
))
546 /* Check what kind of buffer we had allocated */
547 if (ImageFlags
& BL_LOAD_IMG_VIRTUAL_BUFFER
)
549 /* Unmap and free the virtual buffer */
550 PhysicalAddress
.QuadPart
= (ULONG_PTR
)BaseAddress
;
551 BlMmUnmapVirtualAddressEx(BaseAddress
, ImageSize
);
552 BlMmFreePhysicalPages(PhysicalAddress
);
556 /* Free the physical buffer */
557 //MmPapFreePages(VirtualAddress, 1);
558 EfiPrintf(L
"Leaking memory\r\n");
562 /* If we hadn't gotten to 100% yet, do it now */
565 BlUtlUpdateProgress(100, &Completed
);
568 /* Return the final status */
572 PIMAGE_SECTION_HEADER
574 _In_ PVOID ImageBase
,
578 PIMAGE_SECTION_HEADER FoundSection
;
580 PIMAGE_SECTION_HEADER SectionHeader
;
581 PIMAGE_NT_HEADERS NtHeader
;
587 /* Make sure the image is valid */
588 Status
= RtlImageNtHeaderEx(0, ImageBase
, ImageSize
, &NtHeader
);
589 if (NT_SUCCESS(Status
))
591 /* Get the first section and loop through them all */
592 SectionHeader
= IMAGE_FIRST_SECTION(NtHeader
);
593 for (i
= 0; i
< NtHeader
->FileHeader
.NumberOfSections
; i
++)
595 /* Check if this is the resource section */
596 if (!_stricmp((PCCH
)SectionHeader
->Name
, ".rsrc"))
598 /* Yep, we're done */
599 FoundSection
= SectionHeader
;
603 /* Nope, keep going */
608 /* Return the matching section */
613 BlImgQueryCodeIntegrityBootOptions (
614 _In_ PBL_LOADED_APPLICATION_ENTRY ApplicationEntry
,
615 _Out_ PBOOLEAN IntegrityChecksDisabled
,
616 _Out_ PBOOLEAN TestSigning
623 /* Check if /DISABLEINTEGRITYCHECKS is on */
624 Status
= BlGetBootOptionBoolean(ApplicationEntry
->BcdData
,
625 BcdLibraryBoolean_DisableIntegrityChecks
,
627 *IntegrityChecksDisabled
= NT_SUCCESS(Status
) && (Value
);
629 /* Check if /TESTSIGNING is on */
630 Status
= BlGetBootOptionBoolean(ApplicationEntry
->BcdData
,
631 BcdLibraryBoolean_AllowPrereleaseSignatures
,
633 *TestSigning
= NT_SUCCESS(Status
) && (Value
);
638 _In_ PVOID ImageBase
,
639 _In_ ULONG ImageSize
,
640 _In_ ULONG ImageFlags
643 /* Check for missing parameters */
644 if (!(ImageSize
) || !(ImageBase
))
647 return STATUS_INVALID_PARAMETER
;
650 /* Unallocate the image buffer */
651 return BlImgUnallocateImageBuffer(ImageBase
, ImageSize
, ImageFlags
);
657 _In_ BL_MEMORY_TYPE MemoryType
,
659 _Out_ PVOID
* ImageBase
,
660 _Out_ PULONG ImageSize
,
665 EfiPrintf(L
"PE not implemented\r\n");
666 return STATUS_NOT_IMPLEMENTED
;
670 BlImgLoadBootApplication (
671 _In_ PBL_LOADED_APPLICATION_ENTRY BootEntry
,
672 _Out_ PULONG AppHandle
676 PULONGLONG AllowedList
;
677 ULONGLONG AllowedCount
;
679 LARGE_INTEGER Frequency
;
681 PBL_DEVICE_DESCRIPTOR Device
, BitLockerDevice
;
684 PBL_APPLICATION_ENTRY AppEntry
;
685 PBL_IMG_FILE ImageFile
;
688 BOOLEAN DisableIntegrity
, TestSigning
;
692 PBL_IMAGE_APPLICATION_ENTRY ImageAppEntry
;
694 BitLockerDevice
= NULL
;
699 ImageAppEntry
= NULL
;
704 EfiPrintf(L
"Loading application %p\r\n", BootEntry
);
706 Status
= BlpGetBootOptionIntegerList(BootEntry
->BcdData
,
707 BcdLibraryIntegerList_AllowedInMemorySettings
,
711 if (Status
== STATUS_SUCCESS
)
713 for (i
= 0; i
< AllowedCount
; i
++)
715 if (AllowedList
[i
] == BcdLibraryInteger_UndocumentedMagic
)
717 BlTimeQueryPerformanceCounter(&Frequency
);
718 BlAppendBootOptionInteger(BootEntry
,
719 BcdLibraryInteger_UndocumentedMagic
,
725 #if BL_BITLOCKER_SUPPORT
726 Status
= BlFveSecureBootUnlockBootDevice(BootEntry
, &BitLockerDevice
, &UnlockCode
);
728 Status
= STATUS_SUCCESS
;
730 if (!NT_SUCCESS(Status
))
735 Status
= BlGetBootOptionDevice(BootEntry
->BcdData
, BcdLibraryDevice_ApplicationDevice
, &Device
, NULL
);
736 if (!NT_SUCCESS(Status
))
741 Status
= BlGetBootOptionString(BootEntry
->BcdData
, BcdLibraryString_ApplicationPath
, &Path
);
742 if (!NT_SUCCESS(Status
))
747 Status
= BlpDeviceOpen(Device
, BL_DEVICE_READ_ACCESS
, 0, &DeviceId
);
748 if (!NT_SUCCESS(Status
))
753 BlImgQueryCodeIntegrityBootOptions(BootEntry
, &DisableIntegrity
, &TestSigning
);
756 RtlZeroMemory(&Context
, sizeof(Context
);
757 Context
.BootEntry
= BootEntry
;
758 BlEnNotifyEvent(0x10000003, &Context
);
762 if (!DisableIntegrity
)
767 Status
= BlImgLoadPEImageEx(DeviceId
, BlLoaderMemory
, Path
, &ImageBase
, &ImageSize
, Hash
, Flags
);
768 if (!NT_SUCCESS(Status
))
774 if (BdDebugTransitions
)
777 Status
= BlBdInitialize();
778 if (NT_SUCCESS(Status
))
780 if (BlBdDebuggerEnabled())
782 BdDebuggerNotPresent
= FALSE
;
783 RtlInitUnicodeString(&PathString
, Path
);
784 BlBdLoadImageSymbols(&PathString
, ImageBase
);
790 #if BL_BITLOCKER_SUPPORT
791 Status
= BlSecureBootCheckPolicyOnFveDevice(BitLockerDevice
);
793 Status
= STATUS_SUCCESS
;
795 if (!NT_SUCCESS(Status
))
800 #if BL_BITLOCKER_SUPPORT
801 Status
= BlFveSecureBootCheckpointBootApp(BootEntry
, BitLockerDevice
, Hash
, UnlockCode
);
803 Status
= STATUS_SUCCESS
;
805 if (!NT_SUCCESS(Status
))
810 ListSize
= BlGetBootOptionListSize(BootEntry
->BcdData
);
812 AppEntry
= BlMmAllocateHeap(ListSize
+ sizeof(*AppEntry
));
815 Status
= STATUS_NO_MEMORY
;
819 RtlZeroMemory(AppEntry
, sizeof(AppEntry
));
821 strcpy(AppEntry
->Signature
, "BTAPENT");
822 AppEntry
->Guid
= BootEntry
->Guid
;
823 AppEntry
->Flags
= BootEntry
->Flags
;
824 RtlCopyMemory(&AppEntry
->BcdData
, BootEntry
->BcdData
, ListSize
);
827 ImageAppEntry
= BlMmAllocateHeap(sizeof(*ImageAppEntry
));
828 ImageAppEntry
->ImageBase
= ImageBase
;
829 ImageAppEntry
->ImageSize
= ImageSize
;
830 ImageAppEntry
->AppEntry
= AppEntry
;
832 if (!IapTableEntries
)
834 IapAllocatedTableEntries
= 0;
836 IapImageTable
= BlMmAllocateHeap(IapTableEntries
* sizeof(PVOID
));
839 Status
= STATUS_NO_MEMORY
;
843 RtlZeroMemory(IapImageTable
, sizeof(IapTableEntries
* sizeof(PVOID
)));
846 Status
= BlTblSetEntry(&IapImageTable
,
855 BlDeviceClose(DeviceId
);
860 BlMmFreeHeap(Device
);
870 BlMmFreeHeap(BitLockerDevice
);
875 BlMmFreeHeap(UnlockCode
);
878 if (NT_SUCCESS(Status
))
880 IapAllocatedTableEntries
++;
886 BlImgUnLoadImage(ImageBase
, ImageSize
, 0);
891 BlMmFreeHeap(AppEntry
);
896 BlMmFreeHeap(ImageFile
);
899 if (!(IapAllocatedTableEntries
) && (IapImageTable
))
901 BlMmFreeHeap(IapImageTable
);
903 IapImageTable
= NULL
;
911 BlpPdParseReturnArguments (
912 _In_ PBL_RETURN_ARGUMENTS ReturnArguments
915 if (ReturnArguments
->DataPage
== 0)
917 return STATUS_SUCCESS
;
920 EfiPrintf(L
"Return arguments not supported\r\n");
921 return STATUS_NOT_IMPLEMENTED
;
925 BlImgStartBootApplication (
926 _In_ ULONG AppHandle
,
927 _Inout_opt_ PBL_RETURN_ARGUMENTS ReturnArguments
930 PBL_IMAGE_APPLICATION_ENTRY ImageAppEntry
;
931 BL_RETURN_ARGUMENTS LocalReturnArgs
;
932 PBL_FILE_SYSTEM_ENTRY FileSystem
;
933 PLIST_ENTRY NextEntry
, ListHead
;
936 if (!ReturnArguments
)
938 LocalReturnArgs
.Version
= 1;
939 LocalReturnArgs
.Status
= STATUS_SUCCESS
;
940 LocalReturnArgs
.Flags
= 0;
941 LocalReturnArgs
.DataPage
= 0;
942 LocalReturnArgs
.DataSize
= 0;
944 ReturnArguments
= &LocalReturnArgs
;
948 if (IapTableEntries
<= AppHandle
)
950 return STATUS_INVALID_PARAMETER
;
953 ImageAppEntry
= IapImageTable
[AppHandle
];
956 return STATUS_INVALID_PARAMETER
;
959 ListHead
= &RegisteredFileSystems
;
960 NextEntry
= RegisteredFileSystems
.Flink
;
961 while (NextEntry
!= ListHead
)
963 FileSystem
= CONTAINING_RECORD(NextEntry
, BL_FILE_SYSTEM_ENTRY
, ListEntry
);
965 if (FileSystem
->PurgeCallback
)
967 FileSystem
->PurgeCallback();
970 NextEntry
= NextEntry
->Flink
;
974 //BlockIoPurgeCache();
976 Status
= ImgArchEfiStartBootApplication(ImageAppEntry
->AppEntry
,
977 ImageAppEntry
->ImageBase
,
978 ImageAppEntry
->ImageSize
,
981 BlpPdParseReturnArguments(ReturnArguments
);
983 #if BL_BITLOCKER_SUPPORT
984 FvebpCheckAllPartitions(TRUE
);
988 BlEnNotifyEvent(0x10000005, NULL
);
992 //BlpDisplayReinitialize();
995 //BlpLogInitialize();
1001 BlImgUnloadBootApplication (
1002 _In_ ULONG AppHandle
1005 PBL_IMAGE_APPLICATION_ENTRY ImageAppEntry
; // esi@2
1008 if (IapTableEntries
<= AppHandle
)
1010 return STATUS_INVALID_PARAMETER
;
1013 ImageAppEntry
= IapImageTable
[AppHandle
];
1016 return STATUS_INVALID_PARAMETER
;
1019 Status
= BlImgUnLoadImage(ImageAppEntry
->ImageBase
,
1020 ImageAppEntry
->ImageSize
,
1022 if (NT_SUCCESS(Status
))
1024 Status
= STATUS_SUCCESS
;
1028 Status
= STATUS_MEMORY_NOT_ALLOCATED
;
1031 BlMmFreeHeap(ImageAppEntry
->AppEntry
);
1032 BlMmFreeHeap(ImageAppEntry
);
1034 IapImageTable
[AppHandle
] = NULL
;
1036 if (!(--IapAllocatedTableEntries
))
1038 BlMmFreeHeap(IapImageTable
);
1039 IapImageTable
= NULL
;
1040 IapTableEntries
= 0;