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