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