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