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