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