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