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
;
158 MemorySizeStr
= (CHAR16
*) FixedPcdGetPtr (PcdWinNtMemorySizeForSecMain
);
159 FirmwareVolumesStr
= (CHAR16
*) FixedPcdGetPtr (PcdWinNtFirmwareVolume
);
161 printf ("\nEDK SEC Main NT Emulation Environment from www.TianoCore.org\n");
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.
167 SetPriorityClass (GetCurrentProcess (), IDLE_PRIORITY_CLASS
);
168 SetThreadPriority (GetCurrentThread (), THREAD_PRIORITY_HIGHEST
);
171 // Allocate space for gSystemMemory Array
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
);
180 // Allocate space for gSystemMemory Array
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
);
189 // Setup Boot Mode. If BootModeStr == "" then BootMode = 0 (BOOT_WITH_FULL_CONFIGURATION)
191 printf (" BootMode 0x%02x\n", FixedPcdGet32 (PcdWinNtBootMode
));
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
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");
205 printf (" SEC passing in %d bytes of temp RAM to PEI\n", InitialStackMemorySize
);
208 // Open All the firmware volumes and remember the info in the gFdInfo global
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");
216 StrCpy (FileNamePtr
, (CHAR16
*)FirmwareVolumesStr
);
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
++)
222 if (FileNamePtr
[Index1
] == 0) {
225 FileNamePtr
[Index1
] = '\0';
226 FileNamePtr
= FileNamePtr
+ Index1
+ 1;
230 // Open the FD and remmeber where it got mapped into our processes address space
232 Status
= WinNtOpenFile (
236 &gFdInfo
[Index
].Address
,
239 if (EFI_ERROR (Status
)) {
240 printf ("ERROR : Can not open Firmware Device File %S (%r). Exiting.\n", FileName
, Status
);
244 printf (" FD loaded from");
246 // printf can't print filenames directly as the \ gets interperted as an
249 for (Index2
= 0; FileName
[Index2
] != '\0'; Index2
++) {
250 printf ("%c", FileName
[Index2
]);
253 if (PeiCoreFile
== NULL
) {
255 // Assume the beginning of the FD is an FV and look for the PEI Core.
256 // Load the first one we find.
258 Status
= SecFfsFindPeiCore ((EFI_FIRMWARE_VOLUME_HEADER
*) (UINTN
) gFdInfo
[Index
].Address
, &PeiCoreFile
);
259 if (!EFI_ERROR (Status
)) {
261 printf (" contains SEC Core");
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.
272 for (Index
= 0, Done
= FALSE
; !Done
; Index
++) {
274 // Save the size of the memory and make a Unicode filename SystemMemory00, ...
276 gSystemMemory
[Index
].Size
= _wtoi (MemorySizeStr
) * 0x100000;
279 // Find the next region
281 for (Index1
= 0; MemorySizeStr
[Index1
] != '!' && MemorySizeStr
[Index1
] != 0; Index1
++)
283 if (MemorySizeStr
[Index1
] == 0) {
287 MemorySizeStr
= MemorySizeStr
+ Index1
+ 1;
293 // Hand off to PEI Core
295 SecLoadFromCore ((UINTN
) InitialStackMemory
, (UINTN
) InitialStackMemorySize
, (UINTN
) gFdInfo
[0].Address
, PeiCoreFile
);
298 // If we get here, then the PEI Core returned. This is an error as PEI should
299 // always hand off to DXE.
301 printf ("ERROR : PEI Core returned\n");
309 IN DWORD CreationDisposition
,
310 IN OUT EFI_PHYSICAL_ADDRESS
*BaseAddress
,
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.
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
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
339 VOID
*VirtualAddress
;
343 // Use Win API to open/create a file
345 NtFileHandle
= CreateFile (
347 GENERIC_READ
| GENERIC_WRITE
,
351 FILE_ATTRIBUTE_NORMAL
,
354 if (NtFileHandle
== INVALID_HANDLE_VALUE
) {
355 return EFI_NOT_FOUND
;
358 // Map the open file into a memory range
360 NtMapHandle
= CreateFileMapping (
368 if (NtMapHandle
== NULL
) {
369 return EFI_DEVICE_ERROR
;
372 // Get the virtual address (address in the emulator) of the mapped file
374 VirtualAddress
= MapViewOfFileEx (
380 (LPVOID
) (UINTN
) *BaseAddress
382 if (VirtualAddress
== NULL
) {
383 return EFI_DEVICE_ERROR
;
388 // Seek to the end of the file to figure out the true file size.
390 FileSize
= SetFilePointer (
396 if (FileSize
== -1) {
397 return EFI_DEVICE_ERROR
;
400 *Length
= (UINT64
) FileSize
;
402 *Length
= (UINT64
) MapSize
;
405 *BaseAddress
= (EFI_PHYSICAL_ADDRESS
) (UINTN
) VirtualAddress
;
411 #define BYTES_PER_RECORD 512
415 SecPeiReportStatusCode (
416 IN CONST EFI_PEI_SERVICES
**PeiServices
,
417 IN EFI_STATUS_CODE_TYPE CodeType
,
418 IN EFI_STATUS_CODE_VALUE Value
,
420 IN CONST EFI_GUID
*CallerId
,
421 IN CONST EFI_STATUS_CODE_DATA
*Data OPTIONAL
427 This routine produces the ReportStatusCode PEI service. It's passed
428 up to the PEI Core via a PPI. T
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.
434 (see EFI_PEI_REPORT_STATUS_CODE)
437 EFI_SUCCESS - Always return success
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
449 CHAR8 PrintBuffer
[BYTES_PER_RECORD
* 2];
457 } else if (ReportStatusCodeExtractAssertInfo (CodeType
, Value
, Data
, &Filename
, &Description
, &LineNumber
)) {
459 // Processes ASSERT ()
461 printf ("ASSERT %s(%d): %s\n", Filename
, LineNumber
, Description
);
463 } else if (ReportStatusCodeExtractDebugInfo (Data
, &ErrorLevel
, &Marker
, &Format
)) {
465 // Process DEBUG () macro
467 AsciiVSPrint (PrintBuffer
, BYTES_PER_RECORD
, Format
, Marker
);
468 printf (PrintBuffer
);
475 Transfers control to a function starting with a new stack.
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.
482 If EntryPoint is NULL, then ASSERT().
483 If NewStack is NULL, then ASSERT().
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
488 @param Context2 A pointer to the context to pass into the EntryPoint
490 @param NewStack A pointer to the new stack to use for the EntryPoint
492 @param NewBsp A pointer to the new BSP for the EntryPoint on IPF. It's
493 Reserved on other architectures.
499 IN SWITCH_STACK_ENTRY_POINT EntryPoint
,
500 IN VOID
*Context1
, OPTIONAL
501 IN VOID
*Context2
, OPTIONAL
502 IN VOID
*Context3
, OPTIONAL
506 BASE_LIBRARY_JUMP_BUFFER JumpBuffer
;
508 ASSERT (EntryPoint
!= NULL
);
509 ASSERT (NewStack
!= NULL
);
512 // Stack should be aligned with CPU_STACK_ALIGNMENT
514 ASSERT (((UINTN
)NewStack
& (CPU_STACK_ALIGNMENT
- 1)) == 0);
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
;
523 LongJump (&JumpBuffer
, (UINTN
)-1);
527 // InternalSwitchStack () will never return
534 IN UINTN LargestRegion
,
535 IN UINTN LargestRegionSize
,
536 IN UINTN BootFirmwareVolumeBase
,
537 IN VOID
*PeiCorePe32File
542 This is the service to load the PEI Core from the Firmware Volume
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
551 Success means control is transfered and thus we should never return
556 EFI_PHYSICAL_ADDRESS TopOfMemory
;
559 EFI_PHYSICAL_ADDRESS PeiCoreEntryPoint
;
560 EFI_PHYSICAL_ADDRESS PeiImageAddress
;
561 EFI_SEC_PEI_HAND_OFF
*SecCoreData
;
564 // Compute Top Of Memory for Stack and PEI Core Allocations
566 TopOfMemory
= LargestRegion
+ LargestRegionSize
;
569 // Allocate 128KB for the Stack
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
;
576 // Patch value in dispatch table values
578 gPrivateDispatchTable
[0].Ppi
= gPeiEfiPeiPeCoffLoader
;
581 // Bind this information into the SEC hand-off state
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);
595 // Load the PEI Core from a Firmware Volume
597 Status
= SecWinNtPeiLoadFile (
603 if (EFI_ERROR (Status
)) {
608 // Transfer control to the PEI Core
611 (SWITCH_STACK_ENTRY_POINT
) (UINTN
) PeiCoreEntryPoint
,
613 (VOID
*) (UINTN
) ((EFI_PEI_PPI_DESCRIPTOR
*) &gPrivateDispatchTable
),
618 // If we get here, then the PEI Core returned. This is an error
625 SecWinNtPeiAutoScan (
627 OUT EFI_PHYSICAL_ADDRESS
*MemoryBase
,
628 OUT UINT64
*MemorySize
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.
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
646 EFI_SUCCESS - If memory region was mapped
647 EFI_UNSUPPORTED - If Index is not supported
651 if (Index
>= gSystemMemoryCount
) {
652 return EFI_UNSUPPORTED
;
656 // Allocate enough memory space for emulator
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
;
663 *MemoryBase
= gSystemMemory
[Index
].Memory
;
664 *MemorySize
= gSystemMemory
[Index
].Size
;
671 SecWinNtWinNtThunkAddress (
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.
682 InterfaceSize - sizeof (EFI_WIN_NT_THUNK_PROTOCOL);
683 InterfaceBase - Address of the gWinNt global
686 EFI_SUCCESS - Data returned
696 SecWinNtPeiLoadFile (
698 IN EFI_PHYSICAL_ADDRESS
*ImageAddress
,
699 IN UINT64
*ImageSize
,
700 IN EFI_PHYSICAL_ADDRESS
*EntryPoint
705 Loads and relocates a PE/COFF image into memory.
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
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
720 PE_COFF_LOADER_IMAGE_CONTEXT ImageContext
;
722 ZeroMem (&ImageContext
, sizeof (ImageContext
));
723 ImageContext
.Handle
= Pe32Data
;
725 ImageContext
.ImageRead
= (PE_COFF_LOADER_READ_FILE
) SecImageRead
;
727 Status
= gPeiEfiPeiPeCoffLoader
->GetImageInfo (gPeiEfiPeiPeCoffLoader
, &ImageContext
);
728 if (EFI_ERROR (Status
)) {
732 // Allocate space in NT (not emulator) memory with ReadWrite and Execute attribue.
733 // Extra space is for alignment
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
;
740 // Align buffer on section boundry
742 ImageContext
.ImageAddress
+= ImageContext
.SectionAlignment
;
743 ImageContext
.ImageAddress
&= ~(ImageContext
.SectionAlignment
- 1);
745 Status
= gPeiEfiPeiPeCoffLoader
->LoadImage (gPeiEfiPeiPeCoffLoader
, &ImageContext
);
746 if (EFI_ERROR (Status
)) {
750 Status
= gPeiEfiPeiPeCoffLoader
->RelocateImage (gPeiEfiPeiPeCoffLoader
, &ImageContext
);
751 if (EFI_ERROR (Status
)) {
756 // BugBug: Flush Instruction Cache Here when CPU Lib is ready
759 *ImageAddress
= ImageContext
.ImageAddress
;
760 *ImageSize
= ImageContext
.ImageSize
;
761 *EntryPoint
= ImageContext
.EntryPoint
;
770 IN OUT EFI_PHYSICAL_ADDRESS
*FdBase
,
771 IN OUT UINT64
*FdSize
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.
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
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
790 if (Index
>= gFdInfoCount
) {
791 return EFI_UNSUPPORTED
;
794 *FdBase
= gFdInfo
[Index
].Address
;
795 *FdSize
= gFdInfo
[Index
].Size
;
797 if (*FdBase
== 0 && *FdSize
== 0) {
798 return EFI_UNSUPPORTED
;
809 IN OUT UINTN
*ReadSize
,
815 Support routine for the PE/COFF Loader that reads a buffer from a PE/COFF file
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.
824 EFI_SUCCESS - ReadSize bytes of data were read into Buffer from the PE/COFF file starting at FileOffset
832 Destination8
= Buffer
;
833 Source8
= (CHAR8
*) ((UINTN
) FileHandle
+ FileOffset
);
836 *(Destination8
++) = *(Source8
++);
845 IN UINTN
*StrLen OPTIONAL
850 Convert the passed in Ascii string to Unicode.
851 Optionally return the length of the strings.
854 Ascii - Ascii string to convert
855 StrLen - Length of string
858 Pointer to malloc'ed Unicode version of Ascii
866 // Allocate a buffer for unicode string
868 for (Index
= 0; Ascii
[Index
] != '\0'; Index
++)
870 Unicode
= malloc ((Index
+ 1) * sizeof (CHAR16
));
871 if (Unicode
== NULL
) {
875 for (Index
= 0; Ascii
[Index
] != '\0'; Index
++) {
876 Unicode
[Index
] = (CHAR16
) Ascii
[Index
];
879 Unicode
[Index
] = '\0';
881 if (StrLen
!= NULL
) {
889 CountSeperatorsInString (
890 IN
const CHAR16
*String
,
896 Count the number of seperators in String
899 String - String to process
900 Seperator - Item to count
903 Number of Seperator in String
909 for (Count
= 0; *String
!= '\0'; String
++) {
910 if (*String
== Seperator
) {
921 IN PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
,
927 Store the ModHandle in an array indexed by the Pdb File name.
928 The ModHandle is needed to unload the image.
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
937 EFI_SUCCESS - ModHandle was stored.
942 PDB_NAME_TO_MOD_HANDLE
*Array
;
946 Array
= mPdbNameModHandleArray
;
947 for (Index
= 0; Index
< mPdbNameModHandleArraySize
; Index
++, Array
++) {
948 if (Array
->PdbPointer
== NULL
) {
950 // Make a copy of the stirng and store the ModHandle
952 Array
->PdbPointer
= malloc (strlen (ImageContext
->PdbPointer
) + 1);
953 ASSERT (Array
->PdbPointer
!= NULL
);
955 strcpy (Array
->PdbPointer
, ImageContext
->PdbPointer
);
956 Array
->ModHandle
= ModHandle
;
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.
967 PreviousSize
= mPdbNameModHandleArraySize
* sizeof (PDB_NAME_TO_MOD_HANDLE
);
968 mPdbNameModHandleArraySize
+= MAX_PDB_NAME_TO_MOD_HANDLE_ARRAY_SIZE
;
970 mPdbNameModHandleArray
= realloc (mPdbNameModHandleArray
, mPdbNameModHandleArraySize
* sizeof (PDB_NAME_TO_MOD_HANDLE
));
971 if (mPdbNameModHandleArray
== NULL
) {
973 return EFI_OUT_OF_RESOURCES
;
976 memset (mPdbNameModHandleArray
+ PreviousSize
, 0, MAX_PDB_NAME_TO_MOD_HANDLE_ARRAY_SIZE
* sizeof (PDB_NAME_TO_MOD_HANDLE
));
978 return AddModHandle (ImageContext
, ModHandle
);
984 IN PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
989 Return the ModHandle and delete the entry in the array.
992 ImageContext - Input data returned from PE Laoder Library. Used to find the
993 .PDB file name of the PE Image.
996 ModHandle - ModHandle assoicated with ImageContext is returned
997 NULL - No ModHandle associated with ImageContext
1002 PDB_NAME_TO_MOD_HANDLE
*Array
;
1004 if (ImageContext
->PdbPointer
== NULL
) {
1006 // If no PDB pointer there is no ModHandle so return NULL
1011 Array
= mPdbNameModHandleArray
;
1012 for (Index
= 0; Index
< mPdbNameModHandleArraySize
; Index
++, Array
++) {
1013 if ((Array
->PdbPointer
!= NULL
) && (strcmp(Array
->PdbPointer
, ImageContext
->PdbPointer
) == 0)) {
1015 // If you find a match return it and delete the entry
1017 free (Array
->PdbPointer
);
1018 Array
->PdbPointer
= NULL
;
1019 return Array
->ModHandle
;
1030 SecNt32PeCoffGetImageInfo (
1031 IN EFI_PEI_PE_COFF_LOADER_PROTOCOL
*This
,
1032 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
1037 Status
= PeCoffLoaderGetImageInfo (ImageContext
);
1038 if (EFI_ERROR (Status
)) {
1042 switch (ImageContext
->ImageType
) {
1044 case EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION
:
1045 ImageContext
->ImageCodeMemoryType
= EfiLoaderCode
;
1046 ImageContext
->ImageDataMemoryType
= EfiLoaderData
;
1049 case EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER
:
1050 ImageContext
->ImageCodeMemoryType
= EfiBootServicesCode
;
1051 ImageContext
->ImageDataMemoryType
= EfiBootServicesData
;
1054 case EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER
:
1055 case EFI_IMAGE_SUBSYSTEM_SAL_RUNTIME_DRIVER
:
1056 ImageContext
->ImageCodeMemoryType
= EfiRuntimeServicesCode
;
1057 ImageContext
->ImageDataMemoryType
= EfiRuntimeServicesData
;
1061 ImageContext
->ImageError
= IMAGE_ERROR_INVALID_SUBSYSTEM
;
1062 return RETURN_UNSUPPORTED
;
1070 SecNt32PeCoffLoadImage (
1071 IN EFI_PEI_PE_COFF_LOADER_PROTOCOL
*This
,
1072 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
1077 Status
= PeCoffLoaderLoadImage (ImageContext
);
1083 SecNt32PeCoffRelocateImage (
1084 IN EFI_PEI_PE_COFF_LOADER_PROTOCOL
*This
,
1085 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
1089 VOID
*DllEntryPoint
;
1090 CHAR16
*DllFileName
;
1095 Status
= PeCoffLoaderRelocateImage (ImageContext
);
1096 if (EFI_ERROR (Status
)) {
1098 // We could not relocated the image in memory properly
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.
1112 DllEntryPoint
= NULL
;
1115 // Load the DLL if it's not an EBC image.
1117 if ((ImageContext
->PdbPointer
!= NULL
) &&
1118 (ImageContext
->Machine
!= EFI_IMAGE_MACHINE_EBC
)) {
1120 // Convert filename from ASCII to Unicode
1122 DllFileName
= AsciiToUnicode (ImageContext
->PdbPointer
, &Index
);
1125 // Check that we have a valid filename
1127 if (Index
< 5 || DllFileName
[Index
- 4] != '.') {
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.
1138 // Replace .PDB with .DLL on the filename
1140 DllFileName
[Index
- 3] = 'D';
1141 DllFileName
[Index
- 2] = 'L';
1142 DllFileName
[Index
- 1] = 'L';
1145 // Load the .DLL file into the user process's address space for source
1148 Library
= LoadLibraryEx (DllFileName
, NULL
, DONT_RESOLVE_DLL_REFERENCES
);
1149 if (Library
!= NULL
) {
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
1158 DllEntryPoint
= (VOID
*) (UINTN
) GetProcAddress (Library
, "InitializeDriver");
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
);
1167 wprintf (L
"WARNING: No source level debug %s. \n", DllFileName
);
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.
1184 SecNt32PeCoffUnloadimage (
1185 IN EFI_PEI_PE_COFF_LOADER_PROTOCOL
*This
,
1186 IN PE_COFF_LOADER_IMAGE_CONTEXT
*ImageContext
1191 ModHandle
= RemoveModeHandle (ImageContext
);
1192 if (ModHandle
!= NULL
) {
1193 FreeLibrary (ModHandle
);