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