1 /**@file
2   WinNt emulator of pre-SEC phase. It's really a Win32 application, but this is
3   Ok since all the other modules for NT32 are NOT Win32 applications.
4 
5   This program gets NT32 PCD setting and figures out what the memory layout
6   will be, how may FD's will be loaded and also what the boot mode is.
7 
8   This code produces 128 K of temporary memory for the SEC stack by directly
9   allocate memory space with ReadWrite and Execute attribute.
10 
11 Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
12 (C) Copyright 2016-2020 Hewlett Packard Enterprise Development LP<BR>
13 SPDX-License-Identifier: BSD-2-Clause-Patent
14 **/
15 
16 #include "WinHost.h"
17 
18 #ifndef SE_TIME_ZONE_NAME
19 #define SE_TIME_ZONE_NAME                 TEXT("SeTimeZonePrivilege")
20 #endif
21 
22 //
23 // The growth size for array of module handle entries
24 //
25 #define MAX_PDB_NAME_TO_MOD_HANDLE_ARRAY_SIZE 0x100
26 
27 //
28 // Module handle entry structure
29 //
30 typedef struct {
31   CHAR8   *PdbPointer;
32   VOID    *ModHandle;
33 } PDB_NAME_TO_MOD_HANDLE;
34 
35 //
36 // An Array to hold the module handles
37 //
38 PDB_NAME_TO_MOD_HANDLE  *mPdbNameModHandleArray = NULL;
39 UINTN                   mPdbNameModHandleArraySize = 0;
40 
41 //
42 // Default information about where the FD is located.
43 //  This array gets filled in with information from PcdWinNtFirmwareVolume
44 //  The number of array elements is allocated base on parsing
45 //  PcdWinNtFirmwareVolume and the memory is never freed.
46 //
47 UINTN                                     gFdInfoCount = 0;
48 NT_FD_INFO                                *gFdInfo;
49 
50 //
51 // Array that supports separate memory ranges.
52 //  The memory ranges are set by PcdWinNtMemorySizeForSecMain.
53 //  The number of array elements is allocated base on parsing
54 //  PcdWinNtMemorySizeForSecMain value and the memory is never freed.
55 //
56 UINTN                                     gSystemMemoryCount = 0;
57 NT_SYSTEM_MEMORY                          *gSystemMemory;
58 
59 /*++
60 
61 Routine Description:
62   This service is called from Index == 0 until it returns EFI_UNSUPPORTED.
63   It allows discontinuous memory regions to be supported by the emulator.
64   It uses gSystemMemory[] and gSystemMemoryCount that were created by
65   parsing the host environment variable EFI_MEMORY_SIZE.
66   The size comes from the varaible and the address comes from the call to
67   UnixOpenFile.
68 
69 Arguments:
70   Index      - Which memory region to use
71   MemoryBase - Return Base address of memory region
72   MemorySize - Return size in bytes of the memory region
73 
74 Returns:
75   EFI_SUCCESS - If memory region was mapped
76   EFI_UNSUPPORTED - If Index is not supported
77 
78 **/
79 EFI_STATUS
WinPeiAutoScan(IN UINTN Index,OUT EFI_PHYSICAL_ADDRESS * MemoryBase,OUT UINT64 * MemorySize)80 WinPeiAutoScan (
81   IN  UINTN                 Index,
82   OUT EFI_PHYSICAL_ADDRESS  *MemoryBase,
83   OUT UINT64                *MemorySize
84   )
85 {
86   if (Index >= gSystemMemoryCount) {
87     return EFI_UNSUPPORTED;
88   }
89 
90   //
91   // Allocate enough memory space for emulator
92   //
93   gSystemMemory[Index].Memory = (EFI_PHYSICAL_ADDRESS) (UINTN) VirtualAlloc (NULL, (SIZE_T) (gSystemMemory[Index].Size), MEM_COMMIT, PAGE_EXECUTE_READWRITE);
94   if (gSystemMemory[Index].Memory == 0) {
95     return EFI_OUT_OF_RESOURCES;
96   }
97 
98   *MemoryBase = gSystemMemory[Index].Memory;
99   *MemorySize = gSystemMemory[Index].Size;
100 
101   return EFI_SUCCESS;
102 }
103 
104 /*++
105 
106 Routine Description:
107   Return the FD Size and base address. Since the FD is loaded from a
108   file into host memory only the SEC will know its address.
109 
110 Arguments:
111   Index  - Which FD, starts at zero.
112   FdSize - Size of the FD in bytes
113   FdBase - Start address of the FD. Assume it points to an FV Header
114   FixUp  - Difference between actual FD address and build address
115 
116 Returns:
117   EFI_SUCCESS     - Return the Base address and size of the FV
118   EFI_UNSUPPORTED - Index does nto map to an FD in the system
119 
120 **/
121 EFI_STATUS
WinFdAddress(IN UINTN Index,IN OUT EFI_PHYSICAL_ADDRESS * FdBase,IN OUT UINT64 * FdSize,IN OUT EFI_PHYSICAL_ADDRESS * FixUp)122 WinFdAddress (
123   IN     UINTN                 Index,
124   IN OUT EFI_PHYSICAL_ADDRESS  *FdBase,
125   IN OUT UINT64                *FdSize,
126   IN OUT EFI_PHYSICAL_ADDRESS  *FixUp
127   )
128 {
129   if (Index >= gFdInfoCount) {
130     return EFI_UNSUPPORTED;
131   }
132 
133 
134   *FdBase = (EFI_PHYSICAL_ADDRESS)(UINTN)gFdInfo[Index].Address;
135   *FdSize = (UINT64)gFdInfo[Index].Size;
136   *FixUp  = 0;
137 
138   if (*FdBase == 0 && *FdSize == 0) {
139     return EFI_UNSUPPORTED;
140   }
141 
142   if (Index == 0) {
143     //
144     // FD 0 has XIP code and well known PCD values
145     // If the memory buffer could not be allocated at the FD build address
146     // the Fixup is the difference.
147     //
148     *FixUp = *FdBase - PcdGet64 (PcdEmuFdBaseAddress);
149   }
150 
151   return EFI_SUCCESS;
152 }
153 
154 /*++
155 
156 Routine Description:
157   Since the SEC is the only Unix program in stack it must export
158   an interface to do POSIX calls.  gUnix is initialized in UnixThunk.c.
159 
160 Arguments:
161   InterfaceSize - sizeof (EFI_WIN_NT_THUNK_PROTOCOL);
162   InterfaceBase - Address of the gUnix global
163 
164 Returns:
165   EFI_SUCCESS - Data returned
166 
167 **/
168 VOID *
WinThunk(VOID)169 WinThunk (
170   VOID
171   )
172 {
173   return &gEmuThunkProtocol;
174 }
175 
176 
177 EMU_THUNK_PPI mSecEmuThunkPpi = {
178   WinPeiAutoScan,
179   WinFdAddress,
180   WinThunk
181 };
182 
183 VOID
SecPrint(CHAR8 * Format,...)184 SecPrint (
185   CHAR8  *Format,
186   ...
187   )
188 {
189   va_list  Marker;
190   UINTN    CharCount;
191   CHAR8    Buffer[0x1000];
192 
193   va_start (Marker, Format);
194 
195   _vsnprintf (Buffer, sizeof (Buffer), Format, Marker);
196 
197   va_end (Marker);
198 
199   CharCount = strlen (Buffer);
200   WriteFile (
201     GetStdHandle (STD_OUTPUT_HANDLE),
202     Buffer,
203     (DWORD)CharCount,
204     (LPDWORD)&CharCount,
205     NULL
206     );
207 }
208 
209 /*++
210 
211 Routine Description:
212  Check to see if an address range is in the EFI GCD memory map.
213 
214  This is all of GCD for system memory passed to DXE Core. FV
215  mapping and other device mapped into system memory are not
216  inlcuded in the check.
217 
218 Arguments:
219   Index      - Which memory region to use
220   MemoryBase - Return Base address of memory region
221   MemorySize - Return size in bytes of the memory region
222 
223 Returns:
224   TRUE -  Address is in the EFI GCD memory map
225   FALSE - Address is NOT in memory map
226 
227 **/
228 BOOLEAN
EfiSystemMemoryRange(IN VOID * MemoryAddress)229 EfiSystemMemoryRange (
230   IN  VOID *MemoryAddress
231   )
232 {
233   UINTN                 Index;
234   EFI_PHYSICAL_ADDRESS  MemoryBase;
235 
236   MemoryBase = (EFI_PHYSICAL_ADDRESS)(UINTN)MemoryAddress;
237   for (Index = 0; Index < gSystemMemoryCount; Index++) {
238     if ((MemoryBase >= gSystemMemory[Index].Memory) &&
239         (MemoryBase < (gSystemMemory[Index].Memory + gSystemMemory[Index].Size)) ) {
240       return TRUE;
241     }
242   }
243 
244   return FALSE;
245 }
246 
247 
248 EFI_STATUS
WinNtOpenFile(IN CHAR16 * FileName,OPTIONAL IN UINT32 MapSize,IN DWORD CreationDisposition,IN OUT VOID ** BaseAddress,OUT UINTN * Length)249 WinNtOpenFile (
250   IN  CHAR16                    *FileName,            OPTIONAL
251   IN  UINT32                    MapSize,
252   IN  DWORD                     CreationDisposition,
253   IN OUT  VOID                  **BaseAddress,
254   OUT UINTN                     *Length
255   )
256 /*++
257 
258 Routine Description:
259   Opens and memory maps a file using WinNt services. If *BaseAddress is non zero
260   the process will try and allocate the memory starting at BaseAddress.
261 
262 Arguments:
263   FileName            - The name of the file to open and map
264   MapSize             - The amount of the file to map in bytes
265   CreationDisposition - The flags to pass to CreateFile().  Use to create new files for
266                         memory emulation, and exiting files for firmware volume emulation
267   BaseAddress         - The base address of the mapped file in the user address space.
268                          If *BaseAddress is 0, the new memory region is used.
269                          If *BaseAddress is not 0, the request memory region is used for
270                           the mapping of the file into the process space.
271   Length              - The size of the mapped region in bytes
272 
273 Returns:
274   EFI_SUCCESS      - The file was opened and mapped.
275   EFI_NOT_FOUND    - FileName was not found in the current directory
276   EFI_DEVICE_ERROR - An error occurred attempting to map the opened file
277 
278 --*/
279 {
280   HANDLE  NtFileHandle;
281   HANDLE  NtMapHandle;
282   VOID    *VirtualAddress;
283   UINTN   FileSize;
284 
285   //
286   // Use Win API to open/create a file
287   //
288   NtFileHandle = INVALID_HANDLE_VALUE;
289   if (FileName != NULL) {
290     NtFileHandle = CreateFile (
291                      FileName,
292                      GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE,
293                      FILE_SHARE_READ,
294                      NULL,
295                      CreationDisposition,
296                      FILE_ATTRIBUTE_NORMAL,
297                      NULL
298                      );
299     if (NtFileHandle == INVALID_HANDLE_VALUE) {
300       return EFI_NOT_FOUND;
301     }
302   }
303   //
304   // Map the open file into a memory range
305   //
306   NtMapHandle = CreateFileMapping (
307                   NtFileHandle,
308                   NULL,
309                   PAGE_EXECUTE_READWRITE,
310                   0,
311                   MapSize,
312                   NULL
313                   );
314   if (NtMapHandle == NULL) {
315     return EFI_DEVICE_ERROR;
316   }
317   //
318   // Get the virtual address (address in the emulator) of the mapped file
319   //
320   VirtualAddress = MapViewOfFileEx (
321                     NtMapHandle,
322                     FILE_MAP_EXECUTE | FILE_MAP_ALL_ACCESS,
323                     0,
324                     0,
325                     MapSize,
326                     *BaseAddress
327                     );
328   if (VirtualAddress == NULL) {
329     return EFI_DEVICE_ERROR;
330   }
331 
332   if (MapSize == 0) {
333     //
334     // Seek to the end of the file to figure out the true file size.
335     //
336     FileSize = SetFilePointer (
337                 NtFileHandle,
338                 0,
339                 NULL,
340                 FILE_END
341                 );
342     if (FileSize == -1) {
343       return EFI_DEVICE_ERROR;
344     }
345 
346     *Length = FileSize;
347   } else {
348     *Length = MapSize;
349   }
350 
351   *BaseAddress = VirtualAddress;
352 
353   return EFI_SUCCESS;
354 }
355 
356 INTN
357 EFIAPI
main(IN INT Argc,IN CHAR8 ** Argv,IN CHAR8 ** Envp)358 main (
359   IN  INT  Argc,
360   IN  CHAR8 **Argv,
361   IN  CHAR8 **Envp
362   )
363 /*++
364 
365 Routine Description:
366   Main entry point to SEC for WinNt. This is a Windows program
367 
368 Arguments:
369   Argc - Number of command line arguments
370   Argv - Array of command line argument strings
371   Envp - Array of environment variable strings
372 
373 Returns:
374   0 - Normal exit
375   1 - Abnormal exit
376 
377 --*/
378 {
379   EFI_STATUS            Status;
380   HANDLE                Token;
381   TOKEN_PRIVILEGES      TokenPrivileges;
382   VOID                  *TemporaryRam;
383   UINT32                TemporaryRamSize;
384   VOID                  *EmuMagicPage;
385   UINTN                 Index;
386   UINTN                 Index1;
387   CHAR16                *FileName;
388   CHAR16                *FileNamePtr;
389   BOOLEAN               Done;
390   EFI_PEI_FILE_HANDLE   FileHandle;
391   VOID                  *SecFile;
392   CHAR16                *MemorySizeStr;
393   CHAR16                *FirmwareVolumesStr;
394   UINTN                 ProcessAffinityMask;
395   UINTN                 SystemAffinityMask;
396   INT32                 LowBit;
397 
398   //
399   // Enable the privilege so that RTC driver can successfully run SetTime()
400   //
401   OpenProcessToken (GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES|TOKEN_QUERY, &Token);
402   if (LookupPrivilegeValue(NULL, SE_TIME_ZONE_NAME, &TokenPrivileges.Privileges[0].Luid)) {
403     TokenPrivileges.PrivilegeCount = 1;
404     TokenPrivileges.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
405     AdjustTokenPrivileges(Token, FALSE, &TokenPrivileges, 0, (PTOKEN_PRIVILEGES) NULL, 0);
406   }
407 
408   MemorySizeStr      = (CHAR16 *) PcdGetPtr (PcdEmuMemorySize);
409   FirmwareVolumesStr = (CHAR16 *) PcdGetPtr (PcdEmuFirmwareVolume);
410 
411   SecPrint ("\n\rEDK II WIN Host Emulation Environment from http://www.tianocore.org/edk2/\n\r");
412 
413   //
414   // Determine the first thread available to this process.
415   //
416   if (GetProcessAffinityMask (GetCurrentProcess (), &ProcessAffinityMask, &SystemAffinityMask)) {
417     LowBit = (INT32)LowBitSet32 ((UINT32)ProcessAffinityMask);
418     if (LowBit != -1) {
419       //
420       // Force the system to bind the process to a single thread to work
421       // around odd semaphore type crashes.
422       //
423       SetProcessAffinityMask (GetCurrentProcess (), (INTN)(BIT0 << LowBit));
424     }
425   }
426 
427   //
428   // Make some Windows calls to Set the process to the highest priority in the
429   //  idle class. We need this to have good performance.
430   //
431   SetPriorityClass (GetCurrentProcess (), IDLE_PRIORITY_CLASS);
432   SetThreadPriority (GetCurrentThread (), THREAD_PRIORITY_HIGHEST);
433 
434   SecInitializeThunk ();
435   //
436   // PPIs pased into PEI_CORE
437   //
438   AddThunkPpi (EFI_PEI_PPI_DESCRIPTOR_PPI, &gEmuThunkPpiGuid, &mSecEmuThunkPpi);
439 
440   //
441   // Emulator Bus Driver Thunks
442   //
443   AddThunkProtocol (&mWinNtWndThunkIo, (CHAR16 *)PcdGetPtr (PcdEmuGop), TRUE);
444   AddThunkProtocol (&mWinNtFileSystemThunkIo, (CHAR16 *)PcdGetPtr (PcdEmuFileSystem), TRUE);
445   AddThunkProtocol (&mWinNtBlockIoThunkIo, (CHAR16 *)PcdGetPtr (PcdEmuVirtualDisk), TRUE);
446   AddThunkProtocol (&mWinNtSnpThunkIo, (CHAR16 *)PcdGetPtr (PcdEmuNetworkInterface), TRUE);
447 
448   //
449   // Allocate space for gSystemMemory Array
450   //
451   gSystemMemoryCount  = CountSeparatorsInString (MemorySizeStr, '!') + 1;
452   gSystemMemory       = calloc (gSystemMemoryCount, sizeof (NT_SYSTEM_MEMORY));
453   if (gSystemMemory == NULL) {
454     SecPrint ("ERROR : Can not allocate memory for %S.  Exiting.\n\r", MemorySizeStr);
455     exit (1);
456   }
457 
458   //
459   // Allocate space for gSystemMemory Array
460   //
461   gFdInfoCount  = CountSeparatorsInString (FirmwareVolumesStr, '!') + 1;
462   gFdInfo       = calloc (gFdInfoCount, sizeof (NT_FD_INFO));
463   if (gFdInfo == NULL) {
464     SecPrint ("ERROR : Can not allocate memory for %S.  Exiting.\n\r", FirmwareVolumesStr);
465     exit (1);
466   }
467   //
468   // Setup Boot Mode.
469   //
470   SecPrint ("  BootMode 0x%02x\n\r", PcdGet32 (PcdEmuBootMode));
471 
472   //
473   //  Allocate 128K memory to emulate temp memory for PEI.
474   //  on a real platform this would be SRAM, or using the cache as RAM.
475   //  Set TemporaryRam to zero so WinNtOpenFile will allocate a new mapping
476   //
477   TemporaryRamSize = TEMPORARY_RAM_SIZE;
478   TemporaryRam     = VirtualAlloc (NULL, (SIZE_T) (TemporaryRamSize), MEM_COMMIT, PAGE_EXECUTE_READWRITE);
479   if (TemporaryRam == NULL) {
480     SecPrint ("ERROR : Can not allocate enough space for SecStack\n\r");
481     exit (1);
482   }
483   SetMem32 (TemporaryRam, TemporaryRamSize, PcdGet32 (PcdInitValueInTempStack));
484 
485   SecPrint ("  OS Emulator passing in %u KB of temp RAM at 0x%08lx to SEC\n\r",
486     TemporaryRamSize / SIZE_1KB,
487     TemporaryRam
488     );
489 
490   //
491   // If enabled use the magic page to communicate between modules
492   // This replaces the PI PeiServicesTable pointer mechanism that
493   // deos not work in the emulator. It also allows the removal of
494   // writable globals from SEC, PEI_CORE (libraries), PEIMs
495   //
496   EmuMagicPage = (VOID *)(UINTN)(FixedPcdGet64 (PcdPeiServicesTablePage) & MAX_UINTN);
497   if (EmuMagicPage != NULL) {
498     UINT64  Size;
499     Status = WinNtOpenFile (
500               NULL,
501               SIZE_4KB,
502               0,
503               &EmuMagicPage,
504               &Size
505               );
506     if (EFI_ERROR (Status)) {
507       SecPrint ("ERROR : Could not allocate PeiServicesTablePage @ %p\n\r", EmuMagicPage);
508       return EFI_DEVICE_ERROR;
509     }
510   }
511 
512   //
513   // Open All the firmware volumes and remember the info in the gFdInfo global
514   // Meanwhile, find the SEC Core.
515   //
516   FileNamePtr = AllocateCopyPool (StrSize (FirmwareVolumesStr), FirmwareVolumesStr);
517   if (FileNamePtr == NULL) {
518     SecPrint ("ERROR : Can not allocate memory for firmware volume string\n\r");
519     exit (1);
520   }
521 
522   for (Done = FALSE, Index = 0, SecFile = NULL; !Done; Index++) {
523     FileName = FileNamePtr;
524     for (Index1 = 0; (FileNamePtr[Index1] != '!') && (FileNamePtr[Index1] != 0); Index1++)
525       ;
526     if (FileNamePtr[Index1] == 0) {
527       Done = TRUE;
528     } else {
529       FileNamePtr[Index1]  = '\0';
530       FileNamePtr = &FileNamePtr[Index1 + 1];
531     }
532 
533     //
534     // Open the FD and remember where it got mapped into our processes address space
535     //
536     Status = WinNtOpenFile (
537               FileName,
538               0,
539               OPEN_EXISTING,
540               &gFdInfo[Index].Address,
541               &gFdInfo[Index].Size
542               );
543     if (EFI_ERROR (Status)) {
544       SecPrint ("ERROR : Can not open Firmware Device File %S (0x%X).  Exiting.\n\r", FileName, Status);
545       exit (1);
546     }
547 
548     SecPrint ("  FD loaded from %S", FileName);
549 
550     if (SecFile == NULL) {
551       //
552       // Assume the beginning of the FD is an FV and look for the SEC Core.
553       // Load the first one we find.
554       //
555       FileHandle = NULL;
556       Status = PeiServicesFfsFindNextFile (
557                   EFI_FV_FILETYPE_SECURITY_CORE,
558                   (EFI_PEI_FV_HANDLE)gFdInfo[Index].Address,
559                   &FileHandle
560                   );
561       if (!EFI_ERROR (Status)) {
562         Status = PeiServicesFfsFindSectionData (EFI_SECTION_PE32, FileHandle, &SecFile);
563         if (!EFI_ERROR (Status)) {
564           SecPrint (" contains SEC Core");
565         }
566       }
567     }
568 
569     SecPrint ("\n\r");
570   }
571   //
572   // Calculate memory regions and store the information in the gSystemMemory
573   //  global for later use. The autosizing code will use this data to
574   //  map this memory into the SEC process memory space.
575   //
576   for (Index = 0, Done = FALSE; !Done; Index++) {
577     //
578     // Save the size of the memory and make a Unicode filename SystemMemory00, ...
579     //
580     gSystemMemory[Index].Size = ((UINT64)_wtoi (MemorySizeStr)) * ((UINT64)SIZE_1MB);
581 
582     //
583     // Find the next region
584     //
585     for (Index1 = 0; MemorySizeStr[Index1] != '!' && MemorySizeStr[Index1] != 0; Index1++)
586       ;
587     if (MemorySizeStr[Index1] == 0) {
588       Done = TRUE;
589     }
590 
591     MemorySizeStr = MemorySizeStr + Index1 + 1;
592   }
593 
594   SecPrint ("\n\r");
595 
596   //
597   // Hand off to SEC Core
598   //
599   SecLoadSecCore ((UINTN)TemporaryRam, TemporaryRamSize, gFdInfo[0].Address, gFdInfo[0].Size, SecFile);
600 
601   //
602   // If we get here, then the SEC Core returned. This is an error as SEC should
603   //  always hand off to PEI Core and then on to DXE Core.
604   //
605   SecPrint ("ERROR : SEC returned\n\r");
606   exit (1);
607 }
608 
609 VOID
SecLoadSecCore(IN UINTN TemporaryRam,IN UINTN TemporaryRamSize,IN VOID * BootFirmwareVolumeBase,IN UINTN BootFirmwareVolumeSize,IN VOID * SecCorePe32File)610 SecLoadSecCore (
611   IN  UINTN   TemporaryRam,
612   IN  UINTN   TemporaryRamSize,
613   IN  VOID    *BootFirmwareVolumeBase,
614   IN  UINTN   BootFirmwareVolumeSize,
615   IN  VOID    *SecCorePe32File
616   )
617 /*++
618 
619 Routine Description:
620   This is the service to load the SEC Core from the Firmware Volume
621 
622 Arguments:
623   TemporaryRam            - Memory to use for SEC.
624   TemporaryRamSize        - Size of Memory to use for SEC
625   BootFirmwareVolumeBase  - Start of the Boot FV
626   SecCorePe32File         - SEC Core PE32
627 
628 Returns:
629   Success means control is transferred and thus we should never return
630 
631 --*/
632 {
633   EFI_STATUS                  Status;
634   VOID                        *TopOfStack;
635   VOID                        *SecCoreEntryPoint;
636   EFI_SEC_PEI_HAND_OFF        *SecCoreData;
637   UINTN                       SecStackSize;
638 
639   //
640   // Compute Top Of Memory for Stack and PEI Core Allocations
641   //
642   SecStackSize = TemporaryRamSize >> 1;
643 
644   //
645   // |-----------| <---- TemporaryRamBase + TemporaryRamSize
646   // |   Heap    |
647   // |           |
648   // |-----------| <---- StackBase / PeiTemporaryMemoryBase
649   // |           |
650   // |  Stack    |
651   // |-----------| <---- TemporaryRamBase
652   //
653   TopOfStack  = (VOID *)(TemporaryRam + SecStackSize);
654 
655   //
656   // Reservet space for storing PeiCore's parament in stack.
657   //
658   TopOfStack  = (VOID *)((UINTN)TopOfStack - sizeof (EFI_SEC_PEI_HAND_OFF) - CPU_STACK_ALIGNMENT);
659   TopOfStack  = ALIGN_POINTER (TopOfStack, CPU_STACK_ALIGNMENT);
660 
661   //
662   // Bind this information into the SEC hand-off state
663   //
664   SecCoreData                         = (EFI_SEC_PEI_HAND_OFF*)(UINTN)TopOfStack;
665   SecCoreData->DataSize               = sizeof (EFI_SEC_PEI_HAND_OFF);
666   SecCoreData->BootFirmwareVolumeBase = BootFirmwareVolumeBase;
667   SecCoreData->BootFirmwareVolumeSize = BootFirmwareVolumeSize;
668   SecCoreData->TemporaryRamBase       = (VOID*)TemporaryRam;
669   SecCoreData->TemporaryRamSize       = TemporaryRamSize;
670   SecCoreData->StackBase              = SecCoreData->TemporaryRamBase;
671   SecCoreData->StackSize              = SecStackSize;
672   SecCoreData->PeiTemporaryRamBase    = (VOID*) ((UINTN) SecCoreData->TemporaryRamBase + SecStackSize);
673   SecCoreData->PeiTemporaryRamSize    = TemporaryRamSize - SecStackSize;
674 
675   //
676   // Load the PEI Core from a Firmware Volume
677   //
678   Status = SecPeCoffGetEntryPoint (
679             SecCorePe32File,
680             &SecCoreEntryPoint
681             );
682   if (EFI_ERROR (Status)) {
683     return ;
684   }
685 
686   //
687   // Transfer control to the SEC Core
688   //
689   SwitchStack (
690     (SWITCH_STACK_ENTRY_POINT)(UINTN)SecCoreEntryPoint,
691     SecCoreData,
692     GetThunkPpiList (),
693     TopOfStack
694     );
695   //
696   // If we get here, then the SEC Core returned.  This is an error
697   //
698   return ;
699 }
700 
701 RETURN_STATUS
702 EFIAPI
SecPeCoffGetEntryPoint(IN VOID * Pe32Data,IN OUT VOID ** EntryPoint)703 SecPeCoffGetEntryPoint (
704   IN     VOID  *Pe32Data,
705   IN OUT VOID  **EntryPoint
706   )
707 {
708   EFI_STATUS                            Status;
709   PE_COFF_LOADER_IMAGE_CONTEXT          ImageContext;
710 
711   ZeroMem (&ImageContext, sizeof (ImageContext));
712   ImageContext.Handle     = Pe32Data;
713 
714   ImageContext.ImageRead  = (PE_COFF_LOADER_READ_FILE) SecImageRead;
715 
716   Status                  = PeCoffLoaderGetImageInfo (&ImageContext);
717   if (EFI_ERROR (Status)) {
718     return Status;
719   }
720   //
721   // Allocate space in NT (not emulator) memory with ReadWrite and Execute attribute.
722   // Extra space is for alignment
723   //
724   ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS) (UINTN) VirtualAlloc (NULL, (SIZE_T) (ImageContext.ImageSize + (ImageContext.SectionAlignment * 2)), MEM_COMMIT, PAGE_EXECUTE_READWRITE);
725   if (ImageContext.ImageAddress == 0) {
726     return EFI_OUT_OF_RESOURCES;
727   }
728   //
729   // Align buffer on section boundary
730   //
731   ImageContext.ImageAddress += ImageContext.SectionAlignment - 1;
732   ImageContext.ImageAddress &= ~((EFI_PHYSICAL_ADDRESS)ImageContext.SectionAlignment - 1);
733 
734   Status = PeCoffLoaderLoadImage (&ImageContext);
735   if (EFI_ERROR (Status)) {
736     return Status;
737   }
738 
739   Status = PeCoffLoaderRelocateImage (&ImageContext);
740   if (EFI_ERROR (Status)) {
741     return Status;
742   }
743 
744   *EntryPoint   = (VOID *)(UINTN)ImageContext.EntryPoint;
745 
746   return EFI_SUCCESS;
747 }
748 
749 EFI_STATUS
750 EFIAPI
SecImageRead(IN VOID * FileHandle,IN UINTN FileOffset,IN OUT UINTN * ReadSize,OUT VOID * Buffer)751 SecImageRead (
752   IN     VOID    *FileHandle,
753   IN     UINTN   FileOffset,
754   IN OUT UINTN   *ReadSize,
755   OUT    VOID    *Buffer
756   )
757 /*++
758 
759 Routine Description:
760   Support routine for the PE/COFF Loader that reads a buffer from a PE/COFF file
761 
762 Arguments:
763   FileHandle - The handle to the PE/COFF file
764   FileOffset - The offset, in bytes, into the file to read
765   ReadSize   - The number of bytes to read from the file starting at FileOffset
766   Buffer     - A pointer to the buffer to read the data into.
767 
768 Returns:
769   EFI_SUCCESS - ReadSize bytes of data were read into Buffer from the PE/COFF file starting at FileOffset
770 
771 --*/
772 {
773   CHAR8 *Destination8;
774   CHAR8 *Source8;
775   UINTN Length;
776 
777   Destination8  = Buffer;
778   Source8       = (CHAR8 *) ((UINTN) FileHandle + FileOffset);
779   Length        = *ReadSize;
780   while (Length--) {
781     *(Destination8++) = *(Source8++);
782   }
783 
784   return EFI_SUCCESS;
785 }
786 
787 CHAR16 *
AsciiToUnicode(IN CHAR8 * Ascii,IN UINTN * StrLen OPTIONAL)788 AsciiToUnicode (
789   IN  CHAR8   *Ascii,
790   IN  UINTN   *StrLen OPTIONAL
791   )
792 /*++
793 
794 Routine Description:
795   Convert the passed in Ascii string to Unicode.
796   Optionally return the length of the strings.
797 
798 Arguments:
799   Ascii   - Ascii string to convert
800   StrLen  - Length of string
801 
802 Returns:
803   Pointer to malloc'ed Unicode version of Ascii
804 
805 --*/
806 {
807   UINTN   Index;
808   CHAR16  *Unicode;
809 
810   //
811   // Allocate a buffer for unicode string
812   //
813   for (Index = 0; Ascii[Index] != '\0'; Index++)
814     ;
815   Unicode = malloc ((Index + 1) * sizeof (CHAR16));
816   if (Unicode == NULL) {
817     return NULL;
818   }
819 
820   for (Index = 0; Ascii[Index] != '\0'; Index++) {
821     Unicode[Index] = (CHAR16) Ascii[Index];
822   }
823 
824   Unicode[Index] = '\0';
825 
826   if (StrLen != NULL) {
827     *StrLen = Index;
828   }
829 
830   return Unicode;
831 }
832 
833 UINTN
CountSeparatorsInString(IN CONST CHAR16 * String,IN CHAR16 Separator)834 CountSeparatorsInString (
835   IN  CONST CHAR16   *String,
836   IN  CHAR16         Separator
837   )
838 /*++
839 
840 Routine Description:
841   Count the number of separators in String
842 
843 Arguments:
844   String    - String to process
845   Separator - Item to count
846 
847 Returns:
848   Number of Separator in String
849 
850 --*/
851 {
852   UINTN Count;
853 
854   for (Count = 0; *String != '\0'; String++) {
855     if (*String == Separator) {
856       Count++;
857     }
858   }
859 
860   return Count;
861 }
862 
863 /**
864   Store the ModHandle in an array indexed by the Pdb File name.
865   The ModHandle is needed to unload the image.
866   @param ImageContext - Input data returned from PE Laoder Library. Used to find the
867                  .PDB file name of the PE Image.
868   @param ModHandle    - Returned from LoadLibraryEx() and stored for call to
869                  FreeLibrary().
870   @return   return EFI_SUCCESS when ModHandle was stored.
871 --*/
872 EFI_STATUS
AddModHandle(IN PE_COFF_LOADER_IMAGE_CONTEXT * ImageContext,IN VOID * ModHandle)873 AddModHandle (
874   IN  PE_COFF_LOADER_IMAGE_CONTEXT         *ImageContext,
875   IN  VOID                                 *ModHandle
876   )
877 
878 {
879   UINTN                   Index;
880   PDB_NAME_TO_MOD_HANDLE  *Array;
881   UINTN                   PreviousSize;
882   PDB_NAME_TO_MOD_HANDLE  *TempArray;
883   HANDLE                  Handle;
884   UINTN                   Size;
885 
886   //
887   // Return EFI_ALREADY_STARTED if this DLL has already been loaded
888   //
889   Array = mPdbNameModHandleArray;
890   for (Index = 0; Index < mPdbNameModHandleArraySize; Index++, Array++) {
891     if (Array->PdbPointer != NULL && Array->ModHandle == ModHandle) {
892       return EFI_ALREADY_STARTED;
893     }
894   }
895 
896   Array = mPdbNameModHandleArray;
897   for (Index = 0; Index < mPdbNameModHandleArraySize; Index++, Array++) {
898     if (Array->PdbPointer == NULL) {
899       //
900       // Make a copy of the stirng and store the ModHandle
901       //
902       Handle = GetProcessHeap ();
903       Size = AsciiStrLen (ImageContext->PdbPointer) + 1;
904       Array->PdbPointer = HeapAlloc ( Handle, HEAP_ZERO_MEMORY, Size);
905       ASSERT (Array->PdbPointer != NULL);
906 
907       AsciiStrCpyS (Array->PdbPointer, Size, ImageContext->PdbPointer);
908       Array->ModHandle = ModHandle;
909       return EFI_SUCCESS;
910     }
911   }
912 
913   //
914   // No free space in mPdbNameModHandleArray so grow it by
915   // MAX_PDB_NAME_TO_MOD_HANDLE_ARRAY_SIZE entires.
916   //
917   PreviousSize = mPdbNameModHandleArraySize * sizeof (PDB_NAME_TO_MOD_HANDLE);
918   mPdbNameModHandleArraySize += MAX_PDB_NAME_TO_MOD_HANDLE_ARRAY_SIZE;
919   //
920   // re-allocate a new buffer and copy the old values to the new locaiton.
921   //
922   TempArray = HeapAlloc (GetProcessHeap (),
923                                 HEAP_ZERO_MEMORY,
924                                 mPdbNameModHandleArraySize * sizeof (PDB_NAME_TO_MOD_HANDLE)
925                                );
926 
927   CopyMem ((VOID *) (UINTN) TempArray, (VOID *) (UINTN)mPdbNameModHandleArray, PreviousSize);
928 
929   HeapFree (GetProcessHeap (), 0, mPdbNameModHandleArray);
930 
931   mPdbNameModHandleArray = TempArray;
932   if (mPdbNameModHandleArray == NULL) {
933     ASSERT (FALSE);
934     return EFI_OUT_OF_RESOURCES;
935   }
936 
937   return AddModHandle (ImageContext, ModHandle);
938 }
939 
940 /**
941   Return the ModHandle and delete the entry in the array.
942    @param  ImageContext - Input data returned from PE Laoder Library. Used to find the
943                  .PDB file name of the PE Image.
944   @return
945     ModHandle - ModHandle assoicated with ImageContext is returned
946     NULL      - No ModHandle associated with ImageContext
947 **/
948 VOID *
RemoveModHandle(IN PE_COFF_LOADER_IMAGE_CONTEXT * ImageContext)949 RemoveModHandle (
950   IN  PE_COFF_LOADER_IMAGE_CONTEXT         *ImageContext
951   )
952 {
953   UINTN                   Index;
954   PDB_NAME_TO_MOD_HANDLE  *Array;
955 
956   if (ImageContext->PdbPointer == NULL) {
957     //
958     // If no PDB pointer there is no ModHandle so return NULL
959     //
960     return NULL;
961   }
962 
963   Array = mPdbNameModHandleArray;
964   for (Index = 0; Index < mPdbNameModHandleArraySize; Index++, Array++) {
965     if ((Array->PdbPointer != NULL) && (AsciiStrCmp(Array->PdbPointer, ImageContext->PdbPointer) == 0)) {
966       //
967       // If you find a match return it and delete the entry
968       //
969       HeapFree (GetProcessHeap (), 0, Array->PdbPointer);
970       Array->PdbPointer = NULL;
971       return Array->ModHandle;
972     }
973   }
974 
975   return NULL;
976 }
977 
978 VOID
979 EFIAPI
PeCoffLoaderRelocateImageExtraAction(IN OUT PE_COFF_LOADER_IMAGE_CONTEXT * ImageContext)980 PeCoffLoaderRelocateImageExtraAction (
981   IN OUT PE_COFF_LOADER_IMAGE_CONTEXT         *ImageContext
982   )
983 {
984   EFI_STATUS        Status;
985   VOID              *DllEntryPoint;
986   CHAR16            *DllFileName;
987   HMODULE           Library;
988   UINTN             Index;
989 
990   ASSERT (ImageContext != NULL);
991   //
992   // If we load our own PE COFF images the Windows debugger can not source
993   //  level debug our code. If a valid PDB pointer exists use it to load
994   //  the *.dll file as a library using Windows* APIs. This allows
995   //  source level debug. The image is still loaded and relocated
996   //  in the Framework memory space like on a real system (by the code above),
997   //  but the entry point points into the DLL loaded by the code below.
998   //
999 
1000   DllEntryPoint = NULL;
1001 
1002   //
1003   // Load the DLL if it's not an EBC image.
1004   //
1005   if ((ImageContext->PdbPointer != NULL) &&
1006       (ImageContext->Machine != EFI_IMAGE_MACHINE_EBC)) {
1007     //
1008     // Convert filename from ASCII to Unicode
1009     //
1010     DllFileName = AsciiToUnicode (ImageContext->PdbPointer, &Index);
1011 
1012     //
1013     // Check that we have a valid filename
1014     //
1015     if (Index < 5 || DllFileName[Index - 4] != '.') {
1016       free (DllFileName);
1017 
1018       //
1019       // Never return an error if PeCoffLoaderRelocateImage() succeeded.
1020       // The image will run, but we just can't source level debug. If we
1021       // return an error the image will not run.
1022       //
1023       return;
1024     }
1025     //
1026     // Replace .PDB with .DLL on the filename
1027     //
1028     DllFileName[Index - 3]  = 'D';
1029     DllFileName[Index - 2]  = 'L';
1030     DllFileName[Index - 1]  = 'L';
1031 
1032     //
1033     // Load the .DLL file into the user process's address space for source
1034     // level debug
1035     //
1036     Library = LoadLibraryEx (DllFileName, NULL, DONT_RESOLVE_DLL_REFERENCES);
1037     if (Library != NULL) {
1038       //
1039       // InitializeDriver is the entry point we put in all our EFI DLL's. The
1040       // DONT_RESOLVE_DLL_REFERENCES argument to LoadLIbraryEx() suppresses the
1041       // normal DLL entry point of DllMain, and prevents other modules that are
1042       // referenced in side the DllFileName from being loaded. There is no error
1043       // checking as the we can point to the PE32 image loaded by Tiano. This
1044       // step is only needed for source level debugging
1045       //
1046       DllEntryPoint = (VOID *) (UINTN) GetProcAddress (Library, "InitializeDriver");
1047 
1048     }
1049 
1050     if ((Library != NULL) && (DllEntryPoint != NULL)) {
1051       Status = AddModHandle (ImageContext, Library);
1052       if (Status == EFI_ALREADY_STARTED) {
1053         //
1054         // If the DLL has already been loaded before, then this instance of the DLL can not be debugged.
1055         //
1056         ImageContext->PdbPointer = NULL;
1057         SecPrint ("WARNING: DLL already loaded.  No source level debug %S.\n\r", DllFileName);
1058       } else {
1059         //
1060         // This DLL is not already loaded, so source level debugging is supported.
1061         //
1062         ImageContext->EntryPoint  = (EFI_PHYSICAL_ADDRESS) (UINTN) DllEntryPoint;
1063         SecPrint ("LoadLibraryEx (\n\r  %S,\n\r  NULL, DONT_RESOLVE_DLL_REFERENCES)\n\r", DllFileName);
1064       }
1065     } else {
1066       SecPrint ("WARNING: No source level debug %S. \n\r", DllFileName);
1067     }
1068 
1069     free (DllFileName);
1070   }
1071 }
1072 
1073 VOID
1074 EFIAPI
PeCoffLoaderUnloadImageExtraAction(IN PE_COFF_LOADER_IMAGE_CONTEXT * ImageContext)1075 PeCoffLoaderUnloadImageExtraAction (
1076   IN PE_COFF_LOADER_IMAGE_CONTEXT  *ImageContext
1077 )
1078 {
1079   VOID  *ModHandle;
1080 
1081   ASSERT (ImageContext != NULL);
1082 
1083   ModHandle = RemoveModHandle (ImageContext);
1084   if (ModHandle != NULL) {
1085     FreeLibrary (ModHandle);
1086     SecPrint ("FreeLibrary (\n\r  %s)\n\r", ImageContext->PdbPointer);
1087   } else {
1088     SecPrint ("WARNING: Unload image without source level debug\n\r");
1089   }
1090 }
1091 
1092 VOID
_ModuleEntryPoint(VOID)1093 _ModuleEntryPoint (
1094   VOID
1095   )
1096 {
1097 }
1098