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