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