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