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