]> git.proxmox.com Git - mirror_edk2.git/blame - InOsEmuPkg/Unix/Sec/SecMain.c
Fix the issue when checking the value of KeyDescriptor->Modifier to see if it was...
[mirror_edk2.git] / InOsEmuPkg / Unix / Sec / SecMain.c
CommitLineData
949f388f 1/*++ @file
2
3Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
4Portions copyright (c) 2008 - 2011, Apple Inc. All rights reserved.<BR>
5This program and the accompanying materials
6are licensed and made available under the terms and conditions of the BSD License
7which accompanies this distribution. The full text of the license may be found at
8http://opensource.org/licenses/bsd-license.php
9
10THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12
13**/
14
15#include "SecMain.h"
16
17#ifdef __APPLE__
18#define MAP_ANONYMOUS MAP_ANON
19char *gGdbWorkingFileName = NULL;
20#endif
21
22
23//
24// Globals
25//
26
27EMU_THUNK_PPI mSecEmuThunkPpi = {
28 GasketSecUnixPeiAutoScan,
29 GasketSecUnixFdAddress,
65e3f333 30 GasketSecEmuThunkAddress
949f388f 31};
32
949f388f 33
34
35
36//
37// Default information about where the FD is located.
38// This array gets filled in with information from EFI_FIRMWARE_VOLUMES
39// EFI_FIRMWARE_VOLUMES is a host environment variable set by system.cmd.
40// The number of array elements is allocated base on parsing
41// EFI_FIRMWARE_VOLUMES and the memory is never freed.
42//
65e3f333 43UINTN gFdInfoCount = 0;
44EMU_FD_INFO *gFdInfo;
949f388f 45
46//
47// Array that supports seperate memory rantes.
48// The memory ranges are set in system.cmd via the EFI_MEMORY_SIZE variable.
49// The number of array elements is allocated base on parsing
50// EFI_MEMORY_SIZE and the memory is never freed.
51//
65e3f333 52UINTN gSystemMemoryCount = 0;
53EMU_SYSTEM_MEMORY *gSystemMemory;
949f388f 54
55
56
57UINTN mImageContextModHandleArraySize = 0;
58IMAGE_CONTEXT_TO_MOD_HANDLE *mImageContextModHandleArray = NULL;
59
60
61
949f388f 62/*++
63
64Routine Description:
65 Main entry point to SEC for Unix. This is a unix program
66
67Arguments:
68 Argc - Number of command line arguments
69 Argv - Array of command line argument strings
70 Envp - Array of environmemt variable strings
71
72Returns:
73 0 - Normal exit
74 1 - Abnormal exit
75
76**/
65e3f333 77int
78main (
79 IN int Argc,
80 IN char **Argv,
81 IN char **Envp
82 )
949f388f 83{
84 EFI_STATUS Status;
85 EFI_PHYSICAL_ADDRESS InitialStackMemory;
86 UINT64 InitialStackMemorySize;
87 UINTN Index;
88 UINTN Index1;
89 UINTN Index2;
90 UINTN PeiIndex;
91 CHAR8 *FileName;
92 BOOLEAN Done;
65e3f333 93 EFI_PEI_FILE_HANDLE FileHandle;
94 VOID *SecFile;
949f388f 95 CHAR16 *MemorySizeStr;
96 CHAR16 *FirmwareVolumesStr;
97 UINTN *StackPointer;
98
65e3f333 99 setbuf (stdout, 0);
100 setbuf (stderr, 0);
949f388f 101
102 MemorySizeStr = (CHAR16 *) PcdGetPtr (PcdEmuMemorySize);
103 FirmwareVolumesStr = (CHAR16 *) PcdGetPtr (PcdEmuFirmwareVolume);
104
65e3f333 105 printf ("\nEDK II UNIX Emulation Environment from edk2.sourceforge.net\n");
949f388f 106
107 //
108 // PPIs pased into PEI_CORE
109 //
949f388f 110 AddThunkPpi (EFI_PEI_PPI_DESCRIPTOR_PPI, &gEmuThunkPpiGuid, &mSecEmuThunkPpi);
949f388f 111
112 SecInitThunkProtocol ();
113
114 //
115 // Emulator Bus Driver Thunks
116 //
117 AddThunkProtocol (&gX11ThunkIo, (CHAR16 *)PcdGetPtr (PcdEmuGop), TRUE);
118 AddThunkProtocol (&gPosixFileSystemThunkIo, (CHAR16 *)PcdGetPtr (PcdEmuFileSystem), TRUE);
119
120 //
121 // Emulator other Thunks
122 //
123 AddThunkProtocol (&gPthreadThunkIo, (CHAR16 *)PcdGetPtr (PcdEmuApCount), FALSE);
124
125 // EmuSecLibConstructor ();
65e3f333 126
127
128 gPpiList = GetThunkPpiList ();
129
949f388f 130
131#ifdef __APPLE__
132 //
133 // We can't use dlopen on OS X, so we need a scheme to get symboles into gdb
134 // We need to create a temp file that contains gdb commands so we can load
135 // symbols when we load every PE/COFF image.
136 //
137 Index = strlen (*Argv);
138 gGdbWorkingFileName = malloc (Index + strlen(".gdb") + 1);
139 strcpy (gGdbWorkingFileName, *Argv);
140 strcat (gGdbWorkingFileName, ".gdb");
141#endif
142
143
144 //
145 // Allocate space for gSystemMemory Array
146 //
147 gSystemMemoryCount = CountSeperatorsInString (MemorySizeStr, '!') + 1;
148 gSystemMemory = calloc (gSystemMemoryCount, sizeof (EMU_SYSTEM_MEMORY));
149 if (gSystemMemory == NULL) {
150 printf ("ERROR : Can not allocate memory for system. Exiting.\n");
151 exit (1);
152 }
153 //
154 // Allocate space for gSystemMemory Array
155 //
156 gFdInfoCount = CountSeperatorsInString (FirmwareVolumesStr, '!') + 1;
157 gFdInfo = calloc (gFdInfoCount, sizeof (EMU_FD_INFO));
158 if (gFdInfo == NULL) {
159 printf ("ERROR : Can not allocate memory for fd info. Exiting.\n");
160 exit (1);
161 }
162
163 printf (" BootMode 0x%02x\n", (unsigned int)PcdGet32 (PcdEmuBootMode));
164
165 //
65e3f333 166 // Open up a 128K file to emulate temp memory for SEC.
949f388f 167 // on a real platform this would be SRAM, or using the cache as RAM.
168 // Set InitialStackMemory to zero so UnixOpenFile will allocate a new mapping
169 //
170 InitialStackMemorySize = STACK_SIZE;
65e3f333 171 InitialStackMemory = (UINTN)MapMemory (
172 0, (UINT32) InitialStackMemorySize,
173 PROT_READ | PROT_WRITE | PROT_EXEC, MAP_ANONYMOUS | MAP_PRIVATE
174 );
949f388f 175 if (InitialStackMemory == 0) {
176 printf ("ERROR : Can not open SecStack Exiting\n");
177 exit (1);
178 }
179
65e3f333 180 printf (" OS Emulator passing in %u KB of temp RAM at 0x%08lx to SEC\n",
949f388f 181 (unsigned int)(InitialStackMemorySize / 1024),
65e3f333 182 (unsigned long)InitialStackMemory
183 );
949f388f 184
185 for (StackPointer = (UINTN*) (UINTN) InitialStackMemory;
186 StackPointer < (UINTN*)(UINTN)((UINTN) InitialStackMemory + (UINT64) InitialStackMemorySize);
187 StackPointer ++) {
188 *StackPointer = 0x5AA55AA5;
189 }
190
191 //
192 // Open All the firmware volumes and remember the info in the gFdInfo global
193 //
194 FileName = (CHAR8 *)malloc (StrLen (FirmwareVolumesStr) + 1);
195 if (FileName == NULL) {
196 printf ("ERROR : Can not allocate memory for firmware volume string\n");
197 exit (1);
198 }
199
200 Index2 = 0;
65e3f333 201 for (Done = FALSE, Index = 0, PeiIndex = 0, SecFile = NULL;
949f388f 202 FirmwareVolumesStr[Index2] != 0;
203 Index++) {
65e3f333 204 for (Index1 = 0; (FirmwareVolumesStr[Index2] != '!') && (FirmwareVolumesStr[Index2] != 0); Index2++) {
949f388f 205 FileName[Index1++] = FirmwareVolumesStr[Index2];
65e3f333 206 }
207 if (FirmwareVolumesStr[Index2] == '!') {
949f388f 208 Index2++;
65e3f333 209 }
949f388f 210 FileName[Index1] = '\0';
211
212 //
213 // Open the FD and remmeber where it got mapped into our processes address space
214 //
215 Status = MapFile (
65e3f333 216 FileName,
217 &gFdInfo[Index].Address,
218 &gFdInfo[Index].Size
219 );
949f388f 220 if (EFI_ERROR (Status)) {
221 printf ("ERROR : Can not open Firmware Device File %s (%x). Exiting.\n", FileName, (unsigned int)Status);
222 exit (1);
223 }
224
65e3f333 225 printf (" FD loaded from %s at 0x%08lx",FileName, (unsigned long)gFdInfo[Index].Address);
949f388f 226
65e3f333 227 if (SecFile == NULL) {
949f388f 228 //
65e3f333 229 // Assume the beginning of the FD is an FV and look for the SEC Core.
949f388f 230 // Load the first one we find.
231 //
65e3f333 232 FileHandle = NULL;
233 Status = PeiServicesFfsFindNextFile (
234 EFI_FV_FILETYPE_SECURITY_CORE,
235 (EFI_PEI_FV_HANDLE)(UINTN)gFdInfo[Index].Address,
236 &FileHandle
237 );
949f388f 238 if (!EFI_ERROR (Status)) {
65e3f333 239 Status = PeiServicesFfsFindSectionData (EFI_SECTION_PE32, FileHandle, &SecFile);
240 if (!EFI_ERROR (Status)) {
241 PeiIndex = Index;
242 printf (" contains SEC Core");
243 }
949f388f 244 }
245 }
246
247 printf ("\n");
248 }
249 //
250 // Calculate memory regions and store the information in the gSystemMemory
251 // global for later use. The autosizing code will use this data to
252 // map this memory into the SEC process memory space.
253 //
254 Index1 = 0;
255 Index = 0;
256 while (1) {
257 UINTN val = 0;
258 //
259 // Save the size of the memory.
260 //
261 while (MemorySizeStr[Index1] >= '0' && MemorySizeStr[Index1] <= '9') {
262 val = val * 10 + MemorySizeStr[Index1] - '0';
263 Index1++;
264 }
265 gSystemMemory[Index++].Size = val * 0x100000;
65e3f333 266 if (MemorySizeStr[Index1] == 0) {
949f388f 267 break;
65e3f333 268 }
949f388f 269 Index1++;
270 }
271
272 printf ("\n");
273
274 //
65e3f333 275 // Hand off to SEC
949f388f 276 //
65e3f333 277 SecLoadFromCore ((UINTN) InitialStackMemory, (UINTN) InitialStackMemorySize, (UINTN) gFdInfo[0].Address, SecFile);
949f388f 278
279 //
65e3f333 280 // If we get here, then the SEC Core returned. This is an error as SEC should
281 // always hand off to PEI Core and then on to DXE Core.
949f388f 282 //
65e3f333 283 printf ("ERROR : SEC returned\n");
949f388f 284 exit (1);
285}
286
65e3f333 287
949f388f 288EFI_PHYSICAL_ADDRESS *
289MapMemory (
290 INTN fd,
291 UINT64 length,
292 INTN prot,
293 INTN flags)
294{
295 STATIC UINTN base = 0x40000000;
296 CONST UINTN align = (1 << 24);
297 VOID *res = NULL;
298 BOOLEAN isAligned = 0;
299
300 //
301 // Try to get an aligned block somewhere in the address space of this
302 // process.
303 //
304 while((!isAligned) && (base != 0)) {
305 res = mmap ((void *)base, length, prot, flags, fd, 0);
306 if (res == MAP_FAILED) {
307 return NULL;
308 }
309 if ((((UINTN)res) & ~(align-1)) == (UINTN)res) {
310 isAligned=1;
65e3f333 311 } else {
949f388f 312 munmap(res, length);
313 base += align;
314 }
315 }
316 return res;
317}
318
65e3f333 319
949f388f 320/*++
321
322Routine Description:
323 Opens and memory maps a file using Unix services. If BaseAddress is non zero
324 the process will try and allocate the memory starting at BaseAddress.
325
326Arguments:
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
337Returns:
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**/
65e3f333 343EFI_STATUS
344MapFile (
345 IN CHAR8 *FileName,
346 IN OUT EFI_PHYSICAL_ADDRESS *BaseAddress,
347 OUT UINT64 *Length
348 )
949f388f 349{
350 int fd;
351 VOID *res;
352 UINTN FileSize;
353
354 fd = open (FileName, O_RDONLY);
65e3f333 355 if (fd < 0) {
949f388f 356 return EFI_NOT_FOUND;
65e3f333 357 }
949f388f 358 FileSize = lseek (fd, 0, SEEK_END);
359
360
65e3f333 361 res = MapMemory (fd, FileSize, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE);
949f388f 362
363 close (fd);
364
65e3f333 365 if (res == MAP_FAILED) {
949f388f 366 return EFI_DEVICE_ERROR;
65e3f333 367 }
368
949f388f 369 *Length = (UINT64) FileSize;
370 *BaseAddress = (EFI_PHYSICAL_ADDRESS) (UINTN) res;
371
372 return EFI_SUCCESS;
373}
374
375
376
949f388f 377/*++
378
379Routine Description:
65e3f333 380 This is the service to load the SEC Core from the Firmware Volume
949f388f 381
382Arguments:
65e3f333 383 LargestRegion - Memory to use for SEC.
949f388f 384 LargestRegionSize - Size of Memory to use for PEI
385 BootFirmwareVolumeBase - Start of the Boot FV
65e3f333 386 PeiCorePe32File - SEC PE32
949f388f 387
388Returns:
389 Success means control is transfered and thus we should never return
390
391**/
65e3f333 392VOID
393SecLoadFromCore (
394 IN UINTN LargestRegion,
395 IN UINTN LargestRegionSize,
396 IN UINTN BootFirmwareVolumeBase,
397 IN VOID *PeiCorePe32File
398 )
949f388f 399{
400 EFI_STATUS Status;
401 EFI_PHYSICAL_ADDRESS TopOfMemory;
402 VOID *TopOfStack;
949f388f 403 EFI_PHYSICAL_ADDRESS PeiCoreEntryPoint;
949f388f 404 EFI_SEC_PEI_HAND_OFF *SecCoreData;
405 UINTN PeiStackSize;
406
407 //
408 // Compute Top Of Memory for Stack and PEI Core Allocations
409 //
410 TopOfMemory = LargestRegion + LargestRegionSize;
411 PeiStackSize = (UINTN)RShiftU64((UINT64)STACK_SIZE,1);
412
413 //
414 // |-----------| <---- TemporaryRamBase + TemporaryRamSize
415 // | Heap |
416 // | |
417 // |-----------| <---- StackBase / PeiTemporaryMemoryBase
418 // | |
419 // | Stack |
420 // |-----------| <---- TemporaryRamBase
421 //
422 TopOfStack = (VOID *)(LargestRegion + PeiStackSize);
423 TopOfMemory = LargestRegion + PeiStackSize;
424
425 //
426 // Reservet space for storing PeiCore's parament in stack.
427 //
428 TopOfStack = (VOID *)((UINTN)TopOfStack - sizeof (EFI_SEC_PEI_HAND_OFF) - CPU_STACK_ALIGNMENT);
429 TopOfStack = ALIGN_POINTER (TopOfStack, CPU_STACK_ALIGNMENT);
430
431
432 //
433 // Bind this information into the SEC hand-off state
434 //
65e3f333 435 SecCoreData = (EFI_SEC_PEI_HAND_OFF*)(UINTN) TopOfStack;
949f388f 436 SecCoreData->DataSize = sizeof(EFI_SEC_PEI_HAND_OFF);
437 SecCoreData->BootFirmwareVolumeBase = (VOID*)BootFirmwareVolumeBase;
438 SecCoreData->BootFirmwareVolumeSize = PcdGet32 (PcdEmuFirmwareFdSize);
439 SecCoreData->TemporaryRamBase = (VOID*)(UINTN)LargestRegion;
440 SecCoreData->TemporaryRamSize = STACK_SIZE;
441 SecCoreData->StackBase = SecCoreData->TemporaryRamBase;
442 SecCoreData->StackSize = PeiStackSize;
443 SecCoreData->PeiTemporaryRamBase = (VOID*) ((UINTN) SecCoreData->TemporaryRamBase + PeiStackSize);
444 SecCoreData->PeiTemporaryRamSize = STACK_SIZE - PeiStackSize;
445
446 //
65e3f333 447 // Find the SEC Core Entry Point
949f388f 448 //
65e3f333 449 Status = SecPeCoffGetEntryPoint (PeiCorePe32File, (VOID **)&PeiCoreEntryPoint);
949f388f 450 if (EFI_ERROR (Status)) {
451 return ;
452 }
453
454 //
65e3f333 455 // Transfer control to the SEC Core
949f388f 456 //
457 PeiSwitchStacks (
458 (SWITCH_STACK_ENTRY_POINT) (UINTN) PeiCoreEntryPoint,
459 SecCoreData,
65e3f333 460 (VOID *)gPpiList,
949f388f 461 TopOfStack
462 );
463 //
65e3f333 464 // If we get here, then the SEC Core returned. This is an error
949f388f 465 //
466 return ;
467}
468
65e3f333 469
949f388f 470/*++
471
472Routine Description:
473 This service is called from Index == 0 until it returns EFI_UNSUPPORTED.
474 It allows discontiguous memory regions to be supported by the emulator.
475 It uses gSystemMemory[] and gSystemMemoryCount that were created by
476 parsing the host environment variable EFI_MEMORY_SIZE.
477 The size comes from the varaible and the address comes from the call to
478 UnixOpenFile.
479
480Arguments:
481 Index - Which memory region to use
482 MemoryBase - Return Base address of memory region
483 MemorySize - Return size in bytes of the memory region
484
485Returns:
486 EFI_SUCCESS - If memory region was mapped
487 EFI_UNSUPPORTED - If Index is not supported
488
489**/
65e3f333 490EFI_STATUS
491EFIAPI
492SecUnixPeiAutoScan (
493 IN UINTN Index,
494 OUT EFI_PHYSICAL_ADDRESS *MemoryBase,
495 OUT UINT64 *MemorySize
496 )
949f388f 497{
498 void *res;
499
500 if (Index >= gSystemMemoryCount) {
501 return EFI_UNSUPPORTED;
502 }
503
504 *MemoryBase = 0;
65e3f333 505 res = MapMemory (
506 0, gSystemMemory[Index].Size,
507 PROT_READ | PROT_WRITE | PROT_EXEC,
508 MAP_PRIVATE | MAP_ANONYMOUS
509 );
510 if (res == MAP_FAILED) {
949f388f 511 return EFI_DEVICE_ERROR;
65e3f333 512 }
949f388f 513 *MemorySize = gSystemMemory[Index].Size;
514 *MemoryBase = (UINTN)res;
515 gSystemMemory[Index].Memory = *MemoryBase;
516
517 return EFI_SUCCESS;
518}
519
65e3f333 520
949f388f 521/*++
522
523Routine Description:
524 Since the SEC is the only Unix program in stack it must export
525 an interface to do POSIX calls. gUnix is initailized in UnixThunk.c.
526
527Arguments:
528 InterfaceSize - sizeof (EFI_WIN_NT_THUNK_PROTOCOL);
529 InterfaceBase - Address of the gUnix global
530
531Returns:
532 EFI_SUCCESS - Data returned
533
534**/
65e3f333 535VOID *
536EFIAPI
537SecEmuThunkAddress (
538 VOID
539 )
949f388f 540{
541 return &gEmuThunkProtocol;
542}
543
544
949f388f 545
546RETURN_STATUS
547EFIAPI
548SecPeCoffGetEntryPoint (
549 IN VOID *Pe32Data,
550 IN OUT VOID **EntryPoint
551 )
552{
65e3f333 553 EFI_STATUS Status;
554 PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;
0ede3853 555
556 ZeroMem (&ImageContext, sizeof (ImageContext));
557 ImageContext.Handle = Pe32Data;
558 ImageContext.ImageRead = (PE_COFF_LOADER_READ_FILE) SecImageRead;
559
560 Status = PeCoffLoaderGetImageInfo (&ImageContext);
561 if (EFI_ERROR (Status)) {
562 return Status;
563 }
564
565 //
566 // Relocate image to match the address where it resides
567 //
8f0067d7 568 ImageContext.ImageAddress = (UINTN)Pe32Data;
0ede3853 569 Status = PeCoffLoaderLoadImage (&ImageContext);
570 if (EFI_ERROR (Status)) {
65e3f333 571 return Status;
572 }
949f388f 573
0ede3853 574 Status = PeCoffLoaderRelocateImage (&ImageContext);
575 if (EFI_ERROR (Status)) {
576 return Status;
577 }
949f388f 578
65e3f333 579 // On Unix a dlopen is done that will change the entry point
580 SecPeCoffRelocateImageExtraAction (&ImageContext);
581 *EntryPoint = (VOID *)(UINTN)ImageContext.EntryPoint;
582
949f388f 583 return Status;
584}
585
586
587
949f388f 588/*++
589
590Routine Description:
591 Return the FD Size and base address. Since the FD is loaded from a
592 file into host memory only the SEC will know it's address.
593
594Arguments:
595 Index - Which FD, starts at zero.
596 FdSize - Size of the FD in bytes
597 FdBase - Start address of the FD. Assume it points to an FV Header
598 FixUp - Difference between actual FD address and build address
599
600Returns:
601 EFI_SUCCESS - Return the Base address and size of the FV
602 EFI_UNSUPPORTED - Index does nto map to an FD in the system
603
604**/
65e3f333 605EFI_STATUS
606EFIAPI
607SecUnixFdAddress (
608 IN UINTN Index,
609 IN OUT EFI_PHYSICAL_ADDRESS *FdBase,
610 IN OUT UINT64 *FdSize,
611 IN OUT EFI_PHYSICAL_ADDRESS *FixUp
612 )
949f388f 613{
614 if (Index >= gFdInfoCount) {
615 return EFI_UNSUPPORTED;
616 }
617
618 *FdBase = gFdInfo[Index].Address;
619 *FdSize = gFdInfo[Index].Size;
620 *FixUp = 0;
621
622 if (*FdBase == 0 && *FdSize == 0) {
623 return EFI_UNSUPPORTED;
624 }
625
626 if (Index == 0) {
627 //
628 // FD 0 has XIP code and well known PCD values
629 // If the memory buffer could not be allocated at the FD build address
630 // the Fixup is the difference.
631 //
632 *FixUp = *FdBase - PcdGet64 (PcdEmuFdBaseAddress);
633 }
634
635 return EFI_SUCCESS;
636}
637
949f388f 638
949f388f 639/*++
640
641Routine Description:
642 Count the number of seperators in String
643
644Arguments:
645 String - String to process
646 Seperator - Item to count
647
648Returns:
649 Number of Seperator in String
650
651**/
65e3f333 652UINTN
653CountSeperatorsInString (
654 IN const CHAR16 *String,
655 IN CHAR16 Seperator
656 )
949f388f 657{
658 UINTN Count;
659
660 for (Count = 0; *String != '\0'; String++) {
661 if (*String == Seperator) {
662 Count++;
663 }
664 }
665
666 return Count;
667}
668
669
0ede3853 670EFI_STATUS
671EFIAPI
672SecImageRead (
673 IN VOID *FileHandle,
674 IN UINTN FileOffset,
675 IN OUT UINTN *ReadSize,
676 OUT VOID *Buffer
677 )
678/*++
679
680Routine Description:
681 Support routine for the PE/COFF Loader that reads a buffer from a PE/COFF file
682
683Arguments:
684 FileHandle - The handle to the PE/COFF file
685 FileOffset - The offset, in bytes, into the file to read
686 ReadSize - The number of bytes to read from the file starting at FileOffset
687 Buffer - A pointer to the buffer to read the data into.
688
689Returns:
690 EFI_SUCCESS - ReadSize bytes of data were read into Buffer from the PE/COFF file starting at FileOffset
691
692**/
693{
694 CHAR8 *Destination8;
695 CHAR8 *Source8;
696 UINTN Length;
697
698 Destination8 = Buffer;
699 Source8 = (CHAR8 *) ((UINTN) FileHandle + FileOffset);
700 Length = *ReadSize;
701 while (Length--) {
702 *(Destination8++) = *(Source8++);
703 }
704
705 return EFI_SUCCESS;
706}
707
708
949f388f 709/*++
710
711Routine Description:
712 Store the ModHandle in an array indexed by the Pdb File name.
713 The ModHandle is needed to unload the image.
714
715Arguments:
716 ImageContext - Input data returned from PE Laoder Library. Used to find the
717 .PDB file name of the PE Image.
718 ModHandle - Returned from LoadLibraryEx() and stored for call to
719 FreeLibrary().
720
721Returns:
722 EFI_SUCCESS - ModHandle was stored.
723
724**/
65e3f333 725EFI_STATUS
726AddHandle (
727 IN PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext,
728 IN VOID *ModHandle
729 )
949f388f 730{
731 UINTN Index;
732 IMAGE_CONTEXT_TO_MOD_HANDLE *Array;
733 UINTN PreviousSize;
734
735
736 Array = mImageContextModHandleArray;
737 for (Index = 0; Index < mImageContextModHandleArraySize; Index++, Array++) {
738 if (Array->ImageContext == NULL) {
739 //
740 // Make a copy of the stirng and store the ModHandle
741 //
742 Array->ImageContext = ImageContext;
743 Array->ModHandle = ModHandle;
744 return EFI_SUCCESS;
745 }
746 }
747
748 //
749 // No free space in mImageContextModHandleArray so grow it by
750 // IMAGE_CONTEXT_TO_MOD_HANDLE entires. realloc will
751 // copy the old values to the new locaiton. But it does
752 // not zero the new memory area.
753 //
754 PreviousSize = mImageContextModHandleArraySize * sizeof (IMAGE_CONTEXT_TO_MOD_HANDLE);
755 mImageContextModHandleArraySize += MAX_IMAGE_CONTEXT_TO_MOD_HANDLE_ARRAY_SIZE;
756
757 mImageContextModHandleArray = realloc (mImageContextModHandleArray, mImageContextModHandleArraySize * sizeof (IMAGE_CONTEXT_TO_MOD_HANDLE));
758 if (mImageContextModHandleArray == NULL) {
759 ASSERT (FALSE);
760 return EFI_OUT_OF_RESOURCES;
761 }
762
763 memset (mImageContextModHandleArray + PreviousSize, 0, MAX_IMAGE_CONTEXT_TO_MOD_HANDLE_ARRAY_SIZE * sizeof (IMAGE_CONTEXT_TO_MOD_HANDLE));
764
765 return AddHandle (ImageContext, ModHandle);
766}
767
768
949f388f 769/*++
770
771Routine Description:
772 Return the ModHandle and delete the entry in the array.
773
774Arguments:
775 ImageContext - Input data returned from PE Laoder Library. Used to find the
776 .PDB file name of the PE Image.
777
778Returns:
779 ModHandle - ModHandle assoicated with ImageContext is returned
780 NULL - No ModHandle associated with ImageContext
781
782**/
65e3f333 783VOID *
784RemoveHandle (
785 IN PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
786 )
949f388f 787{
788 UINTN Index;
789 IMAGE_CONTEXT_TO_MOD_HANDLE *Array;
790
791 if (ImageContext->PdbPointer == NULL) {
792 //
793 // If no PDB pointer there is no ModHandle so return NULL
794 //
795 return NULL;
796 }
797
798 Array = mImageContextModHandleArray;
799 for (Index = 0; Index < mImageContextModHandleArraySize; Index++, Array++) {
800 if (Array->ImageContext == ImageContext) {
801 //
802 // If you find a match return it and delete the entry
803 //
804 Array->ImageContext = NULL;
805 return Array->ModHandle;
806 }
807 }
808
809 return NULL;
810}
811
812
813
814//
815// Target for gdb breakpoint in a script that uses gGdbWorkingFileName to source a
816// add-symbol-file command. Hey what can you say scripting in gdb is not that great....
817//
818// Put .gdbinit in the CWD where you do gdb SecMain.dll for source level debug
819//
820// cat .gdbinit
821// b SecGdbScriptBreak
822// command
823// silent
65e3f333 824// source SecMain.gdb
949f388f 825// c
826// end
827//
828VOID
829SecGdbScriptBreak (
830 VOID
831 )
832{
833}
834
835VOID
836SecUnixLoaderBreak (
837 VOID
838 )
839{
840}
841
842BOOLEAN
843IsPdbFile (
844 IN CHAR8 *PdbFileName
845 )
846{
847 UINTN Len;
848
849 if (PdbFileName == NULL) {
850 return FALSE;
851 }
852
853 Len = strlen (PdbFileName);
854 if ((Len < 5)|| (PdbFileName[Len - 4] != '.')) {
855 return FALSE;
856 }
857
858 if ((PdbFileName[Len - 3] == 'P' || PdbFileName[Len - 3] == 'p') &&
859 (PdbFileName[Len - 2] == 'D' || PdbFileName[Len - 2] == 'd') &&
860 (PdbFileName[Len - 1] == 'B' || PdbFileName[Len - 1] == 'b')) {
861 return TRUE;
862 }
863
864 return FALSE;
865}
866
867
868#define MAX_SPRINT_BUFFER_SIZE 0x200
869
870void
871PrintLoadAddress (
872 IN PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
873 )
874{
875 if (ImageContext->PdbPointer == NULL) {
876 fprintf (stderr,
877 "0x%08lx Loading NO DEBUG with entry point 0x%08lx\n",
878 (unsigned long)(ImageContext->ImageAddress),
879 (unsigned long)ImageContext->EntryPoint
880 );
881 } else {
882 fprintf (stderr,
883 "0x%08lx Loading %s with entry point 0x%08lx\n",
884 (unsigned long)(ImageContext->ImageAddress + ImageContext->SizeOfHeaders),
885 ImageContext->PdbPointer,
886 (unsigned long)ImageContext->EntryPoint
887 );
888 }
889 // Keep output synced up
890 fflush (stderr);
891}
892
893
894VOID
895EFIAPI
896SecPeCoffRelocateImageExtraAction (
897 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
898 )
899{
900
901#ifdef __APPLE__
902 BOOLEAN EnabledOnEntry;
903
904 //
905 // Make sure writting of the file is an atomic operation
906 //
907 if (SecInterruptEanbled ()) {
908 SecDisableInterrupt ();
909 EnabledOnEntry = TRUE;
910 } else {
911 EnabledOnEntry = FALSE;
912 }
913
914 PrintLoadAddress (ImageContext);
915
916 //
917 // In mach-o (OS X executable) dlopen() can only load files in the MH_DYLIB of MH_BUNDLE format.
918 // To convert to PE/COFF we need to construct a mach-o with the MH_PRELOAD format. We create
919 // .dSYM files for the PE/COFF images that can be used by gdb for source level debugging.
920 //
921 FILE *GdbTempFile;
922
923 //
924 // In the Mach-O to PE/COFF conversion the size of the PE/COFF headers is not accounted for.
925 // Thus we need to skip over the PE/COFF header when giving load addresses for our symbol table.
926 //
927 if (ImageContext->PdbPointer != NULL && !IsPdbFile (ImageContext->PdbPointer)) {
928 //
929 // Now we have a database of the images that are currently loaded
930 //
931
932 //
933 // 'symbol-file' will clear out currnet symbol mappings in gdb.
934 // you can do a 'add-symbol-file filename address' for every image we loaded to get source
935 // level debug in gdb. Note Sec, being a true application will work differently.
936 //
937 // We add the PE/COFF header size into the image as the mach-O does not have a header in
938 // loaded into system memory.
939 //
940 // This gives us a data base of gdb commands and after something is unloaded that entry will be
941 // removed. We don't yet have the scheme of how to comunicate with gdb, but we have the
942 // data base of info ready to roll.
943 //
944 // We could use qXfer:libraries:read, but OS X GDB does not currently support it.
945 // <library-list>
946 // <library name="/lib/libc.so.6"> // ImageContext->PdbPointer
947 // <segment address="0x10000000"/> // ImageContext->ImageAddress + ImageContext->SizeOfHeaders
948 // </library>
949 // </library-list>
950 //
951
952 //
953 // Write the file we need for the gdb script
954 //
955 GdbTempFile = fopen (gGdbWorkingFileName, "w");
956 if (GdbTempFile != NULL) {
957 fprintf (GdbTempFile, "add-symbol-file %s 0x%08lx\n", ImageContext->PdbPointer, (long unsigned int)(ImageContext->ImageAddress + ImageContext->SizeOfHeaders));
958 fclose (GdbTempFile);
959
960 //
961 // Target for gdb breakpoint in a script that uses gGdbWorkingFileName to set a breakpoint.
962 // Hey what can you say scripting in gdb is not that great....
963 //
964 SecGdbScriptBreak ();
965 } else {
966 ASSERT (FALSE);
967 }
968
969 AddHandle (ImageContext, ImageContext->PdbPointer);
970
971 if (EnabledOnEntry) {
972 SecEnableInterrupt ();
973 }
974
975
976 }
977
978#else
979
980 void *Handle = NULL;
981 void *Entry = NULL;
982
983 if (ImageContext->PdbPointer == NULL) {
984 return;
985 }
986
987 if (!IsPdbFile (ImageContext->PdbPointer)) {
988 return;
989 }
990
65e3f333 991 fprintf (
992 stderr,
949f388f 993 "Loading %s 0x%08lx - entry point 0x%08lx\n",
994 ImageContext->PdbPointer,
995 (unsigned long)ImageContext->ImageAddress,
65e3f333 996 (unsigned long)ImageContext->EntryPoint
997 );
949f388f 998
999 Handle = dlopen (ImageContext->PdbPointer, RTLD_NOW);
1000
1001 if (Handle) {
1002 Entry = dlsym (Handle, "_ModuleEntryPoint");
1003 } else {
1004 printf("%s\n", dlerror());
1005 }
1006
1007 if (Entry != NULL) {
1008 ImageContext->EntryPoint = (UINTN)Entry;
65e3f333 1009 printf ("Change %s Entrypoint to :0x%08lx\n", ImageContext->PdbPointer, (unsigned long)Entry);
949f388f 1010 }
1011
1012 SecUnixLoaderBreak ();
1013
1014#endif
1015
1016 return;
1017}
1018
1019
1020VOID
1021EFIAPI
1022SecPeCoffUnloadImageExtraAction (
1023 IN PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
1024 )
1025{
1026 VOID *Handle;
1027
1028 Handle = RemoveHandle (ImageContext);
1029
1030#ifdef __APPLE__
1031 FILE *GdbTempFile;
1032 BOOLEAN EnabledOnEntry;
1033
1034 if (Handle != NULL) {
1035 //
1036 // Need to skip .PDB files created from VC++
1037 //
1038 if (!IsPdbFile (ImageContext->PdbPointer)) {
1039 if (SecInterruptEanbled ()) {
1040 SecDisableInterrupt ();
1041 EnabledOnEntry = TRUE;
1042 } else {
1043 EnabledOnEntry = FALSE;
1044 }
1045
1046 //
1047 // Write the file we need for the gdb script
1048 //
1049 GdbTempFile = fopen (gGdbWorkingFileName, "w");
1050 if (GdbTempFile != NULL) {
1051 fprintf (GdbTempFile, "remove-symbol-file %s\n", ImageContext->PdbPointer);
1052 fclose (GdbTempFile);
1053
1054 //
1055 // Target for gdb breakpoint in a script that uses gGdbWorkingFileName to set a breakpoint.
1056 // Hey what can you say scripting in gdb is not that great....
1057 //
1058 SecGdbScriptBreak ();
1059 } else {
1060 ASSERT (FALSE);
1061 }
1062
1063 if (EnabledOnEntry) {
1064 SecEnableInterrupt ();
1065 }
1066 }
1067 }
1068
1069#else
1070 //
1071 // Don't want to confuse gdb with symbols for something that got unloaded
1072 //
1073 if (Handle != NULL) {
1074 dlclose (Handle);
1075 }
1076
1077#endif
1078 return;
1079}
1080
1081