1 /*++ @file
2
3 Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
4 Portions copyright (c) 2008 - 2011, Apple Inc. All rights reserved.<BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
9
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12
13 **/
14
15 #include "Host.h"
16
17 #ifdef __APPLE__
18 #define MAP_ANONYMOUS MAP_ANON
19 #endif
20
21
22 //
23 // Globals
24 //
25
26 EMU_THUNK_PPI mSecEmuThunkPpi = {
27 GasketSecUnixPeiAutoScan,
28 GasketSecUnixFdAddress,
29 GasketSecEmuThunkAddress
30 };
31
32 char *gGdbWorkingFileName = NULL;
33 unsigned int mScriptSymbolChangesCount = 0;
34
35
36 //
37 // Default information about where the FD is located.
38 // This array gets filled in with information from EFI_FIRMWARE_VOLUMES
39 // EFI_FIRMWARE_VOLUMES is a host environment variable set by system.cmd.
40 // The number of array elements is allocated base on parsing
41 // EFI_FIRMWARE_VOLUMES and the memory is never freed.
42 //
43 UINTN gFdInfoCount = 0;
44 EMU_FD_INFO *gFdInfo;
45
46 //
47 // Array that supports seperate memory rantes.
48 // The memory ranges are set in system.cmd via the EFI_MEMORY_SIZE variable.
49 // The number of array elements is allocated base on parsing
50 // EFI_MEMORY_SIZE and the memory is never freed.
51 //
52 UINTN gSystemMemoryCount = 0;
53 EMU_SYSTEM_MEMORY *gSystemMemory;
54
55
56
57 UINTN mImageContextModHandleArraySize = 0;
58 IMAGE_CONTEXT_TO_MOD_HANDLE *mImageContextModHandleArray = NULL;
59
60 EFI_PEI_PPI_DESCRIPTOR *gPpiList;
61
62
63 int gInXcode = 0;
64
65
66 /*++
67 Breakpoint target for Xcode project. Set in the Xcode XML
68
69 Xcode breakpoint will 'source Host.gdb'
70 gGdbWorkingFileName is set to Host.gdb
71
72 **/
73 VOID
SecGdbConfigBreak(VOID)74 SecGdbConfigBreak (
75 VOID
76 )
77 {
78 }
79
80
81
82 /*++
83
84 Routine Description:
85 Main entry point to SEC for Unix. This is a unix program
86
87 Arguments:
88 Argc - Number of command line arguments
89 Argv - Array of command line argument strings
90 Envp - Array of environment variable strings
91
92 Returns:
93 0 - Normal exit
94 1 - Abnormal exit
95
96 **/
97 int
main(IN int Argc,IN char ** Argv,IN char ** Envp)98 main (
99 IN int Argc,
100 IN char **Argv,
101 IN char **Envp
102 )
103 {
104 EFI_STATUS Status;
105 EFI_PHYSICAL_ADDRESS InitialStackMemory;
106 UINT64 InitialStackMemorySize;
107 UINTN Index;
108 UINTN Index1;
109 UINTN Index2;
110 UINTN PeiIndex;
111 CHAR8 *FileName;
112 BOOLEAN Done;
113 EFI_PEI_FILE_HANDLE FileHandle;
114 VOID *SecFile;
115 CHAR16 *MemorySizeStr;
116 CHAR16 *FirmwareVolumesStr;
117 UINTN *StackPointer;
118 FILE *GdbTempFile;
119
120 //
121 // Xcode does not support sourcing gdb scripts directly, so the Xcode XML
122 // has a break point script to source the GdbRun script.
123 //
124 SecGdbConfigBreak ();
125
126 //
127 // If dlopen doesn't work, then we build a gdb script to allow the
128 // symbols to be loaded.
129 //
130 Index = strlen (*Argv);
131 gGdbWorkingFileName = AllocatePool (Index + strlen(".gdb") + 1);
132 strcpy (gGdbWorkingFileName, *Argv);
133 strcat (gGdbWorkingFileName, ".gdb");
134
135 //
136 // Empty out the gdb symbols script file.
137 //
138 GdbTempFile = fopen (gGdbWorkingFileName, "w");
139 if (GdbTempFile != NULL) {
140 fclose (GdbTempFile);
141 }
142
143 printf ("\nEDK II UNIX Host Emulation Environment from http://www.tianocore.org/edk2/\n");
144
145 setbuf (stdout, 0);
146 setbuf (stderr, 0);
147
148 MemorySizeStr = (CHAR16 *) PcdGetPtr (PcdEmuMemorySize);
149 FirmwareVolumesStr = (CHAR16 *) PcdGetPtr (PcdEmuFirmwareVolume);
150
151 //
152 // PPIs pased into PEI_CORE
153 //
154 AddThunkPpi (EFI_PEI_PPI_DESCRIPTOR_PPI, &gEmuThunkPpiGuid, &mSecEmuThunkPpi);
155
156 SecInitThunkProtocol ();
157
158 //
159 // Emulator Bus Driver Thunks
160 //
161 AddThunkProtocol (&gX11ThunkIo, (CHAR16 *)PcdGetPtr (PcdEmuGop), TRUE);
162 AddThunkProtocol (&gPosixFileSystemThunkIo, (CHAR16 *)PcdGetPtr (PcdEmuFileSystem), TRUE);
163 AddThunkProtocol (&gBlockIoThunkIo, (CHAR16 *)PcdGetPtr (PcdEmuVirtualDisk), TRUE);
164 AddThunkProtocol (&gSnpThunkIo, (CHAR16 *)PcdGetPtr (PcdEmuNetworkInterface), TRUE);
165
166 //
167 // Emulator other Thunks
168 //
169 AddThunkProtocol (&gPthreadThunkIo, (CHAR16 *)PcdGetPtr (PcdEmuApCount), FALSE);
170
171 // EmuSecLibConstructor ();
172
173 gPpiList = GetThunkPpiList ();
174
175 //
176 // Allocate space for gSystemMemory Array
177 //
178 gSystemMemoryCount = CountSeparatorsInString (MemorySizeStr, '!') + 1;
179 gSystemMemory = AllocateZeroPool (gSystemMemoryCount * sizeof (EMU_SYSTEM_MEMORY));
180 if (gSystemMemory == NULL) {
181 printf ("ERROR : Can not allocate memory for system. Exiting.\n");
182 exit (1);
183 }
184 //
185 // Allocate space for gSystemMemory Array
186 //
187 gFdInfoCount = CountSeparatorsInString (FirmwareVolumesStr, '!') + 1;
188 gFdInfo = AllocateZeroPool (gFdInfoCount * sizeof (EMU_FD_INFO));
189 if (gFdInfo == NULL) {
190 printf ("ERROR : Can not allocate memory for fd info. Exiting.\n");
191 exit (1);
192 }
193
194 printf (" BootMode 0x%02x\n", (unsigned int)PcdGet32 (PcdEmuBootMode));
195
196 //
197 // Open up a 128K file to emulate temp memory for SEC.
198 // on a real platform this would be SRAM, or using the cache as RAM.
199 // Set InitialStackMemory to zero so UnixOpenFile will allocate a new mapping
200 //
201 InitialStackMemorySize = STACK_SIZE;
202 InitialStackMemory = (UINTN)MapMemory (
203 0, (UINT32) InitialStackMemorySize,
204 PROT_READ | PROT_WRITE | PROT_EXEC, MAP_ANONYMOUS | MAP_PRIVATE
205 );
206 if (InitialStackMemory == 0) {
207 printf ("ERROR : Can not open SecStack Exiting\n");
208 exit (1);
209 }
210
211 printf (" OS Emulator passing in %u KB of temp RAM at 0x%08lx to SEC\n",
212 (unsigned int)(InitialStackMemorySize / 1024),
213 (unsigned long)InitialStackMemory
214 );
215
216 for (StackPointer = (UINTN*) (UINTN) InitialStackMemory;
217 StackPointer < (UINTN*)(UINTN)((UINTN) InitialStackMemory + (UINT64) InitialStackMemorySize);
218 StackPointer ++) {
219 *StackPointer = 0x5AA55AA5;
220 }
221
222 //
223 // Open All the firmware volumes and remember the info in the gFdInfo global
224 //
225 FileName = (CHAR8 *) AllocatePool (StrLen (FirmwareVolumesStr) + 1);
226 if (FileName == NULL) {
227 printf ("ERROR : Can not allocate memory for firmware volume string\n");
228 exit (1);
229 }
230
231 Index2 = 0;
232 for (Done = FALSE, Index = 0, PeiIndex = 0, SecFile = NULL;
233 FirmwareVolumesStr[Index2] != 0;
234 Index++) {
235 for (Index1 = 0; (FirmwareVolumesStr[Index2] != '!') && (FirmwareVolumesStr[Index2] != 0); Index2++) {
236 FileName[Index1++] = FirmwareVolumesStr[Index2];
237 }
238 if (FirmwareVolumesStr[Index2] == '!') {
239 Index2++;
240 }
241 FileName[Index1] = '\0';
242
243 if (Index == 0) {
244 // Map FV Recovery Read Only and other areas Read/Write
245 Status = MapFd0 (
246 FileName,
247 &gFdInfo[0].Address,
248 &gFdInfo[0].Size
249 );
250 } else {
251 //
252 // Open the FD and remember where it got mapped into our processes address space
253 // Maps Read Only
254 //
255 Status = MapFile (
256 FileName,
257 &gFdInfo[Index].Address,
258 &gFdInfo[Index].Size
259 );
260 }
261 if (EFI_ERROR (Status)) {
262 printf ("ERROR : Can not open Firmware Device File %s (%x). Exiting.\n", FileName, (unsigned int)Status);
263 exit (1);
264 }
265
266 printf (" FD loaded from %s at 0x%08lx",FileName, (unsigned long)gFdInfo[Index].Address);
267
268 if (SecFile == NULL) {
269 //
270 // Assume the beginning of the FD is an FV and look for the SEC Core.
271 // Load the first one we find.
272 //
273 FileHandle = NULL;
274 Status = PeiServicesFfsFindNextFile (
275 EFI_FV_FILETYPE_SECURITY_CORE,
276 (EFI_PEI_FV_HANDLE)(UINTN)gFdInfo[Index].Address,
277 &FileHandle
278 );
279 if (!EFI_ERROR (Status)) {
280 Status = PeiServicesFfsFindSectionData (EFI_SECTION_PE32, FileHandle, &SecFile);
281 if (!EFI_ERROR (Status)) {
282 PeiIndex = Index;
283 printf (" contains SEC Core");
284 }
285 }
286 }
287
288 printf ("\n");
289 }
290
291 if (SecFile == NULL) {
292 printf ("ERROR : SEC not found!\n");
293 exit (1);
294 }
295
296 //
297 // Calculate memory regions and store the information in the gSystemMemory
298 // global for later use. The autosizing code will use this data to
299 // map this memory into the SEC process memory space.
300 //
301 Index1 = 0;
302 Index = 0;
303 while (1) {
304 UINTN val = 0;
305 //
306 // Save the size of the memory.
307 //
308 while (MemorySizeStr[Index1] >= '0' && MemorySizeStr[Index1] <= '9') {
309 val = val * 10 + MemorySizeStr[Index1] - '0';
310 Index1++;
311 }
312 gSystemMemory[Index++].Size = val * 0x100000;
313 if (MemorySizeStr[Index1] == 0) {
314 break;
315 }
316 Index1++;
317 }
318
319 printf ("\n");
320
321 //
322 // Hand off to SEC
323 //
324 SecLoadFromCore ((UINTN) InitialStackMemory, (UINTN) InitialStackMemorySize, (UINTN) gFdInfo[0].Address, SecFile);
325
326 //
327 // If we get here, then the SEC Core returned. This is an error as SEC should
328 // always hand off to PEI Core and then on to DXE Core.
329 //
330 printf ("ERROR : SEC returned\n");
331 exit (1);
332 }
333
334
335 EFI_PHYSICAL_ADDRESS *
MapMemory(IN INTN fd,IN UINT64 length,IN INTN prot,IN INTN flags)336 MapMemory (
337 IN INTN fd,
338 IN UINT64 length,
339 IN INTN prot,
340 IN INTN flags
341 )
342 {
343 STATIC UINTN base = 0x40000000;
344 CONST UINTN align = (1 << 24);
345 VOID *res = NULL;
346 BOOLEAN isAligned = 0;
347
348 //
349 // Try to get an aligned block somewhere in the address space of this
350 // process.
351 //
352 while((!isAligned) && (base != 0)) {
353 res = mmap ((void *)base, length, prot, flags, fd, 0);
354 if (res == MAP_FAILED) {
355 return NULL;
356 }
357 if ((((UINTN)res) & ~(align-1)) == (UINTN)res) {
358 isAligned=1;
359 } else {
360 munmap(res, length);
361 base += align;
362 }
363 }
364 return res;
365 }
366
367
368 /*++
369
370 Routine Description:
371 Opens and memory maps a file using Unix services. If BaseAddress is non zero
372 the process will try and allocate the memory starting at BaseAddress.
373
374 Arguments:
375 FileName - The name of the file to open and map
376 MapSize - The amount of the file to map in bytes
377 CreationDisposition - The flags to pass to CreateFile(). Use to create new files for
378 memory emulation, and exiting files for firmware volume emulation
379 BaseAddress - The base address of the mapped file in the user address space.
380 If passed in as NULL the a new memory region is used.
381 If passed in as non NULL the request memory region is used for
382 the mapping of the file into the process space.
383 Length - The size of the mapped region in bytes
384
385 Returns:
386 EFI_SUCCESS - The file was opened and mapped.
387 EFI_NOT_FOUND - FileName was not found in the current directory
388 EFI_DEVICE_ERROR - An error occured attempting to map the opened file
389
390 **/
391 EFI_STATUS
MapFile(IN CHAR8 * FileName,IN OUT EFI_PHYSICAL_ADDRESS * BaseAddress,OUT UINT64 * Length)392 MapFile (
393 IN CHAR8 *FileName,
394 IN OUT EFI_PHYSICAL_ADDRESS *BaseAddress,
395 OUT UINT64 *Length
396 )
397 {
398 int fd;
399 VOID *res;
400 UINTN FileSize;
401
402 fd = open (FileName, O_RDWR);
403 if (fd < 0) {
404 return EFI_NOT_FOUND;
405 }
406 FileSize = lseek (fd, 0, SEEK_END);
407
408
409 res = MapMemory (fd, FileSize, PROT_READ | PROT_EXEC, MAP_PRIVATE);
410
411 close (fd);
412
413 if (res == NULL) {
414 perror ("MapFile() Failed");
415 return EFI_DEVICE_ERROR;
416 }
417
418 *Length = (UINT64) FileSize;
419 *BaseAddress = (EFI_PHYSICAL_ADDRESS) (UINTN) res;
420
421 return EFI_SUCCESS;
422 }
423
424 EFI_STATUS
MapFd0(IN CHAR8 * FileName,IN OUT EFI_PHYSICAL_ADDRESS * BaseAddress,OUT UINT64 * Length)425 MapFd0 (
426 IN CHAR8 *FileName,
427 IN OUT EFI_PHYSICAL_ADDRESS *BaseAddress,
428 OUT UINT64 *Length
429 )
430 {
431 int fd;
432 void *res, *res2, *res3;
433 UINTN FileSize;
434 UINTN FvSize;
435 void *EmuMagicPage;
436
437 fd = open (FileName, O_RDWR);
438 if (fd < 0) {
439 return EFI_NOT_FOUND;
440 }
441 FileSize = lseek (fd, 0, SEEK_END);
442
443 FvSize = FixedPcdGet64 (PcdEmuFlashFvRecoverySize);
444
445 // Assume start of FD is Recovery FV, and make it write protected
446 res = mmap (
447 (void *)(UINTN)FixedPcdGet64 (PcdEmuFlashFvRecoveryBase),
448 FvSize,
449 PROT_READ | PROT_EXEC,
450 MAP_PRIVATE,
451 fd,
452 0
453 );
454 if (res == MAP_FAILED) {
455 perror ("MapFd0() Failed res =");
456 close (fd);
457 return EFI_DEVICE_ERROR;
458 } else if (res != (void *)(UINTN)FixedPcdGet64 (PcdEmuFlashFvRecoveryBase)) {
459 // We could not load at the build address, so we need to allow writes
460 munmap (res, FvSize);
461 res = mmap (
462 (void *)(UINTN)FixedPcdGet64 (PcdEmuFlashFvRecoveryBase),
463 FvSize,
464 PROT_READ | PROT_WRITE | PROT_EXEC,
465 MAP_PRIVATE,
466 fd,
467 0
468 );
469 if (res == MAP_FAILED) {
470 perror ("MapFd0() Failed res =");
471 close (fd);
472 return EFI_DEVICE_ERROR;
473 }
474 }
475
476 // Map the rest of the FD as read/write
477 res2 = mmap (
478 (void *)(UINTN)(FixedPcdGet64 (PcdEmuFlashFvRecoveryBase) + FvSize),
479 FileSize - FvSize,
480 PROT_READ | PROT_WRITE | PROT_EXEC,
481 MAP_SHARED,
482 fd,
483 FvSize
484 );
485 close (fd);
486 if (res2 == MAP_FAILED) {
487 perror ("MapFd0() Failed res2 =");
488 return EFI_DEVICE_ERROR;
489 }
490
491 //
492 // If enabled use the magic page to communicate between modules
493 // This replaces the PI PeiServicesTable pointer mechanism that
494 // deos not work in the emulator. It also allows the removal of
495 // writable globals from SEC, PEI_CORE (libraries), PEIMs
496 //
497 EmuMagicPage = (void *)(UINTN)FixedPcdGet64 (PcdPeiServicesTablePage);
498 if (EmuMagicPage != NULL) {
499 res3 = mmap (
500 (void *)EmuMagicPage,
501 4096,
502 PROT_READ | PROT_WRITE,
503 MAP_PRIVATE | MAP_ANONYMOUS,
504 0,
505 0
506 );
507 if (res3 != EmuMagicPage) {
508 printf ("MapFd0(): Could not allocate PeiServicesTablePage @ %lx\n", (long unsigned int)EmuMagicPage);
509 return EFI_DEVICE_ERROR;
510 }
511 }
512
513 *Length = (UINT64) FileSize;
514 *BaseAddress = (EFI_PHYSICAL_ADDRESS) (UINTN) res;
515
516 return EFI_SUCCESS;
517 }
518
519
520 /*++
521
522 Routine Description:
523 This is the service to load the SEC Core from the Firmware Volume
524
525 Arguments:
526 LargestRegion - Memory to use for SEC.
527 LargestRegionSize - Size of Memory to use for PEI
528 BootFirmwareVolumeBase - Start of the Boot FV
529 PeiCorePe32File - SEC PE32
530
531 Returns:
532 Success means control is transfered and thus we should never return
533
534 **/
535 VOID
SecLoadFromCore(IN UINTN LargestRegion,IN UINTN LargestRegionSize,IN UINTN BootFirmwareVolumeBase,IN VOID * PeiCorePe32File)536 SecLoadFromCore (
537 IN UINTN LargestRegion,
538 IN UINTN LargestRegionSize,
539 IN UINTN BootFirmwareVolumeBase,
540 IN VOID *PeiCorePe32File
541 )
542 {
543 EFI_STATUS Status;
544 EFI_PHYSICAL_ADDRESS TopOfMemory;
545 VOID *TopOfStack;
546 EFI_PHYSICAL_ADDRESS PeiCoreEntryPoint;
547 EFI_SEC_PEI_HAND_OFF *SecCoreData;
548 UINTN PeiStackSize;
549
550 //
551 // Compute Top Of Memory for Stack and PEI Core Allocations
552 //
553 TopOfMemory = LargestRegion + LargestRegionSize;
554 PeiStackSize = (UINTN)RShiftU64((UINT64)STACK_SIZE,1);
555
556 //
557 // |-----------| <---- TemporaryRamBase + TemporaryRamSize
558 // | Heap |
559 // | |
560 // |-----------| <---- StackBase / PeiTemporaryMemoryBase
561 // | |
562 // | Stack |
563 // |-----------| <---- TemporaryRamBase
564 //
565 TopOfStack = (VOID *)(LargestRegion + PeiStackSize);
566 TopOfMemory = LargestRegion + PeiStackSize;
567
568 //
569 // Reservet space for storing PeiCore's parament in stack.
570 //
571 TopOfStack = (VOID *)((UINTN)TopOfStack - sizeof (EFI_SEC_PEI_HAND_OFF) - CPU_STACK_ALIGNMENT);
572 TopOfStack = ALIGN_POINTER (TopOfStack, CPU_STACK_ALIGNMENT);
573
574
575 //
576 // Bind this information into the SEC hand-off state
577 //
578 SecCoreData = (EFI_SEC_PEI_HAND_OFF*)(UINTN) TopOfStack;
579 SecCoreData->DataSize = sizeof(EFI_SEC_PEI_HAND_OFF);
580 SecCoreData->BootFirmwareVolumeBase = (VOID*)BootFirmwareVolumeBase;
581 SecCoreData->BootFirmwareVolumeSize = PcdGet32 (PcdEmuFirmwareFdSize);
582 SecCoreData->TemporaryRamBase = (VOID*)(UINTN)LargestRegion;
583 SecCoreData->TemporaryRamSize = STACK_SIZE;
584 SecCoreData->StackBase = SecCoreData->TemporaryRamBase;
585 SecCoreData->StackSize = PeiStackSize;
586 SecCoreData->PeiTemporaryRamBase = (VOID*) ((UINTN) SecCoreData->TemporaryRamBase + PeiStackSize);
587 SecCoreData->PeiTemporaryRamSize = STACK_SIZE - PeiStackSize;
588
589 //
590 // Find the SEC Core Entry Point
591 //
592 Status = SecPeCoffGetEntryPoint (PeiCorePe32File, (VOID **)&PeiCoreEntryPoint);
593 if (EFI_ERROR (Status)) {
594 return ;
595 }
596
597 //
598 // Transfer control to the SEC Core
599 //
600 PeiSwitchStacks (
601 (SWITCH_STACK_ENTRY_POINT) (UINTN) PeiCoreEntryPoint,
602 SecCoreData,
603 (VOID *)gPpiList,
604 TopOfStack
605 );
606 //
607 // If we get here, then the SEC Core returned. This is an error
608 //
609 return ;
610 }
611
612
613 /*++
614
615 Routine Description:
616 This service is called from Index == 0 until it returns EFI_UNSUPPORTED.
617 It allows discontinuous memory regions to be supported by the emulator.
618 It uses gSystemMemory[] and gSystemMemoryCount that were created by
619 parsing the host environment variable EFI_MEMORY_SIZE.
620 The size comes from the varaible and the address comes from the call to
621 UnixOpenFile.
622
623 Arguments:
624 Index - Which memory region to use
625 MemoryBase - Return Base address of memory region
626 MemorySize - Return size in bytes of the memory region
627
628 Returns:
629 EFI_SUCCESS - If memory region was mapped
630 EFI_UNSUPPORTED - If Index is not supported
631
632 **/
633 EFI_STATUS
SecUnixPeiAutoScan(IN UINTN Index,OUT EFI_PHYSICAL_ADDRESS * MemoryBase,OUT UINT64 * MemorySize)634 SecUnixPeiAutoScan (
635 IN UINTN Index,
636 OUT EFI_PHYSICAL_ADDRESS *MemoryBase,
637 OUT UINT64 *MemorySize
638 )
639 {
640 void *res;
641
642 if (Index >= gSystemMemoryCount) {
643 return EFI_UNSUPPORTED;
644 }
645
646 *MemoryBase = 0;
647 res = MapMemory (
648 0, gSystemMemory[Index].Size,
649 PROT_READ | PROT_WRITE | PROT_EXEC,
650 MAP_PRIVATE | MAP_ANONYMOUS
651 );
652 if (res == MAP_FAILED) {
653 return EFI_DEVICE_ERROR;
654 }
655 *MemorySize = gSystemMemory[Index].Size;
656 *MemoryBase = (UINTN)res;
657 gSystemMemory[Index].Memory = *MemoryBase;
658
659 return EFI_SUCCESS;
660 }
661
662
663 /*++
664
665 Routine Description:
666 Check to see if an address range is in the EFI GCD memory map.
667
668 This is all of GCD for system memory passed to DXE Core. FV
669 mapping and other device mapped into system memory are not
670 inlcuded in the check.
671
672 Arguments:
673 Index - Which memory region to use
674 MemoryBase - Return Base address of memory region
675 MemorySize - Return size in bytes of the memory region
676
677 Returns:
678 TRUE - Address is in the EFI GCD memory map
679 FALSE - Address is NOT in memory map
680
681 **/
682 BOOLEAN
EfiSystemMemoryRange(IN VOID * MemoryAddress)683 EfiSystemMemoryRange (
684 IN VOID *MemoryAddress
685 )
686 {
687 UINTN Index;
688 EFI_PHYSICAL_ADDRESS MemoryBase;
689
690 MemoryBase = (EFI_PHYSICAL_ADDRESS)(UINTN)MemoryAddress;
691 for (Index = 0; Index < gSystemMemoryCount; Index++) {
692 if ((MemoryBase >= gSystemMemory[Index].Memory) &&
693 (MemoryBase < (gSystemMemory[Index].Memory + gSystemMemory[Index].Size)) ) {
694 return TRUE;
695 }
696 }
697
698 return FALSE;
699 }
700
701
702 /*++
703
704 Routine Description:
705 Since the SEC is the only Unix program in stack it must export
706 an interface to do POSIX calls. gUnix is initialized in UnixThunk.c.
707
708 Arguments:
709 InterfaceSize - sizeof (EFI_WIN_NT_THUNK_PROTOCOL);
710 InterfaceBase - Address of the gUnix global
711
712 Returns:
713 EFI_SUCCESS - Data returned
714
715 **/
716 VOID *
SecEmuThunkAddress(VOID)717 SecEmuThunkAddress (
718 VOID
719 )
720 {
721 return &gEmuThunkProtocol;
722 }
723
724
725
726 RETURN_STATUS
727 EFIAPI
SecPeCoffGetEntryPoint(IN VOID * Pe32Data,IN OUT VOID ** EntryPoint)728 SecPeCoffGetEntryPoint (
729 IN VOID *Pe32Data,
730 IN OUT VOID **EntryPoint
731 )
732 {
733 EFI_STATUS Status;
734 PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;
735
736 ZeroMem (&ImageContext, sizeof (ImageContext));
737 ImageContext.Handle = Pe32Data;
738 ImageContext.ImageRead = (PE_COFF_LOADER_READ_FILE) SecImageRead;
739
740 Status = PeCoffLoaderGetImageInfo (&ImageContext);
741 if (EFI_ERROR (Status)) {
742 return Status;
743 }
744
745 if (ImageContext.ImageAddress != (UINTN)Pe32Data) {
746 //
747 // Relocate image to match the address where it resides
748 //
749 ImageContext.ImageAddress = (UINTN)Pe32Data;
750 Status = PeCoffLoaderLoadImage (&ImageContext);
751 if (EFI_ERROR (Status)) {
752 return Status;
753 }
754
755 Status = PeCoffLoaderRelocateImage (&ImageContext);
756 if (EFI_ERROR (Status)) {
757 return Status;
758 }
759 } else {
760 //
761 // Or just return image entry point
762 //
763 ImageContext.PdbPointer = PeCoffLoaderGetPdbPointer (Pe32Data);
764 Status = PeCoffLoaderGetEntryPoint (Pe32Data, EntryPoint);
765 if (EFI_ERROR (Status)) {
766 return Status;
767 }
768 ImageContext.EntryPoint = (UINTN)*EntryPoint;
769 }
770
771 // On Unix a dlopen is done that will change the entry point
772 SecPeCoffRelocateImageExtraAction (&ImageContext);
773 *EntryPoint = (VOID *)(UINTN)ImageContext.EntryPoint;
774
775 return Status;
776 }
777
778
779
780 /*++
781
782 Routine Description:
783 Return the FD Size and base address. Since the FD is loaded from a
784 file into host memory only the SEC will know it's address.
785
786 Arguments:
787 Index - Which FD, starts at zero.
788 FdSize - Size of the FD in bytes
789 FdBase - Start address of the FD. Assume it points to an FV Header
790 FixUp - Difference between actual FD address and build address
791
792 Returns:
793 EFI_SUCCESS - Return the Base address and size of the FV
794 EFI_UNSUPPORTED - Index does nto map to an FD in the system
795
796 **/
797 EFI_STATUS
SecUnixFdAddress(IN UINTN Index,IN OUT EFI_PHYSICAL_ADDRESS * FdBase,IN OUT UINT64 * FdSize,IN OUT EFI_PHYSICAL_ADDRESS * FixUp)798 SecUnixFdAddress (
799 IN UINTN Index,
800 IN OUT EFI_PHYSICAL_ADDRESS *FdBase,
801 IN OUT UINT64 *FdSize,
802 IN OUT EFI_PHYSICAL_ADDRESS *FixUp
803 )
804 {
805 if (Index >= gFdInfoCount) {
806 return EFI_UNSUPPORTED;
807 }
808
809 *FdBase = gFdInfo[Index].Address;
810 *FdSize = gFdInfo[Index].Size;
811 *FixUp = 0;
812
813 if (*FdBase == 0 && *FdSize == 0) {
814 return EFI_UNSUPPORTED;
815 }
816
817 if (Index == 0) {
818 //
819 // FD 0 has XIP code and well known PCD values
820 // If the memory buffer could not be allocated at the FD build address
821 // the Fixup is the difference.
822 //
823 *FixUp = *FdBase - PcdGet64 (PcdEmuFdBaseAddress);
824 }
825
826 return EFI_SUCCESS;
827 }
828
829
830 /*++
831
832 Routine Description:
833 Count the number of separators in String
834
835 Arguments:
836 String - String to process
837 Separator - Item to count
838
839 Returns:
840 Number of Separator in String
841
842 **/
843 UINTN
CountSeparatorsInString(IN const CHAR16 * String,IN CHAR16 Separator)844 CountSeparatorsInString (
845 IN const CHAR16 *String,
846 IN CHAR16 Separator
847 )
848 {
849 UINTN Count;
850
851 for (Count = 0; *String != '\0'; String++) {
852 if (*String == Separator) {
853 Count++;
854 }
855 }
856
857 return Count;
858 }
859
860
861 EFI_STATUS
862 EFIAPI
SecImageRead(IN VOID * FileHandle,IN UINTN FileOffset,IN OUT UINTN * ReadSize,OUT VOID * Buffer)863 SecImageRead (
864 IN VOID *FileHandle,
865 IN UINTN FileOffset,
866 IN OUT UINTN *ReadSize,
867 OUT VOID *Buffer
868 )
869 /*++
870
871 Routine Description:
872 Support routine for the PE/COFF Loader that reads a buffer from a PE/COFF file
873
874 Arguments:
875 FileHandle - The handle to the PE/COFF file
876 FileOffset - The offset, in bytes, into the file to read
877 ReadSize - The number of bytes to read from the file starting at FileOffset
878 Buffer - A pointer to the buffer to read the data into.
879
880 Returns:
881 EFI_SUCCESS - ReadSize bytes of data were read into Buffer from the PE/COFF file starting at FileOffset
882
883 **/
884 {
885 CHAR8 *Destination8;
886 CHAR8 *Source8;
887 UINTN Length;
888
889 Destination8 = Buffer;
890 Source8 = (CHAR8 *) ((UINTN) FileHandle + FileOffset);
891 Length = *ReadSize;
892 while (Length--) {
893 *(Destination8++) = *(Source8++);
894 }
895
896 return EFI_SUCCESS;
897 }
898
899
900 /*++
901
902 Routine Description:
903 Store the ModHandle in an array indexed by the Pdb File name.
904 The ModHandle is needed to unload the image.
905
906 Arguments:
907 ImageContext - Input data returned from PE Laoder Library. Used to find the
908 .PDB file name of the PE Image.
909 ModHandle - Returned from LoadLibraryEx() and stored for call to
910 FreeLibrary().
911
912 Returns:
913 EFI_SUCCESS - ModHandle was stored.
914
915 **/
916 EFI_STATUS
AddHandle(IN PE_COFF_LOADER_IMAGE_CONTEXT * ImageContext,IN VOID * ModHandle)917 AddHandle (
918 IN PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext,
919 IN VOID *ModHandle
920 )
921 {
922 UINTN Index;
923 IMAGE_CONTEXT_TO_MOD_HANDLE *Array;
924 UINTN PreviousSize;
925
926
927 Array = mImageContextModHandleArray;
928 for (Index = 0; Index < mImageContextModHandleArraySize; Index++, Array++) {
929 if (Array->ImageContext == NULL) {
930 //
931 // Make a copy of the stirng and store the ModHandle
932 //
933 Array->ImageContext = ImageContext;
934 Array->ModHandle = ModHandle;
935 return EFI_SUCCESS;
936 }
937 }
938
939 //
940 // No free space in mImageContextModHandleArray so grow it by
941 // IMAGE_CONTEXT_TO_MOD_HANDLE entires. realloc will
942 // copy the old values to the new locaiton. But it does
943 // not zero the new memory area.
944 //
945 PreviousSize = mImageContextModHandleArraySize * sizeof (IMAGE_CONTEXT_TO_MOD_HANDLE);
946 mImageContextModHandleArraySize += MAX_IMAGE_CONTEXT_TO_MOD_HANDLE_ARRAY_SIZE;
947
948 mImageContextModHandleArray = ReallocatePool (
949 (mImageContextModHandleArraySize - 1) * sizeof (IMAGE_CONTEXT_TO_MOD_HANDLE),
950 mImageContextModHandleArraySize * sizeof (IMAGE_CONTEXT_TO_MOD_HANDLE),
951 mImageContextModHandleArray
952 );
953 if (mImageContextModHandleArray == NULL) {
954 ASSERT (FALSE);
955 return EFI_OUT_OF_RESOURCES;
956 }
957
958 memset (mImageContextModHandleArray + PreviousSize, 0, MAX_IMAGE_CONTEXT_TO_MOD_HANDLE_ARRAY_SIZE * sizeof (IMAGE_CONTEXT_TO_MOD_HANDLE));
959
960 return AddHandle (ImageContext, ModHandle);
961 }
962
963
964 /*++
965
966 Routine Description:
967 Return the ModHandle and delete the entry in the array.
968
969 Arguments:
970 ImageContext - Input data returned from PE Laoder Library. Used to find the
971 .PDB file name of the PE Image.
972
973 Returns:
974 ModHandle - ModHandle assoicated with ImageContext is returned
975 NULL - No ModHandle associated with ImageContext
976
977 **/
978 VOID *
RemoveHandle(IN PE_COFF_LOADER_IMAGE_CONTEXT * ImageContext)979 RemoveHandle (
980 IN PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
981 )
982 {
983 UINTN Index;
984 IMAGE_CONTEXT_TO_MOD_HANDLE *Array;
985
986 if (ImageContext->PdbPointer == NULL) {
987 //
988 // If no PDB pointer there is no ModHandle so return NULL
989 //
990 return NULL;
991 }
992
993 Array = mImageContextModHandleArray;
994 for (Index = 0; Index < mImageContextModHandleArraySize; Index++, Array++) {
995 if (Array->ImageContext == ImageContext) {
996 //
997 // If you find a match return it and delete the entry
998 //
999 Array->ImageContext = NULL;
1000 return Array->ModHandle;
1001 }
1002 }
1003
1004 return NULL;
1005 }
1006
1007
1008
1009 BOOLEAN
IsPdbFile(IN CHAR8 * PdbFileName)1010 IsPdbFile (
1011 IN CHAR8 *PdbFileName
1012 )
1013 {
1014 UINTN Len;
1015
1016 if (PdbFileName == NULL) {
1017 return FALSE;
1018 }
1019
1020 Len = strlen (PdbFileName);
1021 if ((Len < 5)|| (PdbFileName[Len - 4] != '.')) {
1022 return FALSE;
1023 }
1024
1025 if ((PdbFileName[Len - 3] == 'P' || PdbFileName[Len - 3] == 'p') &&
1026 (PdbFileName[Len - 2] == 'D' || PdbFileName[Len - 2] == 'd') &&
1027 (PdbFileName[Len - 1] == 'B' || PdbFileName[Len - 1] == 'b')) {
1028 return TRUE;
1029 }
1030
1031 return FALSE;
1032 }
1033
1034
1035 #define MAX_SPRINT_BUFFER_SIZE 0x200
1036
1037 void
PrintLoadAddress(IN PE_COFF_LOADER_IMAGE_CONTEXT * ImageContext)1038 PrintLoadAddress (
1039 IN PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
1040 )
1041 {
1042 if (ImageContext->PdbPointer == NULL) {
1043 fprintf (stderr,
1044 "0x%08lx Loading NO DEBUG with entry point 0x%08lx\n",
1045 (unsigned long)(ImageContext->ImageAddress),
1046 (unsigned long)ImageContext->EntryPoint
1047 );
1048 } else {
1049 fprintf (stderr,
1050 "0x%08lx Loading %s with entry point 0x%08lx\n",
1051 (unsigned long)(ImageContext->ImageAddress + ImageContext->SizeOfHeaders),
1052 ImageContext->PdbPointer,
1053 (unsigned long)ImageContext->EntryPoint
1054 );
1055 }
1056 // Keep output synced up
1057 fflush (stderr);
1058 }
1059
1060
1061 /**
1062 Loads the image using dlopen so symbols will be automatically
1063 loaded by gdb.
1064
1065 @param ImageContext The PE/COFF image context
1066
1067 @retval TRUE - The image was successfully loaded
1068 @retval FALSE - The image was successfully loaded
1069
1070 **/
1071 BOOLEAN
DlLoadImage(IN OUT PE_COFF_LOADER_IMAGE_CONTEXT * ImageContext)1072 DlLoadImage (
1073 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
1074 )
1075 {
1076
1077 #ifdef __APPLE__
1078
1079 return FALSE;
1080
1081 #else
1082
1083 void *Handle = NULL;
1084 void *Entry = NULL;
1085
1086 if (ImageContext->PdbPointer == NULL) {
1087 return FALSE;
1088 }
1089
1090 if (!IsPdbFile (ImageContext->PdbPointer)) {
1091 return FALSE;
1092 }
1093
1094 fprintf (
1095 stderr,
1096 "Loading %s 0x%08lx - entry point 0x%08lx\n",
1097 ImageContext->PdbPointer,
1098 (unsigned long)ImageContext->ImageAddress,
1099 (unsigned long)ImageContext->EntryPoint
1100 );
1101
1102 Handle = dlopen (ImageContext->PdbPointer, RTLD_NOW);
1103 if (Handle != NULL) {
1104 Entry = dlsym (Handle, "_ModuleEntryPoint");
1105 AddHandle (ImageContext, Handle);
1106 } else {
1107 printf("%s\n", dlerror());
1108 }
1109
1110 if (Entry != NULL) {
1111 ImageContext->EntryPoint = (UINTN)Entry;
1112 printf ("Change %s Entrypoint to :0x%08lx\n", ImageContext->PdbPointer, (unsigned long)Entry);
1113 return TRUE;
1114 } else {
1115 return FALSE;
1116 }
1117
1118 #endif
1119 }
1120
1121
1122 VOID
SecGdbScriptBreak(char * FileName,int FileNameLength,long unsigned int LoadAddress,int AddSymbolFlag)1123 SecGdbScriptBreak (
1124 char *FileName,
1125 int FileNameLength,
1126 long unsigned int LoadAddress,
1127 int AddSymbolFlag
1128 )
1129 {
1130 return;
1131 }
1132
1133
1134 /**
1135 Adds the image to a gdb script so it's symbols can be loaded.
1136 The AddFirmwareSymbolFile helper macro is used.
1137
1138 @param ImageContext The PE/COFF image context
1139
1140 **/
1141 VOID
GdbScriptAddImage(IN OUT PE_COFF_LOADER_IMAGE_CONTEXT * ImageContext)1142 GdbScriptAddImage (
1143 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
1144 )
1145 {
1146
1147 PrintLoadAddress (ImageContext);
1148
1149 if (ImageContext->PdbPointer != NULL && !IsPdbFile (ImageContext->PdbPointer)) {
1150 FILE *GdbTempFile;
1151 if (FeaturePcdGet (PcdEmulatorLazyLoadSymbols)) {
1152 GdbTempFile = fopen (gGdbWorkingFileName, "a");
1153 if (GdbTempFile != NULL) {
1154 long unsigned int SymbolsAddr = (long unsigned int)(ImageContext->ImageAddress + ImageContext->SizeOfHeaders);
1155 mScriptSymbolChangesCount++;
1156 fprintf (
1157 GdbTempFile,
1158 "AddFirmwareSymbolFile 0x%x %s 0x%08lx\n",
1159 mScriptSymbolChangesCount,
1160 ImageContext->PdbPointer,
1161 SymbolsAddr
1162 );
1163 fclose (GdbTempFile);
1164 // This is for the lldb breakpoint only
1165 SecGdbScriptBreak (ImageContext->PdbPointer, strlen (ImageContext->PdbPointer) + 1, (long unsigned int)(ImageContext->ImageAddress + ImageContext->SizeOfHeaders), 1);
1166 } else {
1167 ASSERT (FALSE);
1168 }
1169 } else {
1170 GdbTempFile = fopen (gGdbWorkingFileName, "w");
1171 if (GdbTempFile != NULL) {
1172 fprintf (
1173 GdbTempFile,
1174 "add-symbol-file %s 0x%08lx\n",
1175 ImageContext->PdbPointer,
1176 (long unsigned int)(ImageContext->ImageAddress + ImageContext->SizeOfHeaders)
1177 );
1178 fclose (GdbTempFile);
1179
1180 //
1181 // Target for gdb breakpoint in a script that uses gGdbWorkingFileName to set a breakpoint.
1182 // Hey what can you say scripting in gdb is not that great....
1183 // Also used for the lldb breakpoint script. The lldb breakpoint script does
1184 // not use the file, it uses the arguments.
1185 //
1186 SecGdbScriptBreak (ImageContext->PdbPointer, strlen (ImageContext->PdbPointer) + 1, (long unsigned int)(ImageContext->ImageAddress + ImageContext->SizeOfHeaders), 1);
1187 } else {
1188 ASSERT (FALSE);
1189 }
1190 }
1191 }
1192 }
1193
1194
1195 VOID
1196 EFIAPI
SecPeCoffRelocateImageExtraAction(IN OUT PE_COFF_LOADER_IMAGE_CONTEXT * ImageContext)1197 SecPeCoffRelocateImageExtraAction (
1198 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
1199 )
1200 {
1201 if (!DlLoadImage (ImageContext)) {
1202 GdbScriptAddImage (ImageContext);
1203 }
1204 }
1205
1206
1207 /**
1208 Adds the image to a gdb script so it's symbols can be unloaded.
1209 The RemoveFirmwareSymbolFile helper macro is used.
1210
1211 @param ImageContext The PE/COFF image context
1212
1213 **/
1214 VOID
GdbScriptRemoveImage(IN OUT PE_COFF_LOADER_IMAGE_CONTEXT * ImageContext)1215 GdbScriptRemoveImage (
1216 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
1217 )
1218 {
1219 FILE *GdbTempFile;
1220
1221 //
1222 // Need to skip .PDB files created from VC++
1223 //
1224 if (IsPdbFile (ImageContext->PdbPointer)) {
1225 return;
1226 }
1227
1228 if (FeaturePcdGet (PcdEmulatorLazyLoadSymbols)) {
1229 //
1230 // Write the file we need for the gdb script
1231 //
1232 GdbTempFile = fopen (gGdbWorkingFileName, "a");
1233 if (GdbTempFile != NULL) {
1234 mScriptSymbolChangesCount++;
1235 fprintf (
1236 GdbTempFile,
1237 "RemoveFirmwareSymbolFile 0x%x %s\n",
1238 mScriptSymbolChangesCount,
1239 ImageContext->PdbPointer
1240 );
1241 fclose (GdbTempFile);
1242 SecGdbScriptBreak (ImageContext->PdbPointer, strlen (ImageContext->PdbPointer) + 1, 0, 0);
1243 } else {
1244 ASSERT (FALSE);
1245 }
1246 } else {
1247 GdbTempFile = fopen (gGdbWorkingFileName, "w");
1248 if (GdbTempFile != NULL) {
1249 fprintf (GdbTempFile, "remove-symbol-file %s\n", ImageContext->PdbPointer);
1250 fclose (GdbTempFile);
1251
1252 //
1253 // Target for gdb breakpoint in a script that uses gGdbWorkingFileName to set a breakpoint.
1254 // Hey what can you say scripting in gdb is not that great....
1255 //
1256 SecGdbScriptBreak (ImageContext->PdbPointer, strlen (ImageContext->PdbPointer) + 1, 0, 0);
1257 } else {
1258 ASSERT (FALSE);
1259 }
1260 }
1261 }
1262
1263
1264 VOID
1265 EFIAPI
SecPeCoffUnloadImageExtraAction(IN PE_COFF_LOADER_IMAGE_CONTEXT * ImageContext)1266 SecPeCoffUnloadImageExtraAction (
1267 IN PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
1268 )
1269 {
1270 VOID *Handle;
1271
1272 //
1273 // Check to see if the image symbols were loaded with gdb script, or dlopen
1274 //
1275 Handle = RemoveHandle (ImageContext);
1276 if (Handle != NULL) {
1277 #ifndef __APPLE__
1278 dlclose (Handle);
1279 #endif
1280 return;
1281 }
1282
1283 GdbScriptRemoveImage (ImageContext);
1284 }
1285
1286
1287