]> git.proxmox.com Git - mirror_edk2.git/blame - EmulatorPkg/Win/Host/WinHost.c
EmulatorPkg/host: fix overflow in Mult
[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
19#define SE_TIME_ZONE_NAME TEXT("SeTimeZonePrivilege")\r
20#endif\r
21\r
10ccc27c
MK
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
30typedef 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
38PDB_NAME_TO_MOD_HANDLE *mPdbNameModHandleArray = NULL;\r
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
47UINTN gFdInfoCount = 0;\r
48NT_FD_INFO *gFdInfo;\r
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
56UINTN gSystemMemoryCount = 0;\r
57NT_SYSTEM_MEMORY *gSystemMemory;\r
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
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
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
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
156Routine 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
160Arguments:\r
161 InterfaceSize - sizeof (EFI_WIN_NT_THUNK_PROTOCOL);\r
162 InterfaceBase - Address of the gUnix global\r
163\r
164Returns:\r
165 EFI_SUCCESS - Data returned\r
166\r
167**/\r
168VOID *\r
169WinThunk (\r
170 VOID\r
171 )\r
172{\r
173 return &gEmuThunkProtocol;\r
174}\r
175\r
176\r
177EMU_THUNK_PPI mSecEmuThunkPpi = {\r
178 WinPeiAutoScan,\r
179 WinFdAddress,\r
180 WinThunk\r
181};\r
182\r
183VOID\r
184SecPrint (\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
211Routine 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
218Arguments:\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
223Returns:\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
228BOOLEAN\r
229EfiSystemMemoryRange (\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
248EFI_STATUS\r
249WinNtOpenFile (\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
258Routine 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
262Arguments:\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
273Returns:\r
274 EFI_SUCCESS - The file was opened and mapped.\r
275 EFI_NOT_FOUND - FileName was not found in the current directory\r
3d6b7fd3 276 EFI_DEVICE_ERROR - An error occurred attempting to map the opened file\r
3c859dfe
RN
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
356INTN\r
357EFIAPI\r
358main (\r
2737037a 359 IN INT Argc,\r
3c859dfe
RN
360 IN CHAR8 **Argv,\r
361 IN CHAR8 **Envp\r
362 )\r
363/*++\r
364\r
365Routine Description:\r
366 Main entry point to SEC for WinNt. This is a Windows program\r
367\r
368Arguments:\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
373Returns:\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
2737037a
LG
394 UINTN ProcessAffinityMask;\r
395 UINTN SystemAffinityMask;\r
3c859dfe
RN
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
30b4abc6 411 SecPrint ("\n\rEDK II WIN Host Emulation Environment from http://www.tianocore.org/edk2/\n\r");\r
3c859dfe
RN
412\r
413 //\r
414 // Determine the first thread available to this process.\r
415 //\r
416 if (GetProcessAffinityMask (GetCurrentProcess (), &ProcessAffinityMask, &SystemAffinityMask)) {\r
2737037a 417 LowBit = (INT32)LowBitSet32 ((UINT32)ProcessAffinityMask);\r
3c859dfe
RN
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
7a465451
RN
440 //\r
441 // Emulator Bus Driver Thunks\r
442 //\r
443 AddThunkProtocol (&mWinNtWndThunkIo, (CHAR16 *)PcdGetPtr (PcdEmuGop), TRUE);\r
56502bf1 444 AddThunkProtocol (&mWinNtFileSystemThunkIo, (CHAR16 *)PcdGetPtr (PcdEmuFileSystem), TRUE);\r
8f819697 445 AddThunkProtocol (&mWinNtBlockIoThunkIo, (CHAR16 *)PcdGetPtr (PcdEmuVirtualDisk), TRUE);\r
bb78cfbe 446 AddThunkProtocol (&mWinNtSnpThunkIo, (CHAR16 *)PcdGetPtr (PcdEmuNetworkInterface), TRUE);\r
7a465451 447\r
3c859dfe
RN
448 //\r
449 // Allocate space for gSystemMemory Array\r
450 //\r
451 gSystemMemoryCount = CountSeparatorsInString (MemorySizeStr, '!') + 1;\r
452 gSystemMemory = calloc (gSystemMemoryCount, sizeof (NT_SYSTEM_MEMORY));\r
453 if (gSystemMemory == NULL) {\r
30b4abc6 454 SecPrint ("ERROR : Can not allocate memory for %S. Exiting.\n\r", MemorySizeStr);\r
3c859dfe
RN
455 exit (1);\r
456 }\r
457\r
458 //\r
459 // Allocate space for gSystemMemory Array\r
460 //\r
461 gFdInfoCount = CountSeparatorsInString (FirmwareVolumesStr, '!') + 1;\r
462 gFdInfo = calloc (gFdInfoCount, sizeof (NT_FD_INFO));\r
463 if (gFdInfo == NULL) {\r
30b4abc6 464 SecPrint ("ERROR : Can not allocate memory for %S. Exiting.\n\r", FirmwareVolumesStr);\r
3c859dfe
RN
465 exit (1);\r
466 }\r
467 //\r
468 // Setup Boot Mode.\r
469 //\r
30b4abc6 470 SecPrint (" BootMode 0x%02x\n\r", PcdGet32 (PcdEmuBootMode));\r
3c859dfe
RN
471\r
472 //\r
473 // Allocate 128K memory to emulate temp memory for PEI.\r
474 // on a real platform this would be SRAM, or using the cache as RAM.\r
475 // Set TemporaryRam to zero so WinNtOpenFile will allocate a new mapping\r
476 //\r
477 TemporaryRamSize = TEMPORARY_RAM_SIZE;\r
478 TemporaryRam = VirtualAlloc (NULL, (SIZE_T) (TemporaryRamSize), MEM_COMMIT, PAGE_EXECUTE_READWRITE);\r
479 if (TemporaryRam == NULL) {\r
30b4abc6 480 SecPrint ("ERROR : Can not allocate enough space for SecStack\n\r");\r
3c859dfe
RN
481 exit (1);\r
482 }\r
f89c018f 483 SetMem32 (TemporaryRam, TemporaryRamSize, PcdGet32 (PcdInitValueInTempStack));\r
3c859dfe 484\r
30b4abc6 485 SecPrint (" OS Emulator passing in %u KB of temp RAM at 0x%08lx to SEC\n\r",\r
3c859dfe
RN
486 TemporaryRamSize / SIZE_1KB,\r
487 TemporaryRam\r
488 );\r
489\r
490 //\r
491 // If enabled use the magic page to communicate between modules\r
492 // This replaces the PI PeiServicesTable pointer mechanism that\r
493 // deos not work in the emulator. It also allows the removal of\r
494 // writable globals from SEC, PEI_CORE (libraries), PEIMs\r
495 //\r
496 EmuMagicPage = (VOID *)(UINTN)(FixedPcdGet64 (PcdPeiServicesTablePage) & MAX_UINTN);\r
497 if (EmuMagicPage != NULL) {\r
498 UINT64 Size;\r
499 Status = WinNtOpenFile (\r
500 NULL,\r
501 SIZE_4KB,\r
502 0,\r
503 &EmuMagicPage,\r
504 &Size\r
505 );\r
506 if (EFI_ERROR (Status)) {\r
30b4abc6 507 SecPrint ("ERROR : Could not allocate PeiServicesTablePage @ %p\n\r", EmuMagicPage);\r
3c859dfe
RN
508 return EFI_DEVICE_ERROR;\r
509 }\r
510 }\r
511\r
512 //\r
513 // Open All the firmware volumes and remember the info in the gFdInfo global\r
514 // Meanwhile, find the SEC Core.\r
515 //\r
516 FileNamePtr = AllocateCopyPool (StrSize (FirmwareVolumesStr), FirmwareVolumesStr);\r
517 if (FileNamePtr == NULL) {\r
30b4abc6 518 SecPrint ("ERROR : Can not allocate memory for firmware volume string\n\r");\r
3c859dfe
RN
519 exit (1);\r
520 }\r
521\r
522 for (Done = FALSE, Index = 0, SecFile = NULL; !Done; Index++) {\r
523 FileName = FileNamePtr;\r
524 for (Index1 = 0; (FileNamePtr[Index1] != '!') && (FileNamePtr[Index1] != 0); Index1++)\r
525 ;\r
526 if (FileNamePtr[Index1] == 0) {\r
527 Done = TRUE;\r
528 } else {\r
529 FileNamePtr[Index1] = '\0';\r
530 FileNamePtr = &FileNamePtr[Index1 + 1];\r
531 }\r
532\r
533 //\r
534 // Open the FD and remember where it got mapped into our processes address space\r
535 //\r
536 Status = WinNtOpenFile (\r
537 FileName,\r
538 0,\r
539 OPEN_EXISTING,\r
540 &gFdInfo[Index].Address,\r
541 &gFdInfo[Index].Size\r
542 );\r
543 if (EFI_ERROR (Status)) {\r
30b4abc6 544 SecPrint ("ERROR : Can not open Firmware Device File %S (0x%X). Exiting.\n\r", FileName, Status);\r
3c859dfe
RN
545 exit (1);\r
546 }\r
547\r
30b4abc6 548 SecPrint (" FD loaded from %S", FileName);\r
3c859dfe
RN
549\r
550 if (SecFile == NULL) {\r
551 //\r
552 // Assume the beginning of the FD is an FV and look for the SEC Core.\r
553 // Load the first one we find.\r
554 //\r
555 FileHandle = NULL;\r
556 Status = PeiServicesFfsFindNextFile (\r
557 EFI_FV_FILETYPE_SECURITY_CORE,\r
558 (EFI_PEI_FV_HANDLE)gFdInfo[Index].Address,\r
559 &FileHandle\r
560 );\r
561 if (!EFI_ERROR (Status)) {\r
562 Status = PeiServicesFfsFindSectionData (EFI_SECTION_PE32, FileHandle, &SecFile);\r
563 if (!EFI_ERROR (Status)) {\r
564 SecPrint (" contains SEC Core");\r
565 }\r
566 }\r
567 }\r
568\r
30b4abc6 569 SecPrint ("\n\r");\r
3c859dfe
RN
570 }\r
571 //\r
572 // Calculate memory regions and store the information in the gSystemMemory\r
573 // global for later use. The autosizing code will use this data to\r
574 // map this memory into the SEC process memory space.\r
575 //\r
576 for (Index = 0, Done = FALSE; !Done; Index++) {\r
577 //\r
578 // Save the size of the memory and make a Unicode filename SystemMemory00, ...\r
579 //\r
dd5c7e3c 580 gSystemMemory[Index].Size = ((UINT64)_wtoi (MemorySizeStr)) * ((UINT64)SIZE_1MB);\r
3c859dfe
RN
581\r
582 //\r
583 // Find the next region\r
584 //\r
585 for (Index1 = 0; MemorySizeStr[Index1] != '!' && MemorySizeStr[Index1] != 0; Index1++)\r
586 ;\r
587 if (MemorySizeStr[Index1] == 0) {\r
588 Done = TRUE;\r
589 }\r
590\r
591 MemorySizeStr = MemorySizeStr + Index1 + 1;\r
592 }\r
593\r
30b4abc6 594 SecPrint ("\n\r");\r
3c859dfe
RN
595\r
596 //\r
597 // Hand off to SEC Core\r
598 //\r
599 SecLoadSecCore ((UINTN)TemporaryRam, TemporaryRamSize, gFdInfo[0].Address, gFdInfo[0].Size, SecFile);\r
600\r
601 //\r
602 // If we get here, then the SEC Core returned. This is an error as SEC should\r
603 // always hand off to PEI Core and then on to DXE Core.\r
604 //\r
30b4abc6 605 SecPrint ("ERROR : SEC returned\n\r");\r
3c859dfe
RN
606 exit (1);\r
607}\r
608\r
609VOID\r
610SecLoadSecCore (\r
611 IN UINTN TemporaryRam,\r
612 IN UINTN TemporaryRamSize,\r
613 IN VOID *BootFirmwareVolumeBase,\r
614 IN UINTN BootFirmwareVolumeSize,\r
615 IN VOID *SecCorePe32File\r
616 )\r
617/*++\r
618\r
619Routine Description:\r
620 This is the service to load the SEC Core from the Firmware Volume\r
621\r
622Arguments:\r
623 TemporaryRam - Memory to use for SEC.\r
624 TemporaryRamSize - Size of Memory to use for SEC\r
625 BootFirmwareVolumeBase - Start of the Boot FV\r
626 SecCorePe32File - SEC Core PE32\r
627\r
628Returns:\r
3d6b7fd3 629 Success means control is transferred and thus we should never return\r
3c859dfe
RN
630\r
631--*/\r
632{\r
633 EFI_STATUS Status;\r
634 VOID *TopOfStack;\r
635 VOID *SecCoreEntryPoint;\r
636 EFI_SEC_PEI_HAND_OFF *SecCoreData;\r
637 UINTN SecStackSize;\r
638\r
639 //\r
640 // Compute Top Of Memory for Stack and PEI Core Allocations\r
641 //\r
642 SecStackSize = TemporaryRamSize >> 1;\r
643\r
644 //\r
645 // |-----------| <---- TemporaryRamBase + TemporaryRamSize\r
646 // | Heap |\r
647 // | |\r
648 // |-----------| <---- StackBase / PeiTemporaryMemoryBase\r
649 // | |\r
650 // | Stack |\r
651 // |-----------| <---- TemporaryRamBase\r
652 //\r
653 TopOfStack = (VOID *)(TemporaryRam + SecStackSize);\r
654\r
655 //\r
656 // Reservet space for storing PeiCore's parament in stack.\r
657 //\r
658 TopOfStack = (VOID *)((UINTN)TopOfStack - sizeof (EFI_SEC_PEI_HAND_OFF) - CPU_STACK_ALIGNMENT);\r
659 TopOfStack = ALIGN_POINTER (TopOfStack, CPU_STACK_ALIGNMENT);\r
660\r
661 //\r
662 // Bind this information into the SEC hand-off state\r
663 //\r
664 SecCoreData = (EFI_SEC_PEI_HAND_OFF*)(UINTN)TopOfStack;\r
665 SecCoreData->DataSize = sizeof (EFI_SEC_PEI_HAND_OFF);\r
666 SecCoreData->BootFirmwareVolumeBase = BootFirmwareVolumeBase;\r
667 SecCoreData->BootFirmwareVolumeSize = BootFirmwareVolumeSize;\r
668 SecCoreData->TemporaryRamBase = (VOID*)TemporaryRam;\r
669 SecCoreData->TemporaryRamSize = TemporaryRamSize;\r
670 SecCoreData->StackBase = SecCoreData->TemporaryRamBase;\r
671 SecCoreData->StackSize = SecStackSize;\r
672 SecCoreData->PeiTemporaryRamBase = (VOID*) ((UINTN) SecCoreData->TemporaryRamBase + SecStackSize);\r
673 SecCoreData->PeiTemporaryRamSize = TemporaryRamSize - SecStackSize;\r
674\r
675 //\r
676 // Load the PEI Core from a Firmware Volume\r
677 //\r
678 Status = SecPeCoffGetEntryPoint (\r
679 SecCorePe32File,\r
680 &SecCoreEntryPoint\r
681 );\r
682 if (EFI_ERROR (Status)) {\r
683 return ;\r
684 }\r
685\r
686 //\r
687 // Transfer control to the SEC Core\r
688 //\r
689 SwitchStack (\r
f4eaaf1a 690 (SWITCH_STACK_ENTRY_POINT)(UINTN)SecCoreEntryPoint,\r
3c859dfe
RN
691 SecCoreData,\r
692 GetThunkPpiList (),\r
693 TopOfStack\r
694 );\r
695 //\r
696 // If we get here, then the SEC Core returned. This is an error\r
697 //\r
698 return ;\r
699}\r
700\r
701RETURN_STATUS\r
702EFIAPI\r
703SecPeCoffGetEntryPoint (\r
704 IN VOID *Pe32Data,\r
705 IN OUT VOID **EntryPoint\r
706 )\r
707{\r
708 EFI_STATUS Status;\r
709 PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;\r
710\r
711 ZeroMem (&ImageContext, sizeof (ImageContext));\r
712 ImageContext.Handle = Pe32Data;\r
713\r
714 ImageContext.ImageRead = (PE_COFF_LOADER_READ_FILE) SecImageRead;\r
715\r
716 Status = PeCoffLoaderGetImageInfo (&ImageContext);\r
717 if (EFI_ERROR (Status)) {\r
718 return Status;\r
719 }\r
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
724 ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS) (UINTN) VirtualAlloc (NULL, (SIZE_T) (ImageContext.ImageSize + (ImageContext.SectionAlignment * 2)), MEM_COMMIT, PAGE_EXECUTE_READWRITE);\r
725 if (ImageContext.ImageAddress == 0) {\r
726 return EFI_OUT_OF_RESOURCES;\r
727 }\r
728 //\r
729 // Align buffer on section boundary\r
730 //\r
731 ImageContext.ImageAddress += ImageContext.SectionAlignment - 1;\r
732 ImageContext.ImageAddress &= ~((EFI_PHYSICAL_ADDRESS)ImageContext.SectionAlignment - 1);\r
733\r
734 Status = PeCoffLoaderLoadImage (&ImageContext);\r
735 if (EFI_ERROR (Status)) {\r
736 return Status;\r
737 }\r
738\r
739 Status = PeCoffLoaderRelocateImage (&ImageContext);\r
740 if (EFI_ERROR (Status)) {\r
741 return Status;\r
742 }\r
743\r
744 *EntryPoint = (VOID *)(UINTN)ImageContext.EntryPoint;\r
745\r
746 return EFI_SUCCESS;\r
747}\r
748\r
749EFI_STATUS\r
750EFIAPI\r
751SecImageRead (\r
752 IN VOID *FileHandle,\r
753 IN UINTN FileOffset,\r
754 IN OUT UINTN *ReadSize,\r
755 OUT VOID *Buffer\r
756 )\r
757/*++\r
758\r
759Routine Description:\r
760 Support routine for the PE/COFF Loader that reads a buffer from a PE/COFF file\r
761\r
762Arguments:\r
763 FileHandle - The handle to the PE/COFF file\r
764 FileOffset - The offset, in bytes, into the file to read\r
765 ReadSize - The number of bytes to read from the file starting at FileOffset\r
766 Buffer - A pointer to the buffer to read the data into.\r
767\r
768Returns:\r
769 EFI_SUCCESS - ReadSize bytes of data were read into Buffer from the PE/COFF file starting at FileOffset\r
770\r
771--*/\r
772{\r
773 CHAR8 *Destination8;\r
774 CHAR8 *Source8;\r
775 UINTN Length;\r
776\r
777 Destination8 = Buffer;\r
778 Source8 = (CHAR8 *) ((UINTN) FileHandle + FileOffset);\r
779 Length = *ReadSize;\r
780 while (Length--) {\r
781 *(Destination8++) = *(Source8++);\r
782 }\r
783\r
784 return EFI_SUCCESS;\r
785}\r
786\r
787CHAR16 *\r
788AsciiToUnicode (\r
789 IN CHAR8 *Ascii,\r
790 IN UINTN *StrLen OPTIONAL\r
791 )\r
792/*++\r
793\r
794Routine Description:\r
795 Convert the passed in Ascii string to Unicode.\r
796 Optionally return the length of the strings.\r
797\r
798Arguments:\r
799 Ascii - Ascii string to convert\r
800 StrLen - Length of string\r
801\r
802Returns:\r
803 Pointer to malloc'ed Unicode version of Ascii\r
804\r
805--*/\r
806{\r
807 UINTN Index;\r
808 CHAR16 *Unicode;\r
809\r
810 //\r
811 // Allocate a buffer for unicode string\r
812 //\r
813 for (Index = 0; Ascii[Index] != '\0'; Index++)\r
814 ;\r
815 Unicode = malloc ((Index + 1) * sizeof (CHAR16));\r
816 if (Unicode == NULL) {\r
817 return NULL;\r
818 }\r
819\r
820 for (Index = 0; Ascii[Index] != '\0'; Index++) {\r
821 Unicode[Index] = (CHAR16) Ascii[Index];\r
822 }\r
823\r
824 Unicode[Index] = '\0';\r
825\r
826 if (StrLen != NULL) {\r
827 *StrLen = Index;\r
828 }\r
829\r
830 return Unicode;\r
831}\r
832\r
833UINTN\r
834CountSeparatorsInString (\r
835 IN CONST CHAR16 *String,\r
836 IN CHAR16 Separator\r
837 )\r
838/*++\r
839\r
840Routine Description:\r
841 Count the number of separators in String\r
842\r
843Arguments:\r
844 String - String to process\r
845 Separator - Item to count\r
846\r
847Returns:\r
848 Number of Separator in String\r
849\r
850--*/\r
851{\r
852 UINTN Count;\r
853\r
854 for (Count = 0; *String != '\0'; String++) {\r
855 if (*String == Separator) {\r
856 Count++;\r
857 }\r
858 }\r
859\r
860 return Count;\r
861}\r
862\r
10ccc27c
MK
863/**\r
864 Store the ModHandle in an array indexed by the Pdb File name.\r
865 The ModHandle is needed to unload the image.\r
866 @param ImageContext - Input data returned from PE Laoder Library. Used to find the\r
867 .PDB file name of the PE Image.\r
868 @param ModHandle - Returned from LoadLibraryEx() and stored for call to\r
869 FreeLibrary().\r
870 @return return EFI_SUCCESS when ModHandle was stored.\r
871--*/\r
872EFI_STATUS\r
873AddModHandle (\r
874 IN PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext,\r
875 IN VOID *ModHandle\r
876 )\r
877\r
878{\r
879 UINTN Index;\r
880 PDB_NAME_TO_MOD_HANDLE *Array;\r
881 UINTN PreviousSize;\r
882 PDB_NAME_TO_MOD_HANDLE *TempArray;\r
883 HANDLE Handle;\r
884 UINTN Size;\r
885\r
886 //\r
887 // Return EFI_ALREADY_STARTED if this DLL has already been loaded\r
888 //\r
889 Array = mPdbNameModHandleArray;\r
890 for (Index = 0; Index < mPdbNameModHandleArraySize; Index++, Array++) {\r
891 if (Array->PdbPointer != NULL && Array->ModHandle == ModHandle) {\r
892 return EFI_ALREADY_STARTED;\r
893 }\r
894 }\r
895\r
896 Array = mPdbNameModHandleArray;\r
897 for (Index = 0; Index < mPdbNameModHandleArraySize; Index++, Array++) {\r
898 if (Array->PdbPointer == NULL) {\r
899 //\r
900 // Make a copy of the stirng and store the ModHandle\r
901 //\r
902 Handle = GetProcessHeap ();\r
903 Size = AsciiStrLen (ImageContext->PdbPointer) + 1;\r
904 Array->PdbPointer = HeapAlloc ( Handle, HEAP_ZERO_MEMORY, Size);\r
905 ASSERT (Array->PdbPointer != NULL);\r
906\r
907 AsciiStrCpyS (Array->PdbPointer, Size, ImageContext->PdbPointer);\r
908 Array->ModHandle = ModHandle;\r
909 return EFI_SUCCESS;\r
910 }\r
911 }\r
912\r
913 //\r
914 // No free space in mPdbNameModHandleArray so grow it by\r
915 // MAX_PDB_NAME_TO_MOD_HANDLE_ARRAY_SIZE entires.\r
916 //\r
917 PreviousSize = mPdbNameModHandleArraySize * sizeof (PDB_NAME_TO_MOD_HANDLE);\r
918 mPdbNameModHandleArraySize += MAX_PDB_NAME_TO_MOD_HANDLE_ARRAY_SIZE;\r
919 //\r
920 // re-allocate a new buffer and copy the old values to the new locaiton.\r
921 //\r
922 TempArray = HeapAlloc (GetProcessHeap (),\r
923 HEAP_ZERO_MEMORY,\r
924 mPdbNameModHandleArraySize * sizeof (PDB_NAME_TO_MOD_HANDLE)\r
925 );\r
926\r
927 CopyMem ((VOID *) (UINTN) TempArray, (VOID *) (UINTN)mPdbNameModHandleArray, PreviousSize);\r
928\r
929 HeapFree (GetProcessHeap (), 0, mPdbNameModHandleArray);\r
930\r
931 mPdbNameModHandleArray = TempArray;\r
932 if (mPdbNameModHandleArray == NULL) {\r
933 ASSERT (FALSE);\r
934 return EFI_OUT_OF_RESOURCES;\r
935 }\r
936\r
937 return AddModHandle (ImageContext, ModHandle);\r
938}\r
939\r
940/**\r
941 Return the ModHandle and delete the entry in the array.\r
942 @param ImageContext - Input data returned from PE Laoder Library. Used to find the\r
943 .PDB file name of the PE Image.\r
944 @return\r
945 ModHandle - ModHandle assoicated with ImageContext is returned\r
946 NULL - No ModHandle associated with ImageContext\r
947**/\r
948VOID *\r
949RemoveModHandle (\r
950 IN PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext\r
951 )\r
952{\r
953 UINTN Index;\r
954 PDB_NAME_TO_MOD_HANDLE *Array;\r
955\r
956 if (ImageContext->PdbPointer == NULL) {\r
957 //\r
958 // If no PDB pointer there is no ModHandle so return NULL\r
959 //\r
960 return NULL;\r
961 }\r
962\r
963 Array = mPdbNameModHandleArray;\r
964 for (Index = 0; Index < mPdbNameModHandleArraySize; Index++, Array++) {\r
965 if ((Array->PdbPointer != NULL) && (AsciiStrCmp(Array->PdbPointer, ImageContext->PdbPointer) == 0)) {\r
966 //\r
967 // If you find a match return it and delete the entry\r
968 //\r
969 HeapFree (GetProcessHeap (), 0, Array->PdbPointer);\r
970 Array->PdbPointer = NULL;\r
971 return Array->ModHandle;\r
972 }\r
973 }\r
974\r
975 return NULL;\r
976}\r
3c859dfe
RN
977\r
978VOID\r
979EFIAPI\r
980PeCoffLoaderRelocateImageExtraAction (\r
981 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext\r
982 )\r
983{\r
10ccc27c 984 EFI_STATUS Status;\r
3c859dfe
RN
985 VOID *DllEntryPoint;\r
986 CHAR16 *DllFileName;\r
987 HMODULE Library;\r
988 UINTN Index;\r
989\r
990 ASSERT (ImageContext != NULL);\r
991 //\r
992 // If we load our own PE COFF images the Windows debugger can not source\r
10ccc27c 993 // level debug our code. If a valid PDB pointer exists use it to load\r
3c859dfe
RN
994 // the *.dll file as a library using Windows* APIs. This allows\r
995 // source level debug. The image is still loaded and relocated\r
996 // in the Framework memory space like on a real system (by the code above),\r
3d6b7fd3 997 // but the entry point points into the DLL loaded by the code below.\r
3c859dfe
RN
998 //\r
999\r
1000 DllEntryPoint = NULL;\r
1001\r
1002 //\r
1003 // Load the DLL if it's not an EBC image.\r
1004 //\r
1005 if ((ImageContext->PdbPointer != NULL) &&\r
1006 (ImageContext->Machine != EFI_IMAGE_MACHINE_EBC)) {\r
1007 //\r
1008 // Convert filename from ASCII to Unicode\r
1009 //\r
1010 DllFileName = AsciiToUnicode (ImageContext->PdbPointer, &Index);\r
1011\r
1012 //\r
1013 // Check that we have a valid filename\r
1014 //\r
1015 if (Index < 5 || DllFileName[Index - 4] != '.') {\r
1016 free (DllFileName);\r
1017\r
1018 //\r
1019 // Never return an error if PeCoffLoaderRelocateImage() succeeded.\r
1020 // The image will run, but we just can't source level debug. If we\r
1021 // return an error the image will not run.\r
1022 //\r
1023 return;\r
1024 }\r
1025 //\r
1026 // Replace .PDB with .DLL on the filename\r
1027 //\r
1028 DllFileName[Index - 3] = 'D';\r
1029 DllFileName[Index - 2] = 'L';\r
1030 DllFileName[Index - 1] = 'L';\r
1031\r
1032 //\r
1033 // Load the .DLL file into the user process's address space for source\r
1034 // level debug\r
1035 //\r
1036 Library = LoadLibraryEx (DllFileName, NULL, DONT_RESOLVE_DLL_REFERENCES);\r
1037 if (Library != NULL) {\r
1038 //\r
1039 // InitializeDriver is the entry point we put in all our EFI DLL's. The\r
1040 // DONT_RESOLVE_DLL_REFERENCES argument to LoadLIbraryEx() suppresses the\r
1041 // normal DLL entry point of DllMain, and prevents other modules that are\r
1042 // referenced in side the DllFileName from being loaded. There is no error\r
1043 // checking as the we can point to the PE32 image loaded by Tiano. This\r
1044 // step is only needed for source level debugging\r
1045 //\r
1046 DllEntryPoint = (VOID *) (UINTN) GetProcAddress (Library, "InitializeDriver");\r
1047\r
1048 }\r
1049\r
1050 if ((Library != NULL) && (DllEntryPoint != NULL)) {\r
10ccc27c
MK
1051 Status = AddModHandle (ImageContext, Library);\r
1052 if (Status == EFI_ALREADY_STARTED) {\r
1053 //\r
1054 // If the DLL has already been loaded before, then this instance of the DLL can not be debugged.\r
1055 //\r
1056 ImageContext->PdbPointer = NULL;\r
1057 SecPrint ("WARNING: DLL already loaded. No source level debug %S.\n\r", DllFileName);\r
1058 } else {\r
1059 //\r
1060 // This DLL is not already loaded, so source level debugging is supported.\r
1061 //\r
1062 ImageContext->EntryPoint = (EFI_PHYSICAL_ADDRESS) (UINTN) DllEntryPoint;\r
1063 SecPrint ("LoadLibraryEx (\n\r %S,\n\r NULL, DONT_RESOLVE_DLL_REFERENCES)\n\r", DllFileName);\r
1064 }\r
3c859dfe 1065 } else {\r
10ccc27c 1066 SecPrint ("WARNING: No source level debug %S. \n\r", DllFileName);\r
3c859dfe
RN
1067 }\r
1068\r
1069 free (DllFileName);\r
1070 }\r
1071}\r
1072\r
1073VOID\r
1074EFIAPI\r
1075PeCoffLoaderUnloadImageExtraAction (\r
10ccc27c 1076 IN PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext\r
3c859dfe
RN
1077)\r
1078{\r
10ccc27c
MK
1079 VOID *ModHandle;\r
1080\r
3c859dfe 1081 ASSERT (ImageContext != NULL);\r
3c859dfe 1082\r
10ccc27c
MK
1083 ModHandle = RemoveModHandle (ImageContext);\r
1084 if (ModHandle != NULL) {\r
1085 FreeLibrary (ModHandle);\r
1086 SecPrint ("FreeLibrary (\n\r %s)\n\r", ImageContext->PdbPointer);\r
1087 } else {\r
1088 SecPrint ("WARNING: Unload image without source level debug\n\r");\r
1089 }\r
1090}\r
3c859dfe
RN
1091\r
1092VOID\r
1093_ModuleEntryPoint (\r
1094 VOID\r
1095 )\r
1096{\r
1097}\r