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