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