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