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