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