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