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