• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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