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
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.
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.
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.
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.
26 This code produces 128 K of temporary memory for the PEI stack by directly
27 allocate memory space with ReadWrite and Execute attribute.
37 EFI_PEI_PE_COFF_LOADER_PROTOCOL_INSTANCE mPeiEfiPeiPeCoffLoaderInstance
= {
39 SecNt32PeCoffGetImageInfo
,
40 SecNt32PeCoffLoadImage
,
41 SecNt32PeCoffRelocateImage
,
42 SecNt32PeCoffUnloadimage
49 EFI_PEI_PE_COFF_LOADER_PROTOCOL
*gPeiEfiPeiPeCoffLoader
= &mPeiEfiPeiPeCoffLoaderInstance
.PeCoff
;
51 NT_PEI_LOAD_FILE_PPI mSecNtLoadFilePpi
= { SecWinNtPeiLoadFile
};
53 PEI_NT_AUTOSCAN_PPI mSecNtAutoScanPpi
= { SecWinNtPeiAutoScan
};
55 PEI_NT_THUNK_PPI mSecWinNtThunkPpi
= { SecWinNtWinNtThunkAddress
};
57 EFI_PEI_PROGRESS_CODE_PPI mSecStatusCodePpi
= { SecPeiReportStatusCode
};
59 NT_FWH_PPI mSecFwhInformationPpi
= { SecWinNtFdAddress
};
62 EFI_PEI_PPI_DESCRIPTOR gPrivateDispatchTable
[] = {
64 EFI_PEI_PPI_DESCRIPTOR_PPI
,
65 &gEfiPeiPeCoffLoaderGuid
,
69 EFI_PEI_PPI_DESCRIPTOR_PPI
,
70 &gNtPeiLoadFilePpiGuid
,
74 EFI_PEI_PPI_DESCRIPTOR_PPI
,
75 &gPeiNtAutoScanPpiGuid
,
79 EFI_PEI_PPI_DESCRIPTOR_PPI
,
84 EFI_PEI_PPI_DESCRIPTOR_PPI
,
85 &gEfiPeiStatusCodePpiGuid
,
89 EFI_PEI_PPI_DESCRIPTOR_PPI
| EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST
,
91 &mSecFwhInformationPpi
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.
102 UINTN gFdInfoCount
= 0;
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.
111 UINTN gSystemMemoryCount
= 0;
112 NT_SYSTEM_MEMORY
*gSystemMemory
;
115 UINTN mPdbNameModHandleArraySize
= 0;
116 PDB_NAME_TO_MOD_HANDLE
*mPdbNameModHandleArray
= NULL
;
131 Main entry point to SEC for WinNt. This is a Windows program
134 Argc - Number of command line arguments
135 Argv - Array of command line argument strings
136 Envp - Array of environmemt variable strings
145 EFI_PHYSICAL_ADDRESS InitialStackMemory
;
146 UINT64 InitialStackMemorySize
;
155 CHAR16
*MemorySizeStr
;
156 CHAR16
*FirmwareVolumesStr
;
159 MemorySizeStr
= (CHAR16
*) FixedPcdGetPtr (PcdWinNtMemorySizeForSecMain
);
160 FirmwareVolumesStr
= (CHAR16
*) FixedPcdGetPtr (PcdWinNtFirmwareVolume
);
162 printf ("\nEDK SEC Main NT Emulation Environment from www.TianoCore.org\n");
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.
168 SetPriorityClass (GetCurrentProcess (), IDLE_PRIORITY_CLASS
);
169 SetThreadPriority (GetCurrentThread (), THREAD_PRIORITY_HIGHEST
);
172 // Allocate space for gSystemMemory Array
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
);
181 // Allocate space for gSystemMemory Array
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
);
190 // Setup Boot Mode. If BootModeStr == "" then BootMode = 0 (BOOT_WITH_FULL_CONFIGURATION)
192 printf (" BootMode 0x%02x\n", FixedPcdGet32 (PcdWinNtBootMode
));
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
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");
206 for (StackPointer
= (UINTN
*) (UINTN
) InitialStackMemory
;
207 StackPointer
< (UINTN
*) ((UINTN
)InitialStackMemory
+ (SIZE_T
) InitialStackMemorySize
);
209 *StackPointer
= 0x5AA55AA5;
212 printf (" SEC passing in %d bytes of temp RAM to PEI\n", InitialStackMemorySize
);
215 // Open All the firmware volumes and remember the info in the gFdInfo global
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");
223 StrCpy (FileNamePtr
, (CHAR16
*)FirmwareVolumesStr
);
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
++)
229 if (FileNamePtr
[Index1
] == 0) {
232 FileNamePtr
[Index1
] = '\0';
233 FileNamePtr
= FileNamePtr
+ Index1
+ 1;
237 // Open the FD and remmeber where it got mapped into our processes address space
239 Status
= WinNtOpenFile (
243 &gFdInfo
[Index
].Address
,
246 if (EFI_ERROR (Status
)) {
247 printf ("ERROR : Can not open Firmware Device File %S (%r). Exiting.\n", FileName
, Status
);
251 printf (" FD loaded from");
253 // printf can't print filenames directly as the \ gets interperted as an
256 for (Index2
= 0; FileName
[Index2
] != '\0'; Index2
++) {
257 printf ("%c", FileName
[Index2
]);
260 if (PeiCoreFile
== NULL
) {
262 // Assume the beginning of the FD is an FV and look for the PEI Core.
263 // Load the first one we find.
265 Status
= SecFfsFindPeiCore ((EFI_FIRMWARE_VOLUME_HEADER
*) (UINTN
) gFdInfo
[Index
].Address
, &PeiCoreFile
);
266 if (!EFI_ERROR (Status
)) {
268 printf (" contains SEC Core");
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.
279 for (Index
= 0, Done
= FALSE
; !Done
; Index
++) {
281 // Save the size of the memory and make a Unicode filename SystemMemory00, ...
283 gSystemMemory
[Index
].Size
= _wtoi (MemorySizeStr
) * 0x100000;
286 // Find the next region
288 for (Index1
= 0; MemorySizeStr
[Index1
] != '!' && MemorySizeStr
[Index1
] != 0; Index1
++)
290 if (MemorySizeStr
[Index1
] == 0) {
294 MemorySizeStr
= MemorySizeStr
+ Index1
+ 1;
300 // Hand off to PEI Core
302 SecLoadFromCore ((UINTN
) InitialStackMemory
, (UINTN
) InitialStackMemorySize
, (UINTN
) gFdInfo
[0].Address
, PeiCoreFile
);
305 // If we get here, then the PEI Core returned. This is an error as PEI should
306 // always hand off to DXE.
308 printf ("ERROR : PEI Core returned\n");
316 IN DWORD CreationDisposition
,
317 IN OUT EFI_PHYSICAL_ADDRESS
*BaseAddress
,
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.
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
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
346 VOID
*VirtualAddress
;
350 // Use Win API to open/create a file
352 NtFileHandle
= CreateFile (
354 GENERIC_READ
| GENERIC_WRITE
,
358 FILE_ATTRIBUTE_NORMAL
,
361 if (NtFileHandle
== INVALID_HANDLE_VALUE
) {
362 return EFI_NOT_FOUND
;
365 // Map the open file into a memory range
367 NtMapHandle
= CreateFileMapping (
375 if (NtMapHandle
== NULL
) {
376 return EFI_DEVICE_ERROR
;
379 // Get the virtual address (address in the emulator) of the mapped file
381 VirtualAddress
= MapViewOfFileEx (
387 (LPVOID
) (UINTN
) *BaseAddress
389 if (VirtualAddress
== NULL
) {
390 return EFI_DEVICE_ERROR
;
395 // Seek to the end of the file to figure out the true file size.
397 FileSize
= SetFilePointer (
403 if (FileSize
== -1) {
404 return EFI_DEVICE_ERROR
;
407 *Length
= (UINT64
) FileSize
;
409 *Length
= (UINT64
) MapSize
;
412 *BaseAddress
= (EFI_PHYSICAL_ADDRESS
) (UINTN
) VirtualAddress
;
418 #define BYTES_PER_RECORD 512
422 SecPeiReportStatusCode (
423 IN CONST EFI_PEI_SERVICES
**PeiServices
,
424 IN EFI_STATUS_CODE_TYPE CodeType
,
425 IN EFI_STATUS_CODE_VALUE Value
,
427 IN CONST EFI_GUID
*CallerId
,
428 IN CONST EFI_STATUS_CODE_DATA
*Data OPTIONAL
434 This routine produces the ReportStatusCode PEI service. It's passed
435 up to the PEI Core via a PPI. T
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.
441 (see EFI_PEI_REPORT_STATUS_CODE)
444 EFI_SUCCESS - Always return success
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
456 CHAR8 PrintBuffer
[BYTES_PER_RECORD
* 2];
464 } else if (ReportStatusCodeExtractAssertInfo (CodeType
, Value
, Data
, &Filename
, &Description
, &LineNumber
)) {
466 // Processes ASSERT ()
468 printf ("ASSERT %s(%d): %s\n", Filename
, LineNumber
, Description
);
470 } else if (ReportStatusCodeExtractDebugInfo (Data
, &ErrorLevel
, &Marker
, &Format
)) {
472 // Process DEBUG () macro
474 AsciiVSPrint (PrintBuffer
, BYTES_PER_RECORD
, Format
, Marker
);
475 printf (PrintBuffer
);
482 Transfers control to a function starting with a new stack.
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.
489 If EntryPoint is NULL, then ASSERT().
490 If NewStack is NULL, then ASSERT().
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
495 @param Context2 A pointer to the context to pass into the EntryPoint
497 @param NewStack A pointer to the new stack to use for the EntryPoint
499 @param NewBsp A pointer to the new BSP for the EntryPoint on IPF. It's
500 Reserved on other architectures.
506 IN SWITCH_STACK_ENTRY_POINT EntryPoint
,
507 IN VOID
*Context1
, OPTIONAL
508 IN VOID
*Context2
, OPTIONAL
509 IN VOID
*Context3
, OPTIONAL
513 BASE_LIBRARY_JUMP_BUFFER JumpBuffer
;
515 ASSERT (EntryPoint
!= NULL
);
516 ASSERT (NewStack
!= NULL
);
519 // Stack should be aligned with CPU_STACK_ALIGNMENT
521 ASSERT (((UINTN
)NewStack
& (CPU_STACK_ALIGNMENT
- 1)) == 0);
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
;
530 LongJump (&JumpBuffer
, (UINTN
)-1);
534 // InternalSwitchStack () will never return
541 IN UINTN LargestRegion
,
542 IN UINTN LargestRegionSize
,
543 IN UINTN BootFirmwareVolumeBase
,
544 IN VOID
*PeiCorePe32File
549 This is the service to load the PEI Core from the Firmware Volume
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
558 Success means control is transfered and thus we should never return
563 EFI_PHYSICAL_ADDRESS TopOfMemory
;
566 EFI_PHYSICAL_ADDRESS PeiCoreEntryPoint
;
567 EFI_PHYSICAL_ADDRESS PeiImageAddress
;
568 EFI_SEC_PEI_HAND_OFF
*SecCoreData
;
571 // Compute Top Of Memory for Stack and PEI Core Allocations
573 TopOfMemory
= LargestRegion
+ LargestRegionSize
;
576 // Allocate 128KB for the Stack
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
;
583 // Patch value in dispatch table values
585 gPrivateDispatchTable
[0].Ppi
= gPeiEfiPeiPeCoffLoader
;
588 // Bind this information into the SEC hand-off state
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);
602 // Load the PEI Core from a Firmware Volume
604 Status
= SecWinNtPeiLoadFile (
610 if (EFI_ERROR (Status
)) {
615 // Transfer control to the PEI Core
618 (SWITCH_STACK_ENTRY_POINT
) (UINTN
) PeiCoreEntryPoint
,
620 (VOID
*) (UINTN
) ((EFI_PEI_PPI_DESCRIPTOR
*) &gPrivateDispatchTable
),
625 // If we get here, then the PEI Core returned. This is an error
632 SecWinNtPeiAutoScan (
634 OUT EFI_PHYSICAL_ADDRESS
*MemoryBase
,
635 OUT UINT64
*MemorySize
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.
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
653 EFI_SUCCESS - If memory region was mapped
654 EFI_UNSUPPORTED - If Index is not supported
658 if (Index
>= gSystemMemoryCount
) {
659 return EFI_UNSUPPORTED
;
663 // Allocate enough memory space for emulator
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
;
670 *MemoryBase
= gSystemMemory
[Index
].Memory
;
671 *MemorySize
= gSystemMemory
[Index
].Size
;
678 SecWinNtWinNtThunkAddress (
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.
689 InterfaceSize - sizeof (EFI_WIN_NT_THUNK_PROTOCOL);
690 InterfaceBase - Address of the gWinNt global
693 EFI_SUCCESS - Data returned
703 SecWinNtPeiLoadFile (
705 IN EFI_PHYSICAL_ADDRESS
*ImageAddress
,
706 IN UINT64
*ImageSize
,
707 IN EFI_PHYSICAL_ADDRESS
*EntryPoint
712 Loads and relocates a PE/COFF image into memory.
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
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
727 PE_COFF_LOADER_IMAGE_CONTEXT ImageContext
;
729 ZeroMem (&ImageContext
, sizeof (ImageContext
));
730 ImageContext
.Handle
= Pe32Data
;
732 ImageContext
.ImageRead
= (PE_COFF_LOADER_READ_FILE
) SecImageRead
;
734 Status
= gPeiEfiPeiPeCoffLoader
->GetImageInfo (gPeiEfiPeiPeCoffLoader
, &ImageContext
);
735 if (EFI_ERROR (Status
)) {
739 // Allocate space in NT (not emulator) memory with ReadWrite and Execute attribue.
740 // Extra space is for alignment
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
;
747 // Align buffer on section boundry
749 ImageContext
.ImageAddress
+= ImageContext
.SectionAlignment
;
750 ImageContext
.ImageAddress
&= ~(ImageContext
.SectionAlignment
- 1);
752 Status
= gPeiEfiPeiPeCoffLoader
->LoadImage (gPeiEfiPeiPeCoffLoader
, &ImageContext
);
753 if (EFI_ERROR (Status
)) {
757 Status
= gPeiEfiPeiPeCoffLoader
->RelocateImage (gPeiEfiPeiPeCoffLoader
, &ImageContext
);
758 if (EFI_ERROR (Status
)) {
763 // BugBug: Flush Instruction Cache Here when CPU Lib is ready
766 *ImageAddress
= ImageContext
.ImageAddress
;
767 *ImageSize
= ImageContext
.ImageSize
;
768 *EntryPoint
= ImageContext
.EntryPoint
;
777 IN OUT EFI_PHYSICAL_ADDRESS
*FdBase
,
778 IN OUT UINT64
*FdSize
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.
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
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
797 if (Index
>= gFdInfoCount
) {
798 return EFI_UNSUPPORTED
;
801 *FdBase
= gFdInfo
[Index
].Address
;
802 *FdSize
= gFdInfo
[Index
].Size
;
804 if (*FdBase
== 0 && *FdSize
== 0) {
805 return EFI_UNSUPPORTED
;
816 IN OUT UINTN
*ReadSize
,
822 Support routine for the PE/COFF Loader that reads a buffer from a PE/COFF file
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.
831 EFI_SUCCESS - ReadSize bytes of data were read into Buffer from the PE/COFF file starting at FileOffset
839 Destination8
= Buffer
;
840 Source8
= (CHAR8
*) ((UINTN
) FileHandle
+ FileOffset
);
843 *(Destination8
++) = *(Source8
++);
852 IN UINTN
*StrLen OPTIONAL
857 Convert the passed in Ascii string to Unicode.
858 Optionally return the length of the strings.
861 Ascii - Ascii string to convert
862 StrLen - Length of string
865 Pointer to malloc'ed Unicode version of Ascii
873 // Allocate a buffer for unicode string
875 for (Index
= 0; Ascii
[Index
] != '\0'; Index
++)
877 Unicode
= malloc ((Index
+ 1) * sizeof (CHAR16
));
878 if (Unicode
== NULL
) {
882 for (Index
= 0; Ascii
[Index
] != '\0'; Index
++) {
883 Unicode
[Index
] = (CHAR16
) Ascii
[Index
];
886 Unicode
[Index
] = '\0';
888 if (StrLen
!= NULL
) {
896 CountSeperatorsInString (
897 IN
const CHAR16
*String
,
903 Count the number of seperators in String
906 String - String to process
907 Seperator - Item to count
910 Number of Seperator in String
916 for (Count
= 0; *String
!= '\0'; String
++) {
917 if (*String
== Seperator
) {
928 IN PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
,
934 Store the ModHandle in an array indexed by the Pdb File name.
935 The ModHandle is needed to unload the image.
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
944 EFI_SUCCESS - ModHandle was stored.
949 PDB_NAME_TO_MOD_HANDLE
*Array
;
953 Array
= mPdbNameModHandleArray
;
954 for (Index
= 0; Index
< mPdbNameModHandleArraySize
; Index
++, Array
++) {
955 if (Array
->PdbPointer
== NULL
) {
957 // Make a copy of the stirng and store the ModHandle
959 Array
->PdbPointer
= malloc (strlen (ImageContext
->PdbPointer
) + 1);
960 ASSERT (Array
->PdbPointer
!= NULL
);
962 strcpy (Array
->PdbPointer
, ImageContext
->PdbPointer
);
963 Array
->ModHandle
= ModHandle
;
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.
974 PreviousSize
= mPdbNameModHandleArraySize
* sizeof (PDB_NAME_TO_MOD_HANDLE
);
975 mPdbNameModHandleArraySize
+= MAX_PDB_NAME_TO_MOD_HANDLE_ARRAY_SIZE
;
977 mPdbNameModHandleArray
= realloc (mPdbNameModHandleArray
, mPdbNameModHandleArraySize
* sizeof (PDB_NAME_TO_MOD_HANDLE
));
978 if (mPdbNameModHandleArray
== NULL
) {
980 return EFI_OUT_OF_RESOURCES
;
983 memset (mPdbNameModHandleArray
+ PreviousSize
, 0, MAX_PDB_NAME_TO_MOD_HANDLE_ARRAY_SIZE
* sizeof (PDB_NAME_TO_MOD_HANDLE
));
985 return AddModHandle (ImageContext
, ModHandle
);
991 IN PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
996 Return the ModHandle and delete the entry in the array.
999 ImageContext - Input data returned from PE Laoder Library. Used to find the
1000 .PDB file name of the PE Image.
1003 ModHandle - ModHandle assoicated with ImageContext is returned
1004 NULL - No ModHandle associated with ImageContext
1009 PDB_NAME_TO_MOD_HANDLE
*Array
;
1011 if (ImageContext
->PdbPointer
== NULL
) {
1013 // If no PDB pointer there is no ModHandle so return NULL
1018 Array
= mPdbNameModHandleArray
;
1019 for (Index
= 0; Index
< mPdbNameModHandleArraySize
; Index
++, Array
++) {
1020 if ((Array
->PdbPointer
!= NULL
) && (strcmp(Array
->PdbPointer
, ImageContext
->PdbPointer
) == 0)) {
1022 // If you find a match return it and delete the entry
1024 free (Array
->PdbPointer
);
1025 Array
->PdbPointer
= NULL
;
1026 return Array
->ModHandle
;
1037 SecNt32PeCoffGetImageInfo (
1038 IN EFI_PEI_PE_COFF_LOADER_PROTOCOL
*This
,
1039 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
1044 Status
= PeCoffLoaderGetImageInfo (ImageContext
);
1045 if (EFI_ERROR (Status
)) {
1049 switch (ImageContext
->ImageType
) {
1051 case EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION
:
1052 ImageContext
->ImageCodeMemoryType
= EfiLoaderCode
;
1053 ImageContext
->ImageDataMemoryType
= EfiLoaderData
;
1056 case EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER
:
1057 ImageContext
->ImageCodeMemoryType
= EfiBootServicesCode
;
1058 ImageContext
->ImageDataMemoryType
= EfiBootServicesData
;
1061 case EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER
:
1062 case EFI_IMAGE_SUBSYSTEM_SAL_RUNTIME_DRIVER
:
1063 ImageContext
->ImageCodeMemoryType
= EfiRuntimeServicesCode
;
1064 ImageContext
->ImageDataMemoryType
= EfiRuntimeServicesData
;
1068 ImageContext
->ImageError
= IMAGE_ERROR_INVALID_SUBSYSTEM
;
1069 return RETURN_UNSUPPORTED
;
1077 SecNt32PeCoffLoadImage (
1078 IN EFI_PEI_PE_COFF_LOADER_PROTOCOL
*This
,
1079 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
1084 Status
= PeCoffLoaderLoadImage (ImageContext
);
1090 SecNt32PeCoffRelocateImage (
1091 IN EFI_PEI_PE_COFF_LOADER_PROTOCOL
*This
,
1092 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
1096 VOID
*DllEntryPoint
;
1097 CHAR16
*DllFileName
;
1102 Status
= PeCoffLoaderRelocateImage (ImageContext
);
1103 if (EFI_ERROR (Status
)) {
1105 // We could not relocated the image in memory properly
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.
1119 DllEntryPoint
= NULL
;
1122 // Load the DLL if it's not an EBC image.
1124 if ((ImageContext
->PdbPointer
!= NULL
) &&
1125 (ImageContext
->Machine
!= EFI_IMAGE_MACHINE_EBC
)) {
1127 // Convert filename from ASCII to Unicode
1129 DllFileName
= AsciiToUnicode (ImageContext
->PdbPointer
, &Index
);
1132 // Check that we have a valid filename
1134 if (Index
< 5 || DllFileName
[Index
- 4] != '.') {
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.
1145 // Replace .PDB with .DLL on the filename
1147 DllFileName
[Index
- 3] = 'D';
1148 DllFileName
[Index
- 2] = 'L';
1149 DllFileName
[Index
- 1] = 'L';
1152 // Load the .DLL file into the user process's address space for source
1155 Library
= LoadLibraryEx (DllFileName
, NULL
, DONT_RESOLVE_DLL_REFERENCES
);
1156 if (Library
!= NULL
) {
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
1165 DllEntryPoint
= (VOID
*) (UINTN
) GetProcAddress (Library
, "InitializeDriver");
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
);
1174 wprintf (L
"WARNING: No source level debug %s. \n", DllFileName
);
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.
1191 SecNt32PeCoffUnloadimage (
1192 IN EFI_PEI_PE_COFF_LOADER_PROTOCOL
*This
,
1193 IN PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
1198 ModHandle
= RemoveModeHandle (ImageContext
);
1199 if (ModHandle
!= NULL
) {
1200 FreeLibrary (ModHandle
);