1/**@file
2
3Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.<BR>
4(C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>
5This program and the accompanying materials
6are licensed and made available under the terms and conditions of the BSD License
7which accompanies this distribution.  The full text of the license may be found at
8http://opensource.org/licenses/bsd-license.php
9
10THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12
13Module Name:
14
15  SecMain.c
16
17Abstract:
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
38NT_PEI_LOAD_FILE_PPI                      mSecNtLoadFilePpi     = { SecWinNtPeiLoadFile };
39
40PEI_NT_AUTOSCAN_PPI                       mSecNtAutoScanPpi     = { SecWinNtPeiAutoScan };
41
42PEI_NT_THUNK_PPI                          mSecWinNtThunkPpi     = { SecWinNtWinNtThunkAddress };
43
44EFI_PEI_PROGRESS_CODE_PPI                 mSecStatusCodePpi     = { SecPeiReportStatusCode };
45
46NT_FWH_PPI                                mSecFwhInformationPpi = { SecWinNtFdAddress };
47
48EFI_PEI_TEMPORARY_RAM_SUPPORT_PPI         mSecTemporaryRamSupportPpi = {SecTemporaryRamSupport};
49
50EFI_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//
90UINTN                                     gFdInfoCount = 0;
91NT_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//
99UINTN                                     gSystemMemoryCount = 0;
100NT_SYSTEM_MEMORY                          *gSystemMemory;
101
102VOID
103EFIAPI
104SecSwitchStack (
105  UINT32   TemporaryMemoryBase,
106  UINT32   PermenentMemoryBase
107  );
108EFI_STATUS
109SecNt32PeCoffRelocateImage (
110  IN OUT PE_COFF_LOADER_IMAGE_CONTEXT         *ImageContext
111  );
112
113VOID
114EFIAPI
115PeiSwitchStacks (
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
123VOID
124SecPrint (
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
149INTN
150EFIAPI
151main (
152  IN  INTN  Argc,
153  IN  CHAR8 **Argv,
154  IN  CHAR8 **Envp
155  )
156/*++
157
158Routine Description:
159  Main entry point to SEC for WinNt. This is a Windows program
160
161Arguments:
162  Argc - Number of command line arguments
163  Argv - Array of command line argument strings
164  Envp - Array of environment variable strings
165
166Returns:
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
368EFI_STATUS
369WinNtOpenFile (
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
378Routine 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
382Arguments:
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
393Returns:
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
476EFI_STATUS
477EFIAPI
478SecPeiReportStatusCode (
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
488Routine 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
496Arguments:
497  (see EFI_PEI_REPORT_STATUS_CODE)
498
499Returns:
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**/
560VOID
561EFIAPI
562PeiSwitchStacks (
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
597VOID
598SecLoadFromCore (
599  IN  UINTN   LargestRegion,
600  IN  UINTN   LargestRegionSize,
601  IN  UINTN   BootFirmwareVolumeBase,
602  IN  VOID    *PeiCorePe32File
603  )
604/*++
605
606Routine Description:
607  This is the service to load the PEI Core from the Firmware Volume
608
609Arguments:
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
615Returns:
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
693EFI_STATUS
694EFIAPI
695SecWinNtPeiAutoScan (
696  IN  UINTN                 Index,
697  OUT EFI_PHYSICAL_ADDRESS  *MemoryBase,
698  OUT UINT64                *MemorySize
699  )
700/*++
701
702Routine 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
710Arguments:
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
715Returns:
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
739VOID *
740EFIAPI
741SecWinNtWinNtThunkAddress (
742  VOID
743  )
744/*++
745
746Routine 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
751Arguments:
752  InterfaceSize - sizeof (EFI_WIN_NT_THUNK_PROTOCOL);
753  InterfaceBase - Address of the gWinNt global
754
755Returns:
756  EFI_SUCCESS - Data returned
757
758--*/
759{
760  return gWinNt;
761}
762
763
764EFI_STATUS
765EFIAPI
766SecWinNtPeiLoadFile (
767  IN  VOID                    *Pe32Data,
768  IN  EFI_PHYSICAL_ADDRESS    *ImageAddress,
769  IN  UINT64                  *ImageSize,
770  IN  EFI_PHYSICAL_ADDRESS    *EntryPoint
771  )
772/*++
773
774Routine Description:
775  Loads and relocates a PE/COFF image into memory.
776
777Arguments:
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
783Returns:
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
836EFI_STATUS
837EFIAPI
838SecWinNtFdAddress (
839  IN     UINTN                 Index,
840  IN OUT EFI_PHYSICAL_ADDRESS  *FdBase,
841  IN OUT UINT64                *FdSize
842  )
843/*++
844
845Routine 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
849Arguments:
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
854Returns:
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
874EFI_STATUS
875EFIAPI
876SecImageRead (
877  IN     VOID    *FileHandle,
878  IN     UINTN   FileOffset,
879  IN OUT UINTN   *ReadSize,
880  OUT    VOID    *Buffer
881  )
882/*++
883
884Routine Description:
885  Support routine for the PE/COFF Loader that reads a buffer from a PE/COFF file
886
887Arguments:
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
893Returns:
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
912CHAR16 *
913AsciiToUnicode (
914  IN  CHAR8   *Ascii,
915  IN  UINTN   *StrLen OPTIONAL
916  )
917/*++
918
919Routine Description:
920  Convert the passed in Ascii string to Unicode.
921  Optionally return the length of the strings.
922
923Arguments:
924  Ascii   - Ascii string to convert
925  StrLen  - Length of string
926
927Returns:
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
958UINTN
959CountSeparatorsInString (
960  IN  CONST CHAR16   *String,
961  IN  CHAR16         Separator
962  )
963/*++
964
965Routine Description:
966  Count the number of separators in String
967
968Arguments:
969  String    - String to process
970  Separator - Item to count
971
972Returns:
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
989EFI_STATUS
990SecNt32PeCoffRelocateImage (
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
1089VOID
1090_ModuleEntryPoint (
1091  VOID
1092  )
1093{
1094}
1095
1096EFI_STATUS
1097EFIAPI
1098SecTemporaryRamSupport (
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