]> git.proxmox.com Git - mirror_edk2.git/blame - Nt32Pkg/Sec/SecMain.c
Use VirtualAlloc() to allocate enough memory space for Nt32 emulator in place of...
[mirror_edk2.git] / Nt32Pkg / Sec / SecMain.c
CommitLineData
2e19fd0f 1/*++\r
2\r
3Copyright (c) 2006, Intel Corporation\r
4All rights reserved. This program and the accompanying materials\r
5are licensed and made available under the terms and conditions of the BSD License\r
6which accompanies this distribution. The full text of the license may be found at\r
7http://opensource.org/licenses/bsd-license.php\r
8\r
9THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
10WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
11\r
12Module Name:\r
13\r
14 SecMain.c\r
15\r
16Abstract:\r
17 WinNt emulator of SEC phase. It's really a Win32 application, but this is\r
18 Ok since all the other modules for NT32 are NOT Win32 applications.\r
19\r
952261d5
LG
20 This program gets NT32 PCD setting and figures out what the memory layout \r
21 will be, how may FD's will be loaded and also what the boot mode is.\r
2e19fd0f 22\r
23 The SEC registers a set of services with the SEC core. gPrivateDispatchTable\r
24 is a list of PPI's produced by the SEC that are availble for usage in PEI.\r
25\r
952261d5
LG
26 This code produces 128 K of temporary memory for the PEI stack by directly\r
27 allocate memory space with ReadWrite and Execute attribute.\r
2e19fd0f 28\r
29--*/\r
30\r
31#include "SecMain.h"\r
d0dc913e 32\r
2e19fd0f 33\r
34//\r
35// Globals\r
36//\r
37EFI_PEI_PE_COFF_LOADER_PROTOCOL_INSTANCE mPeiEfiPeiPeCoffLoaderInstance = {\r
38 {\r
39 SecNt32PeCoffGetImageInfo,\r
40 SecNt32PeCoffLoadImage,\r
41 SecNt32PeCoffRelocateImage,\r
42 SecNt32PeCoffUnloadimage\r
43 },\r
44 NULL\r
45};\r
46\r
47\r
48\r
49EFI_PEI_PE_COFF_LOADER_PROTOCOL *gPeiEfiPeiPeCoffLoader = &mPeiEfiPeiPeCoffLoaderInstance.PeCoff;\r
50\r
51NT_PEI_LOAD_FILE_PPI mSecNtLoadFilePpi = { SecWinNtPeiLoadFile };\r
52\r
53PEI_NT_AUTOSCAN_PPI mSecNtAutoScanPpi = { SecWinNtPeiAutoScan };\r
54\r
55PEI_NT_THUNK_PPI mSecWinNtThunkPpi = { SecWinNtWinNtThunkAddress };\r
56\r
57EFI_PEI_PROGRESS_CODE_PPI mSecStatusCodePpi = { SecPeiReportStatusCode };\r
58\r
59NT_FWH_PPI mSecFwhInformationPpi = { SecWinNtFdAddress };\r
60\r
61\r
62EFI_PEI_PPI_DESCRIPTOR gPrivateDispatchTable[] = {\r
63 {\r
64 EFI_PEI_PPI_DESCRIPTOR_PPI,\r
65 &gEfiPeiPeCoffLoaderGuid,\r
66 NULL\r
67 },\r
68 {\r
69 EFI_PEI_PPI_DESCRIPTOR_PPI,\r
70 &gNtPeiLoadFilePpiGuid,\r
71 &mSecNtLoadFilePpi\r
72 },\r
73 {\r
74 EFI_PEI_PPI_DESCRIPTOR_PPI,\r
75 &gPeiNtAutoScanPpiGuid,\r
76 &mSecNtAutoScanPpi\r
77 },\r
78 {\r
79 EFI_PEI_PPI_DESCRIPTOR_PPI,\r
80 &gPeiNtThunkPpiGuid,\r
81 &mSecWinNtThunkPpi\r
82 },\r
83 {\r
84 EFI_PEI_PPI_DESCRIPTOR_PPI,\r
85 &gEfiPeiStatusCodePpiGuid,\r
86 &mSecStatusCodePpi\r
87 },\r
88 {\r
89 EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST,\r
90 &gNtFwhPpiGuid,\r
91 &mSecFwhInformationPpi\r
92 }\r
93};\r
94\r
95\r
96//\r
97// Default information about where the FD is located.\r
952261d5 98// This array gets filled in with information from PcdWinNtFirmwareVolume\r
2e19fd0f 99// The number of array elements is allocated base on parsing\r
952261d5 100// PcdWinNtFirmwareVolume and the memory is never freed.\r
2e19fd0f 101//\r
102UINTN gFdInfoCount = 0;\r
103NT_FD_INFO *gFdInfo;\r
104\r
105//\r
106// Array that supports seperate memory rantes.\r
952261d5 107// The memory ranges are set by PcdWinNtMemorySizeForSecMain.\r
2e19fd0f 108// The number of array elements is allocated base on parsing\r
952261d5 109// PcdWinNtMemorySizeForSecMain value and the memory is never freed.\r
2e19fd0f 110//\r
111UINTN gSystemMemoryCount = 0;\r
112NT_SYSTEM_MEMORY *gSystemMemory;\r
113\r
114\r
115UINTN mPdbNameModHandleArraySize = 0;\r
116PDB_NAME_TO_MOD_HANDLE *mPdbNameModHandleArray = NULL;\r
117\r
118\r
119\r
120\r
121INTN\r
122EFIAPI\r
123main (\r
124 IN INTN Argc,\r
125 IN CHAR8 **Argv,\r
126 IN CHAR8 **Envp\r
127 )\r
128/*++\r
129\r
130Routine Description:\r
131 Main entry point to SEC for WinNt. This is a Windows program\r
132\r
133Arguments:\r
134 Argc - Number of command line arguments\r
135 Argv - Array of command line argument strings\r
136 Envp - Array of environmemt variable strings\r
137\r
138Returns:\r
139 0 - Normal exit\r
140 1 - Abnormal exit\r
141\r
142--*/\r
143{\r
144 EFI_STATUS Status;\r
145 EFI_PHYSICAL_ADDRESS InitialStackMemory;\r
146 UINT64 InitialStackMemorySize;\r
147 UINTN Index;\r
148 UINTN Index1;\r
149 UINTN Index2;\r
150 UINTN PeiIndex;\r
151 CHAR16 *FileName;\r
152 CHAR16 *FileNamePtr;\r
153 BOOLEAN Done;\r
154 VOID *PeiCoreFile;\r
155 CHAR16 *MemorySizeStr;\r
156 CHAR16 *FirmwareVolumesStr;\r
952261d5
LG
157 \r
158 MemorySizeStr = (CHAR16 *) FixedPcdGetPtr (PcdWinNtMemorySizeForSecMain);\r
159 FirmwareVolumesStr = (CHAR16 *) FixedPcdGetPtr (PcdWinNtFirmwareVolume);\r
2e19fd0f 160\r
161 printf ("\nEDK SEC Main NT Emulation Environment from www.TianoCore.org\n");\r
162\r
163 //\r
164 // Make some Windows calls to Set the process to the highest priority in the\r
165 // idle class. We need this to have good performance.\r
166 //\r
167 SetPriorityClass (GetCurrentProcess (), IDLE_PRIORITY_CLASS);\r
168 SetThreadPriority (GetCurrentThread (), THREAD_PRIORITY_HIGHEST);\r
169\r
170 //\r
171 // Allocate space for gSystemMemory Array\r
172 //\r
173 gSystemMemoryCount = CountSeperatorsInString (MemorySizeStr, '!') + 1;\r
174 gSystemMemory = calloc (gSystemMemoryCount, sizeof (NT_SYSTEM_MEMORY));\r
175 if (gSystemMemory == NULL) {\r
176 printf ("ERROR : Can not allocate memory for %s. Exiting.\n", MemorySizeStr);\r
177 exit (1);\r
178 }\r
179 //\r
180 // Allocate space for gSystemMemory Array\r
181 //\r
182 gFdInfoCount = CountSeperatorsInString (FirmwareVolumesStr, '!') + 1;\r
183 gFdInfo = calloc (gFdInfoCount, sizeof (NT_FD_INFO));\r
184 if (gFdInfo == NULL) {\r
185 printf ("ERROR : Can not allocate memory for %s. Exiting.\n", FirmwareVolumesStr);\r
186 exit (1);\r
187 }\r
188 //\r
189 // Setup Boot Mode. If BootModeStr == "" then BootMode = 0 (BOOT_WITH_FULL_CONFIGURATION)\r
190 //\r
191 printf (" BootMode 0x%02x\n", FixedPcdGet32 (PcdWinNtBootMode));\r
192\r
193 //\r
952261d5 194 // Allocate 128K memory to emulate temp memory for PEI.\r
2e19fd0f 195 // on a real platform this would be SRAM, or using the cache as RAM.\r
196 // Set InitialStackMemory to zero so WinNtOpenFile will allocate a new mapping\r
197 //\r
952261d5
LG
198 InitialStackMemorySize = STACK_SIZE;\r
199 InitialStackMemory = (EFI_PHYSICAL_ADDRESS) (UINTN) VirtualAlloc (NULL, (SIZE_T) (InitialStackMemorySize), MEM_COMMIT, PAGE_EXECUTE_READWRITE);\r
200 if (InitialStackMemory == 0) {\r
201 printf ("ERROR : Can not allocate enough space for SecStack\n");\r
2e19fd0f 202 exit (1);\r
203 }\r
204\r
205 printf (" SEC passing in %d bytes of temp RAM to PEI\n", InitialStackMemorySize);\r
206\r
207 //\r
208 // Open All the firmware volumes and remember the info in the gFdInfo global\r
209 //\r
210 FileNamePtr = (CHAR16 *)malloc (StrLen ((CHAR16 *)FirmwareVolumesStr) * sizeof(CHAR16));\r
211 if (FileNamePtr == NULL) {\r
212 printf ("ERROR : Can not allocate memory for firmware volume string\n");\r
213 exit (1);\r
214 }\r
215\r
216 StrCpy (FileNamePtr, (CHAR16*)FirmwareVolumesStr);\r
217\r
218 for (Done = FALSE, Index = 0, PeiIndex = 0, PeiCoreFile = NULL; !Done; Index++) {\r
219 FileName = FileNamePtr;\r
220 for (Index1 = 0; (FileNamePtr[Index1] != '!') && (FileNamePtr[Index1] != 0); Index1++)\r
221 ;\r
222 if (FileNamePtr[Index1] == 0) {\r
223 Done = TRUE;\r
224 } else {\r
225 FileNamePtr[Index1] = '\0';\r
226 FileNamePtr = FileNamePtr + Index1 + 1;\r
227 }\r
228\r
229 //\r
230 // Open the FD and remmeber where it got mapped into our processes address space\r
231 //\r
232 Status = WinNtOpenFile (\r
233 FileName,\r
234 0,\r
235 OPEN_EXISTING,\r
236 &gFdInfo[Index].Address,\r
237 &gFdInfo[Index].Size\r
238 );\r
239 if (EFI_ERROR (Status)) {\r
240 printf ("ERROR : Can not open Firmware Device File %S (%r). Exiting.\n", FileName, Status);\r
241 exit (1);\r
242 }\r
243\r
244 printf (" FD loaded from");\r
245 //\r
246 // printf can't print filenames directly as the \ gets interperted as an\r
247 // escape character.\r
248 //\r
249 for (Index2 = 0; FileName[Index2] != '\0'; Index2++) {\r
250 printf ("%c", FileName[Index2]);\r
251 }\r
252\r
253 if (PeiCoreFile == NULL) {\r
254 //\r
255 // Assume the beginning of the FD is an FV and look for the PEI Core.\r
256 // Load the first one we find.\r
257 //\r
258 Status = SecFfsFindPeiCore ((EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) gFdInfo[Index].Address, &PeiCoreFile);\r
259 if (!EFI_ERROR (Status)) {\r
260 PeiIndex = Index;\r
261 printf (" contains SEC Core");\r
262 }\r
263 }\r
264\r
265 printf ("\n");\r
266 }\r
267 //\r
268 // Calculate memory regions and store the information in the gSystemMemory\r
269 // global for later use. The autosizing code will use this data to\r
270 // map this memory into the SEC process memory space.\r
271 //\r
272 for (Index = 0, Done = FALSE; !Done; Index++) {\r
273 //\r
274 // Save the size of the memory and make a Unicode filename SystemMemory00, ...\r
275 //\r
276 gSystemMemory[Index].Size = _wtoi (MemorySizeStr) * 0x100000;\r
2e19fd0f 277\r
278 //\r
279 // Find the next region\r
280 //\r
281 for (Index1 = 0; MemorySizeStr[Index1] != '!' && MemorySizeStr[Index1] != 0; Index1++)\r
282 ;\r
283 if (MemorySizeStr[Index1] == 0) {\r
284 Done = TRUE;\r
285 }\r
286\r
287 MemorySizeStr = MemorySizeStr + Index1 + 1;\r
288 }\r
289\r
290 printf ("\n");\r
291\r
292 //\r
293 // Hand off to PEI Core\r
294 //\r
295 SecLoadFromCore ((UINTN) InitialStackMemory, (UINTN) InitialStackMemorySize, (UINTN) gFdInfo[0].Address, PeiCoreFile);\r
296\r
297 //\r
298 // If we get here, then the PEI Core returned. This is an error as PEI should\r
299 // always hand off to DXE.\r
300 //\r
301 printf ("ERROR : PEI Core returned\n");\r
302 exit (1);\r
303}\r
304\r
305EFI_STATUS\r
306WinNtOpenFile (\r
307 IN CHAR16 *FileName,\r
308 IN UINT32 MapSize,\r
309 IN DWORD CreationDisposition,\r
310 IN OUT EFI_PHYSICAL_ADDRESS *BaseAddress,\r
311 OUT UINT64 *Length\r
312 )\r
313/*++\r
314\r
315Routine Description:\r
316 Opens and memory maps a file using WinNt services. If BaseAddress is non zero\r
317 the process will try and allocate the memory starting at BaseAddress.\r
318\r
319Arguments:\r
320 FileName - The name of the file to open and map\r
321 MapSize - The amount of the file to map in bytes\r
322 CreationDisposition - The flags to pass to CreateFile(). Use to create new files for\r
323 memory emulation, and exiting files for firmware volume emulation\r
324 BaseAddress - The base address of the mapped file in the user address space.\r
325 If passed in as NULL the a new memory region is used.\r
326 If passed in as non NULL the request memory region is used for\r
327 the mapping of the file into the process space.\r
328 Length - The size of the mapped region in bytes\r
329\r
330Returns:\r
331 EFI_SUCCESS - The file was opened and mapped.\r
332 EFI_NOT_FOUND - FileName was not found in the current directory\r
333 EFI_DEVICE_ERROR - An error occured attempting to map the opened file\r
334\r
335--*/\r
336{\r
337 HANDLE NtFileHandle;\r
338 HANDLE NtMapHandle;\r
339 VOID *VirtualAddress;\r
340 UINTN FileSize;\r
341\r
342 //\r
343 // Use Win API to open/create a file\r
344 //\r
345 NtFileHandle = CreateFile (\r
346 FileName,\r
347 GENERIC_READ | GENERIC_WRITE,\r
348 FILE_SHARE_READ,\r
349 NULL,\r
350 CreationDisposition,\r
351 FILE_ATTRIBUTE_NORMAL,\r
352 NULL\r
353 );\r
354 if (NtFileHandle == INVALID_HANDLE_VALUE) {\r
355 return EFI_NOT_FOUND;\r
356 }\r
357 //\r
358 // Map the open file into a memory range\r
359 //\r
360 NtMapHandle = CreateFileMapping (\r
361 NtFileHandle,\r
362 NULL,\r
363 PAGE_READWRITE,\r
364 0,\r
365 MapSize,\r
366 NULL\r
367 );\r
368 if (NtMapHandle == NULL) {\r
369 return EFI_DEVICE_ERROR;\r
370 }\r
371 //\r
372 // Get the virtual address (address in the emulator) of the mapped file\r
373 //\r
374 VirtualAddress = MapViewOfFileEx (\r
375 NtMapHandle,\r
376 FILE_MAP_ALL_ACCESS,\r
377 0,\r
378 0,\r
379 MapSize,\r
380 (LPVOID) (UINTN) *BaseAddress\r
381 );\r
382 if (VirtualAddress == NULL) {\r
383 return EFI_DEVICE_ERROR;\r
384 }\r
385\r
386 if (MapSize == 0) {\r
387 //\r
388 // Seek to the end of the file to figure out the true file size.\r
389 //\r
390 FileSize = SetFilePointer (\r
391 NtFileHandle,\r
392 0,\r
393 NULL,\r
394 FILE_END\r
395 );\r
396 if (FileSize == -1) {\r
397 return EFI_DEVICE_ERROR;\r
398 }\r
399\r
400 *Length = (UINT64) FileSize;\r
401 } else {\r
402 *Length = (UINT64) MapSize;\r
403 }\r
404\r
405 *BaseAddress = (EFI_PHYSICAL_ADDRESS) (UINTN) VirtualAddress;\r
406\r
407 return EFI_SUCCESS;\r
408}\r
409\r
2e19fd0f 410\r
d0dc913e 411#define BYTES_PER_RECORD 512\r
2e19fd0f 412\r
413EFI_STATUS\r
414EFIAPI\r
415SecPeiReportStatusCode (\r
e1001af1 416 IN CONST EFI_PEI_SERVICES **PeiServices,\r
2e19fd0f 417 IN EFI_STATUS_CODE_TYPE CodeType,\r
418 IN EFI_STATUS_CODE_VALUE Value,\r
419 IN UINT32 Instance,\r
e1001af1 420 IN CONST EFI_GUID *CallerId,\r
421 IN CONST EFI_STATUS_CODE_DATA *Data OPTIONAL\r
2e19fd0f 422 )\r
423/*++\r
424\r
425Routine Description:\r
426\r
427 This routine produces the ReportStatusCode PEI service. It's passed\r
428 up to the PEI Core via a PPI. T\r
429\r
430 This code currently uses the NT clib printf. This does not work the same way\r
431 as the EFI Print (), as %t, %g, %s as Unicode are not supported.\r
432\r
433Arguments:\r
434 (see EFI_PEI_REPORT_STATUS_CODE)\r
435\r
436Returns:\r
437 EFI_SUCCESS - Always return success\r
438\r
439--*/\r
440// TODO: PeiServices - add argument and description to function comment\r
441// TODO: CodeType - add argument and description to function comment\r
442// TODO: Value - add argument and description to function comment\r
443// TODO: Instance - add argument and description to function comment\r
444// TODO: CallerId - add argument and description to function comment\r
445// TODO: Data - add argument and description to function comment\r
446{\r
447 CHAR8 *Format;\r
2e19fd0f 448 VA_LIST Marker;\r
449 CHAR8 PrintBuffer[BYTES_PER_RECORD * 2];\r
450 CHAR8 *Filename;\r
451 CHAR8 *Description;\r
452 UINT32 LineNumber;\r
d0dc913e 453 UINT32 ErrorLevel;\r
2e19fd0f 454\r
d0dc913e
A
455\r
456 if (Data == NULL) {\r
457 } else if (ReportStatusCodeExtractAssertInfo (CodeType, Value, Data, &Filename, &Description, &LineNumber)) {\r
2e19fd0f 458 //\r
d0dc913e 459 // Processes ASSERT ()\r
2e19fd0f 460 //\r
d0dc913e 461 printf ("ASSERT %s(%d): %s\n", Filename, LineNumber, Description);\r
2e19fd0f 462\r
d0dc913e
A
463 } else if (ReportStatusCodeExtractDebugInfo (Data, &ErrorLevel, &Marker, &Format)) {\r
464 //\r
465 // Process DEBUG () macro \r
466 //\r
467 AsciiVSPrint (PrintBuffer, BYTES_PER_RECORD, Format, Marker);\r
468 printf (PrintBuffer);\r
2e19fd0f 469 }\r
470\r
471 return EFI_SUCCESS;\r
472}\r
473\r
5aae0aa7 474/**\r
475 Transfers control to a function starting with a new stack.\r
476\r
477 Transfers control to the function specified by EntryPoint using the new stack\r
478 specified by NewStack and passing in the parameters specified by Context1 and\r
479 Context2. Context1 and Context2 are optional and may be NULL. The function\r
480 EntryPoint must never return.\r
481\r
482 If EntryPoint is NULL, then ASSERT().\r
483 If NewStack is NULL, then ASSERT().\r
484\r
485 @param EntryPoint A pointer to function to call with the new stack.\r
486 @param Context1 A pointer to the context to pass into the EntryPoint\r
487 function.\r
488 @param Context2 A pointer to the context to pass into the EntryPoint\r
489 function.\r
490 @param NewStack A pointer to the new stack to use for the EntryPoint\r
491 function.\r
492 @param NewBsp A pointer to the new BSP for the EntryPoint on IPF. It's\r
493 Reserved on other architectures.\r
494\r
495**/\r
496VOID\r
497EFIAPI\r
498PeiSwitchStacks (\r
499 IN SWITCH_STACK_ENTRY_POINT EntryPoint,\r
500 IN VOID *Context1, OPTIONAL\r
501 IN VOID *Context2, OPTIONAL\r
502 IN VOID *Context3, OPTIONAL\r
503 IN VOID *NewStack\r
504 )\r
505{\r
506 BASE_LIBRARY_JUMP_BUFFER JumpBuffer;\r
507 \r
508 ASSERT (EntryPoint != NULL);\r
509 ASSERT (NewStack != NULL);\r
510\r
511 //\r
512 // Stack should be aligned with CPU_STACK_ALIGNMENT\r
513 //\r
514 ASSERT (((UINTN)NewStack & (CPU_STACK_ALIGNMENT - 1)) == 0);\r
515\r
516 JumpBuffer.Eip = (UINTN)EntryPoint;\r
517 JumpBuffer.Esp = (UINTN)NewStack - sizeof (VOID*);\r
518 JumpBuffer.Esp -= sizeof (Context1) + sizeof (Context2) + sizeof(Context3);\r
519 ((VOID**)JumpBuffer.Esp)[1] = Context1;\r
520 ((VOID**)JumpBuffer.Esp)[2] = Context2;\r
521 ((VOID**)JumpBuffer.Esp)[3] = Context3;\r
522\r
523 LongJump (&JumpBuffer, (UINTN)-1);\r
524 \r
525\r
526 //\r
527 // InternalSwitchStack () will never return\r
528 //\r
529 ASSERT (FALSE); \r
530}\r
2e19fd0f 531\r
532VOID\r
533SecLoadFromCore (\r
534 IN UINTN LargestRegion,\r
535 IN UINTN LargestRegionSize,\r
536 IN UINTN BootFirmwareVolumeBase,\r
537 IN VOID *PeiCorePe32File\r
538 )\r
539/*++\r
540\r
541Routine Description:\r
542 This is the service to load the PEI Core from the Firmware Volume\r
543\r
544Arguments:\r
545 LargestRegion - Memory to use for PEI.\r
546 LargestRegionSize - Size of Memory to use for PEI\r
547 BootFirmwareVolumeBase - Start of the Boot FV\r
548 PeiCorePe32File - PEI Core PE32\r
549\r
550Returns:\r
551 Success means control is transfered and thus we should never return\r
552\r
553--*/\r
554{\r
555 EFI_STATUS Status;\r
556 EFI_PHYSICAL_ADDRESS TopOfMemory;\r
557 VOID *TopOfStack;\r
558 UINT64 PeiCoreSize;\r
559 EFI_PHYSICAL_ADDRESS PeiCoreEntryPoint;\r
560 EFI_PHYSICAL_ADDRESS PeiImageAddress;\r
5aae0aa7 561 EFI_SEC_PEI_HAND_OFF *SecCoreData;\r
2e19fd0f 562\r
563 //\r
564 // Compute Top Of Memory for Stack and PEI Core Allocations\r
565 //\r
566 TopOfMemory = LargestRegion + LargestRegionSize;\r
567\r
568 //\r
569 // Allocate 128KB for the Stack\r
570 //\r
5aae0aa7 571 TopOfStack = (VOID *)((UINTN)TopOfMemory - sizeof (EFI_SEC_PEI_HAND_OFF) - CPU_STACK_ALIGNMENT);\r
2e19fd0f 572 TopOfStack = ALIGN_POINTER (TopOfStack, CPU_STACK_ALIGNMENT);\r
573 TopOfMemory = TopOfMemory - STACK_SIZE;\r
574\r
575 //\r
576 // Patch value in dispatch table values\r
577 //\r
578 gPrivateDispatchTable[0].Ppi = gPeiEfiPeiPeCoffLoader;\r
579\r
580 //\r
581 // Bind this information into the SEC hand-off state\r
582 //\r
5aae0aa7 583 SecCoreData = (EFI_SEC_PEI_HAND_OFF*)(UINTN) TopOfStack;\r
584 SecCoreData->DataSize = sizeof(EFI_SEC_PEI_HAND_OFF);\r
585 SecCoreData->BootFirmwareVolumeBase = (VOID*)BootFirmwareVolumeBase;\r
586 SecCoreData->BootFirmwareVolumeSize = FixedPcdGet32(PcdWinNtFirmwareFdSize);\r
587 SecCoreData->TemporaryRamBase = (VOID*)(UINTN)TopOfMemory; \r
588 SecCoreData->TemporaryRamSize = STACK_SIZE;\r
589 SecCoreData->PeiTemporaryRamBase = SecCoreData->TemporaryRamBase;\r
590 SecCoreData->PeiTemporaryRamSize = (UINTN)RShiftU64((UINT64)STACK_SIZE,1);\r
591 SecCoreData->StackBase = (VOID*)((UINTN)SecCoreData->TemporaryRamBase + (UINTN)SecCoreData->TemporaryRamSize);\r
592 SecCoreData->StackSize = (UINTN)RShiftU64((UINT64)STACK_SIZE,1);\r
2e19fd0f 593\r
594 //\r
595 // Load the PEI Core from a Firmware Volume\r
596 //\r
597 Status = SecWinNtPeiLoadFile (\r
598 PeiCorePe32File,\r
599 &PeiImageAddress,\r
600 &PeiCoreSize,\r
601 &PeiCoreEntryPoint\r
602 );\r
603 if (EFI_ERROR (Status)) {\r
604 return ;\r
605 }\r
5aae0aa7 606 \r
2e19fd0f 607 //\r
608 // Transfer control to the PEI Core\r
609 //\r
5aae0aa7 610 PeiSwitchStacks (\r
2e19fd0f 611 (SWITCH_STACK_ENTRY_POINT) (UINTN) PeiCoreEntryPoint,\r
5aae0aa7 612 SecCoreData,\r
613 (VOID *) (UINTN) ((EFI_PEI_PPI_DESCRIPTOR *) &gPrivateDispatchTable),\r
2e19fd0f 614 NULL,\r
615 TopOfStack\r
616 );\r
617 //\r
618 // If we get here, then the PEI Core returned. This is an error\r
619 //\r
620 return ;\r
621}\r
622\r
623EFI_STATUS\r
624EFIAPI\r
625SecWinNtPeiAutoScan (\r
626 IN UINTN Index,\r
627 OUT EFI_PHYSICAL_ADDRESS *MemoryBase,\r
628 OUT UINT64 *MemorySize\r
629 )\r
630/*++\r
631\r
632Routine Description:\r
633 This service is called from Index == 0 until it returns EFI_UNSUPPORTED.\r
634 It allows discontiguous memory regions to be supported by the emulator.\r
635 It uses gSystemMemory[] and gSystemMemoryCount that were created by\r
952261d5
LG
636 parsing PcdWinNtMemorySizeForSecMain value.\r
637 The size comes from the Pcd value and the address comes from the memory space \r
638 with ReadWrite and Execute attributes allocated by VirtualAlloc() API.\r
2e19fd0f 639\r
640Arguments:\r
641 Index - Which memory region to use\r
642 MemoryBase - Return Base address of memory region\r
643 MemorySize - Return size in bytes of the memory region\r
644\r
645Returns:\r
646 EFI_SUCCESS - If memory region was mapped\r
647 EFI_UNSUPPORTED - If Index is not supported\r
648\r
649--*/\r
650{\r
2e19fd0f 651 if (Index >= gSystemMemoryCount) {\r
652 return EFI_UNSUPPORTED;\r
653 }\r
952261d5
LG
654 \r
655 //\r
656 // Allocate enough memory space for emulator \r
657 //\r
658 gSystemMemory[Index].Memory = (EFI_PHYSICAL_ADDRESS) (UINTN) VirtualAlloc (NULL, (SIZE_T) (gSystemMemory[Index].Size), MEM_COMMIT, PAGE_EXECUTE_READWRITE);\r
659 if (gSystemMemory[Index].Memory == 0) {\r
660 return EFI_OUT_OF_RESOURCES;\r
661 }\r
662 \r
663 *MemoryBase = gSystemMemory[Index].Memory;\r
664 *MemorySize = gSystemMemory[Index].Size;\r
2e19fd0f 665\r
952261d5 666 return EFI_SUCCESS;\r
2e19fd0f 667}\r
668\r
669VOID *\r
670EFIAPI\r
671SecWinNtWinNtThunkAddress (\r
672 VOID\r
673 )\r
674/*++\r
675\r
676Routine Description:\r
677 Since the SEC is the only Windows program in stack it must export\r
678 an interface to do Win API calls. That's what the WinNtThunk address\r
679 is for. gWinNt is initailized in WinNtThunk.c.\r
680\r
681Arguments:\r
682 InterfaceSize - sizeof (EFI_WIN_NT_THUNK_PROTOCOL);\r
683 InterfaceBase - Address of the gWinNt global\r
684\r
685Returns:\r
686 EFI_SUCCESS - Data returned\r
687\r
688--*/\r
689{\r
690 return gWinNt;\r
691}\r
692\r
693\r
694EFI_STATUS\r
695EFIAPI\r
696SecWinNtPeiLoadFile (\r
697 IN VOID *Pe32Data,\r
698 IN EFI_PHYSICAL_ADDRESS *ImageAddress,\r
699 IN UINT64 *ImageSize,\r
700 IN EFI_PHYSICAL_ADDRESS *EntryPoint\r
701 )\r
702/*++\r
703\r
704Routine Description:\r
705 Loads and relocates a PE/COFF image into memory.\r
706\r
707Arguments:\r
708 Pe32Data - The base address of the PE/COFF file that is to be loaded and relocated\r
709 ImageAddress - The base address of the relocated PE/COFF image\r
710 ImageSize - The size of the relocated PE/COFF image\r
711 EntryPoint - The entry point of the relocated PE/COFF image\r
712\r
713Returns:\r
714 EFI_SUCCESS - The file was loaded and relocated\r
715 EFI_OUT_OF_RESOURCES - There was not enough memory to load and relocate the PE/COFF file\r
716\r
717--*/\r
718{\r
719 EFI_STATUS Status;\r
720 PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;\r
721\r
722 ZeroMem (&ImageContext, sizeof (ImageContext));\r
723 ImageContext.Handle = Pe32Data;\r
724\r
725 ImageContext.ImageRead = (PE_COFF_LOADER_READ_FILE) SecImageRead;\r
726\r
727 Status = gPeiEfiPeiPeCoffLoader->GetImageInfo (gPeiEfiPeiPeCoffLoader, &ImageContext);\r
728 if (EFI_ERROR (Status)) {\r
729 return Status;\r
730 }\r
731 //\r
952261d5
LG
732 // Allocate space in NT (not emulator) memory with ReadWrite and Execute attribue. \r
733 // Extra space is for alignment\r
2e19fd0f 734 //\r
952261d5 735 ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS) (UINTN) VirtualAlloc (NULL, (SIZE_T) (ImageContext.ImageSize + (ImageContext.SectionAlignment * 2)), MEM_COMMIT, PAGE_EXECUTE_READWRITE);\r
2e19fd0f 736 if (ImageContext.ImageAddress == 0) {\r
737 return EFI_OUT_OF_RESOURCES;\r
738 }\r
739 //\r
740 // Align buffer on section boundry\r
741 //\r
742 ImageContext.ImageAddress += ImageContext.SectionAlignment;\r
743 ImageContext.ImageAddress &= ~(ImageContext.SectionAlignment - 1);\r
744\r
745 Status = gPeiEfiPeiPeCoffLoader->LoadImage (gPeiEfiPeiPeCoffLoader, &ImageContext);\r
746 if (EFI_ERROR (Status)) {\r
747 return Status;\r
748 }\r
749\r
750 Status = gPeiEfiPeiPeCoffLoader->RelocateImage (gPeiEfiPeiPeCoffLoader, &ImageContext);\r
751 if (EFI_ERROR (Status)) {\r
752 return Status;\r
753 }\r
754\r
755 //\r
756 // BugBug: Flush Instruction Cache Here when CPU Lib is ready\r
757 //\r
758\r
759 *ImageAddress = ImageContext.ImageAddress;\r
760 *ImageSize = ImageContext.ImageSize;\r
761 *EntryPoint = ImageContext.EntryPoint;\r
762\r
763 return EFI_SUCCESS;\r
764}\r
765\r
766EFI_STATUS\r
767EFIAPI\r
768SecWinNtFdAddress (\r
769 IN UINTN Index,\r
770 IN OUT EFI_PHYSICAL_ADDRESS *FdBase,\r
771 IN OUT UINT64 *FdSize\r
772 )\r
773/*++\r
774\r
775Routine Description:\r
776 Return the FD Size and base address. Since the FD is loaded from a\r
777 file into Windows memory only the SEC will know it's address.\r
778\r
779Arguments:\r
780 Index - Which FD, starts at zero.\r
781 FdSize - Size of the FD in bytes\r
782 FdBase - Start address of the FD. Assume it points to an FV Header\r
783\r
784Returns:\r
785 EFI_SUCCESS - Return the Base address and size of the FV\r
786 EFI_UNSUPPORTED - Index does nto map to an FD in the system\r
787\r
788--*/\r
789{\r
790 if (Index >= gFdInfoCount) {\r
791 return EFI_UNSUPPORTED;\r
792 }\r
793\r
794 *FdBase = gFdInfo[Index].Address;\r
795 *FdSize = gFdInfo[Index].Size;\r
796\r
797 if (*FdBase == 0 && *FdSize == 0) {\r
798 return EFI_UNSUPPORTED;\r
799 }\r
800\r
801 return EFI_SUCCESS;\r
802}\r
803\r
804EFI_STATUS\r
805EFIAPI\r
806SecImageRead (\r
807 IN VOID *FileHandle,\r
808 IN UINTN FileOffset,\r
809 IN OUT UINTN *ReadSize,\r
810 OUT VOID *Buffer\r
811 )\r
812/*++\r
813\r
814Routine Description:\r
815 Support routine for the PE/COFF Loader that reads a buffer from a PE/COFF file\r
816\r
817Arguments:\r
818 FileHandle - The handle to the PE/COFF file\r
819 FileOffset - The offset, in bytes, into the file to read\r
820 ReadSize - The number of bytes to read from the file starting at FileOffset\r
821 Buffer - A pointer to the buffer to read the data into.\r
822\r
823Returns:\r
824 EFI_SUCCESS - ReadSize bytes of data were read into Buffer from the PE/COFF file starting at FileOffset\r
825\r
826--*/\r
827{\r
828 CHAR8 *Destination8;\r
829 CHAR8 *Source8;\r
830 UINTN Length;\r
831\r
832 Destination8 = Buffer;\r
833 Source8 = (CHAR8 *) ((UINTN) FileHandle + FileOffset);\r
834 Length = *ReadSize;\r
835 while (Length--) {\r
836 *(Destination8++) = *(Source8++);\r
837 }\r
838\r
839 return EFI_SUCCESS;\r
840}\r
841\r
842CHAR16 *\r
843AsciiToUnicode (\r
844 IN CHAR8 *Ascii,\r
845 IN UINTN *StrLen OPTIONAL\r
846 )\r
847/*++\r
848\r
849Routine Description:\r
850 Convert the passed in Ascii string to Unicode.\r
851 Optionally return the length of the strings.\r
852\r
853Arguments:\r
854 Ascii - Ascii string to convert\r
855 StrLen - Length of string\r
856\r
857Returns:\r
858 Pointer to malloc'ed Unicode version of Ascii\r
859\r
860--*/\r
861{\r
862 UINTN Index;\r
863 CHAR16 *Unicode;\r
864\r
865 //\r
866 // Allocate a buffer for unicode string\r
867 //\r
868 for (Index = 0; Ascii[Index] != '\0'; Index++)\r
869 ;\r
870 Unicode = malloc ((Index + 1) * sizeof (CHAR16));\r
871 if (Unicode == NULL) {\r
872 return NULL;\r
873 }\r
874\r
875 for (Index = 0; Ascii[Index] != '\0'; Index++) {\r
876 Unicode[Index] = (CHAR16) Ascii[Index];\r
877 }\r
878\r
879 Unicode[Index] = '\0';\r
880\r
881 if (StrLen != NULL) {\r
882 *StrLen = Index;\r
883 }\r
884\r
885 return Unicode;\r
886}\r
887\r
888UINTN\r
889CountSeperatorsInString (\r
890 IN const CHAR16 *String,\r
891 IN CHAR16 Seperator\r
892 )\r
893/*++\r
894\r
895Routine Description:\r
896 Count the number of seperators in String\r
897\r
898Arguments:\r
899 String - String to process\r
900 Seperator - Item to count\r
901\r
902Returns:\r
903 Number of Seperator in String\r
904\r
905--*/\r
906{\r
907 UINTN Count;\r
908\r
909 for (Count = 0; *String != '\0'; String++) {\r
910 if (*String == Seperator) {\r
911 Count++;\r
912 }\r
913 }\r
914\r
915 return Count;\r
916}\r
917\r
918\r
919EFI_STATUS\r
920AddModHandle (\r
921 IN PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext,\r
922 IN VOID *ModHandle\r
923 )\r
924/*++\r
925\r
926Routine Description:\r
927 Store the ModHandle in an array indexed by the Pdb File name.\r
928 The ModHandle is needed to unload the image. \r
929\r
930Arguments:\r
931 ImageContext - Input data returned from PE Laoder Library. Used to find the \r
932 .PDB file name of the PE Image.\r
933 ModHandle - Returned from LoadLibraryEx() and stored for call to \r
934 FreeLibrary().\r
935\r
936Returns:\r
937 EFI_SUCCESS - ModHandle was stored. \r
938\r
939--*/\r
940{\r
941 UINTN Index;\r
942 PDB_NAME_TO_MOD_HANDLE *Array;\r
943 UINTN PreviousSize;\r
944\r
945\r
946 Array = mPdbNameModHandleArray;\r
947 for (Index = 0; Index < mPdbNameModHandleArraySize; Index++, Array++) {\r
948 if (Array->PdbPointer == NULL) {\r
949 //\r
950 // Make a copy of the stirng and store the ModHandle\r
951 //\r
952 Array->PdbPointer = malloc (strlen (ImageContext->PdbPointer) + 1);\r
953 ASSERT (Array->PdbPointer != NULL);\r
954\r
955 strcpy (Array->PdbPointer, ImageContext->PdbPointer);\r
956 Array->ModHandle = ModHandle;\r
957 return EFI_SUCCESS;\r
958 }\r
959 }\r
960 \r
961 //\r
962 // No free space in mPdbNameModHandleArray so grow it by \r
963 // MAX_PDB_NAME_TO_MOD_HANDLE_ARRAY_SIZE entires. realloc will\r
964 // copy the old values to the new locaiton. But it does\r
965 // not zero the new memory area.\r
966 //\r
967 PreviousSize = mPdbNameModHandleArraySize * sizeof (PDB_NAME_TO_MOD_HANDLE);\r
968 mPdbNameModHandleArraySize += MAX_PDB_NAME_TO_MOD_HANDLE_ARRAY_SIZE;\r
969\r
970 mPdbNameModHandleArray = realloc (mPdbNameModHandleArray, mPdbNameModHandleArraySize * sizeof (PDB_NAME_TO_MOD_HANDLE));\r
971 if (mPdbNameModHandleArray == NULL) {\r
972 ASSERT (FALSE);\r
973 return EFI_OUT_OF_RESOURCES;\r
974 }\r
975 \r
976 memset (mPdbNameModHandleArray + PreviousSize, 0, MAX_PDB_NAME_TO_MOD_HANDLE_ARRAY_SIZE * sizeof (PDB_NAME_TO_MOD_HANDLE));\r
977 \r
978 return AddModHandle (ImageContext, ModHandle);\r
979}\r
980\r
981\r
982VOID *\r
983RemoveModeHandle (\r
984 IN PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext\r
985 )\r
986/*++\r
987\r
988Routine Description:\r
989 Return the ModHandle and delete the entry in the array.\r
990\r
991Arguments:\r
992 ImageContext - Input data returned from PE Laoder Library. Used to find the \r
993 .PDB file name of the PE Image.\r
994\r
995Returns:\r
996 ModHandle - ModHandle assoicated with ImageContext is returned\r
997 NULL - No ModHandle associated with ImageContext\r
998\r
999--*/\r
1000{\r
1001 UINTN Index;\r
1002 PDB_NAME_TO_MOD_HANDLE *Array;\r
1003\r
1004 if (ImageContext->PdbPointer == NULL) {\r
1005 //\r
1006 // If no PDB pointer there is no ModHandle so return NULL\r
1007 //\r
1008 return NULL;\r
1009 }\r
1010\r
1011 Array = mPdbNameModHandleArray;\r
1012 for (Index = 0; Index < mPdbNameModHandleArraySize; Index++, Array++) {\r
1013 if ((Array->PdbPointer != NULL) && (strcmp(Array->PdbPointer, ImageContext->PdbPointer) == 0)) {\r
1014 //\r
1015 // If you find a match return it and delete the entry\r
1016 //\r
1017 free (Array->PdbPointer);\r
1018 Array->PdbPointer = NULL;\r
1019 return Array->ModHandle;\r
1020 }\r
1021 }\r
1022\r
1023 return NULL;\r
1024}\r
1025\r
1026\r
1027\r
1028EFI_STATUS\r
1029EFIAPI\r
1030SecNt32PeCoffGetImageInfo (\r
1031 IN EFI_PEI_PE_COFF_LOADER_PROTOCOL *This,\r
1032 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext\r
1033 )\r
1034{\r
1035 EFI_STATUS Status;\r
1036\r
1037 Status = PeCoffLoaderGetImageInfo (ImageContext);\r
1038 if (EFI_ERROR (Status)) {\r
1039 return Status;\r
1040 }\r
1041\r
1042 switch (ImageContext->ImageType) {\r
1043\r
1044 case EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION:\r
1045 ImageContext->ImageCodeMemoryType = EfiLoaderCode;\r
1046 ImageContext->ImageDataMemoryType = EfiLoaderData;\r
1047 break;\r
1048\r
1049 case EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER:\r
1050 ImageContext->ImageCodeMemoryType = EfiBootServicesCode;\r
1051 ImageContext->ImageDataMemoryType = EfiBootServicesData;\r
1052 break;\r
1053\r
1054 case EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER:\r
1055 case EFI_IMAGE_SUBSYSTEM_SAL_RUNTIME_DRIVER:\r
1056 ImageContext->ImageCodeMemoryType = EfiRuntimeServicesCode;\r
1057 ImageContext->ImageDataMemoryType = EfiRuntimeServicesData;\r
1058 break;\r
1059\r
1060 default:\r
1061 ImageContext->ImageError = IMAGE_ERROR_INVALID_SUBSYSTEM;\r
1062 return RETURN_UNSUPPORTED;\r
1063 }\r
1064\r
1065 return Status;\r
1066}\r
1067\r
1068EFI_STATUS\r
1069EFIAPI\r
1070SecNt32PeCoffLoadImage (\r
1071 IN EFI_PEI_PE_COFF_LOADER_PROTOCOL *This,\r
1072 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext\r
1073 )\r
1074{\r
1075 EFI_STATUS Status;\r
1076\r
1077 Status = PeCoffLoaderLoadImage (ImageContext);\r
1078 return Status;\r
1079}\r
1080\r
1081EFI_STATUS\r
1082EFIAPI\r
1083SecNt32PeCoffRelocateImage (\r
1084 IN EFI_PEI_PE_COFF_LOADER_PROTOCOL *This,\r
1085 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext\r
1086 )\r
1087{\r
1088 EFI_STATUS Status;\r
1089 VOID *DllEntryPoint;\r
1090 CHAR16 *DllFileName;\r
1091 HMODULE Library;\r
1092 UINTN Index;\r
1093\r
1094\r
1095 Status = PeCoffLoaderRelocateImage (ImageContext);\r
1096 if (EFI_ERROR (Status)) {\r
1097 //\r
1098 // We could not relocated the image in memory properly\r
1099 //\r
1100 return Status;\r
1101 }\r
1102\r
1103 //\r
1104 // If we load our own PE COFF images the Windows debugger can not source\r
1105 // level debug our code. If a valid PDB pointer exists usw it to load\r
1106 // the *.dll file as a library using Windows* APIs. This allows \r
1107 // source level debug. The image is still loaded and reloaced\r
1108 // in the Framework memory space like on a real system (by the code above),\r
1109 // but the entry point points into the DLL loaded by the code bellow. \r
1110 //\r
1111\r
1112 DllEntryPoint = NULL;\r
1113\r
1114 //\r
1115 // Load the DLL if it's not an EBC image.\r
1116 //\r
1117 if ((ImageContext->PdbPointer != NULL) &&\r
1118 (ImageContext->Machine != EFI_IMAGE_MACHINE_EBC)) {\r
1119 //\r
1120 // Convert filename from ASCII to Unicode\r
1121 //\r
1122 DllFileName = AsciiToUnicode (ImageContext->PdbPointer, &Index);\r
1123\r
1124 //\r
1125 // Check that we have a valid filename\r
1126 //\r
1127 if (Index < 5 || DllFileName[Index - 4] != '.') {\r
1128 free (DllFileName);\r
1129\r
1130 //\r
1131 // Never return an error if PeCoffLoaderRelocateImage() succeeded.\r
1132 // The image will run, but we just can't source level debug. If we\r
1133 // return an error the image will not run.\r
1134 //\r
1135 return EFI_SUCCESS;\r
1136 }\r
1137 //\r
1138 // Replace .PDB with .DLL on the filename\r
1139 //\r
1140 DllFileName[Index - 3] = 'D';\r
1141 DllFileName[Index - 2] = 'L';\r
1142 DllFileName[Index - 1] = 'L';\r
1143\r
1144 //\r
1145 // Load the .DLL file into the user process's address space for source \r
1146 // level debug\r
1147 //\r
1148 Library = LoadLibraryEx (DllFileName, NULL, DONT_RESOLVE_DLL_REFERENCES);\r
1149 if (Library != NULL) {\r
1150 //\r
1151 // InitializeDriver is the entry point we put in all our EFI DLL's. The\r
1152 // DONT_RESOLVE_DLL_REFERENCES argument to LoadLIbraryEx() supresses the \r
1153 // normal DLL entry point of DllMain, and prevents other modules that are\r
1154 // referenced in side the DllFileName from being loaded. There is no error \r
1155 // checking as the we can point to the PE32 image loaded by Tiano. This \r
1156 // step is only needed for source level debuging\r
1157 //\r
1158 DllEntryPoint = (VOID *) (UINTN) GetProcAddress (Library, "InitializeDriver");\r
1159\r
1160 }\r
1161\r
1162 if ((Library != NULL) && (DllEntryPoint != NULL)) {\r
1163 AddModHandle (ImageContext, Library);\r
1164 ImageContext->EntryPoint = (EFI_PHYSICAL_ADDRESS) (UINTN) DllEntryPoint;\r
1165 wprintf (L"LoadLibraryEx (%s,\n NULL, DONT_RESOLVE_DLL_REFERENCES)\n", DllFileName);\r
1166 } else {\r
1167 wprintf (L"WARNING: No source level debug %s. \n", DllFileName);\r
1168 }\r
1169\r
1170 free (DllFileName);\r
1171 }\r
1172\r
1173 //\r
1174 // Never return an error if PeCoffLoaderRelocateImage() succeeded.\r
1175 // The image will run, but we just can't source level debug. If we\r
1176 // return an error the image will not run.\r
1177 //\r
1178 return EFI_SUCCESS;\r
1179}\r
1180\r
1181\r
1182EFI_STATUS\r
1183EFIAPI\r
1184SecNt32PeCoffUnloadimage (\r
1185 IN EFI_PEI_PE_COFF_LOADER_PROTOCOL *This,\r
1186 IN PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext\r
1187 )\r
1188{\r
1189 VOID *ModHandle;\r
1190\r
1191 ModHandle = RemoveModeHandle (ImageContext);\r
1192 if (ModHandle != NULL) {\r
1193 FreeLibrary (ModHandle);\r
1194 }\r
1195 return EFI_SUCCESS;\r
1196}\r
1197\r
1198VOID\r
1199_ModuleEntryPoint (\r
1200 VOID\r
1201 )\r
1202{\r
1203}\r
1204\r