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