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