]> git.proxmox.com Git - mirror_edk2.git/blame - InOsEmuPkg/Unix/Sec/SecMain.c
Added generic EFIABI SEC to InOsEmuPkg. Add library to abstract FV cracking and remov...
[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 NULL,
462 TopOfStack
463 );
464 //
65e3f333 465 // If we get here, then the SEC Core returned. This is an error
949f388f 466 //
467 return ;
468}
469
65e3f333 470
949f388f 471/*++
472
473Routine 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
481Arguments:
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
486Returns:
487 EFI_SUCCESS - If memory region was mapped
488 EFI_UNSUPPORTED - If Index is not supported
489
490**/
65e3f333 491EFI_STATUS
492EFIAPI
493SecUnixPeiAutoScan (
494 IN UINTN Index,
495 OUT EFI_PHYSICAL_ADDRESS *MemoryBase,
496 OUT UINT64 *MemorySize
497 )
949f388f 498{
499 void *res;
500
501 if (Index >= gSystemMemoryCount) {
502 return EFI_UNSUPPORTED;
503 }
504
505 *MemoryBase = 0;
65e3f333 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) {
949f388f 512 return EFI_DEVICE_ERROR;
65e3f333 513 }
949f388f 514 *MemorySize = gSystemMemory[Index].Size;
515 *MemoryBase = (UINTN)res;
516 gSystemMemory[Index].Memory = *MemoryBase;
517
518 return EFI_SUCCESS;
519}
520
65e3f333 521
949f388f 522/*++
523
524Routine 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
528Arguments:
529 InterfaceSize - sizeof (EFI_WIN_NT_THUNK_PROTOCOL);
530 InterfaceBase - Address of the gUnix global
531
532Returns:
533 EFI_SUCCESS - Data returned
534
535**/
65e3f333 536VOID *
537EFIAPI
538SecEmuThunkAddress (
539 VOID
540 )
949f388f 541{
542 return &gEmuThunkProtocol;
543}
544
545
949f388f 546
547RETURN_STATUS
548EFIAPI
549SecPeCoffGetEntryPoint (
550 IN VOID *Pe32Data,
551 IN OUT VOID **EntryPoint
552 )
553{
65e3f333 554 EFI_STATUS Status;
555 PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;
556
557 ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)Pe32Data;
558 ImageContext.SizeOfHeaders = PeCoffGetSizeOfHeaders (Pe32Data);
559 ImageContext.PdbPointer = PeCoffLoaderGetPdbPointer (Pe32Data);
560 Status = PeCoffLoaderGetEntryPoint (Pe32Data, EntryPoint);
561 if (!EFI_ERROR (Status)) {
562 return Status;
563 }
949f388f 564
65e3f333 565 ImageContext.EntryPoint = (UINTN)EntryPoint;
949f388f 566
65e3f333 567 // On Unix a dlopen is done that will change the entry point
568 SecPeCoffRelocateImageExtraAction (&ImageContext);
569 *EntryPoint = (VOID *)(UINTN)ImageContext.EntryPoint;
570
949f388f 571 return Status;
572}
573
574
575
949f388f 576/*++
577
578Routine Description:
579 Return the FD Size and base address. Since the FD is loaded from a
580 file into host memory only the SEC will know it's address.
581
582Arguments:
583 Index - Which FD, starts at zero.
584 FdSize - Size of the FD in bytes
585 FdBase - Start address of the FD. Assume it points to an FV Header
586 FixUp - Difference between actual FD address and build address
587
588Returns:
589 EFI_SUCCESS - Return the Base address and size of the FV
590 EFI_UNSUPPORTED - Index does nto map to an FD in the system
591
592**/
65e3f333 593EFI_STATUS
594EFIAPI
595SecUnixFdAddress (
596 IN UINTN Index,
597 IN OUT EFI_PHYSICAL_ADDRESS *FdBase,
598 IN OUT UINT64 *FdSize,
599 IN OUT EFI_PHYSICAL_ADDRESS *FixUp
600 )
949f388f 601{
602 if (Index >= gFdInfoCount) {
603 return EFI_UNSUPPORTED;
604 }
605
606 *FdBase = gFdInfo[Index].Address;
607 *FdSize = gFdInfo[Index].Size;
608 *FixUp = 0;
609
610 if (*FdBase == 0 && *FdSize == 0) {
611 return EFI_UNSUPPORTED;
612 }
613
614 if (Index == 0) {
615 //
616 // FD 0 has XIP code and well known PCD values
617 // If the memory buffer could not be allocated at the FD build address
618 // the Fixup is the difference.
619 //
620 *FixUp = *FdBase - PcdGet64 (PcdEmuFdBaseAddress);
621 }
622
623 return EFI_SUCCESS;
624}
625
949f388f 626
949f388f 627/*++
628
629Routine Description:
630 Count the number of seperators in String
631
632Arguments:
633 String - String to process
634 Seperator - Item to count
635
636Returns:
637 Number of Seperator in String
638
639**/
65e3f333 640UINTN
641CountSeperatorsInString (
642 IN const CHAR16 *String,
643 IN CHAR16 Seperator
644 )
949f388f 645{
646 UINTN Count;
647
648 for (Count = 0; *String != '\0'; String++) {
649 if (*String == Seperator) {
650 Count++;
651 }
652 }
653
654 return Count;
655}
656
657
949f388f 658/*++
659
660Routine Description:
661 Store the ModHandle in an array indexed by the Pdb File name.
662 The ModHandle is needed to unload the image.
663
664Arguments:
665 ImageContext - Input data returned from PE Laoder Library. Used to find the
666 .PDB file name of the PE Image.
667 ModHandle - Returned from LoadLibraryEx() and stored for call to
668 FreeLibrary().
669
670Returns:
671 EFI_SUCCESS - ModHandle was stored.
672
673**/
65e3f333 674EFI_STATUS
675AddHandle (
676 IN PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext,
677 IN VOID *ModHandle
678 )
949f388f 679{
680 UINTN Index;
681 IMAGE_CONTEXT_TO_MOD_HANDLE *Array;
682 UINTN PreviousSize;
683
684
685 Array = mImageContextModHandleArray;
686 for (Index = 0; Index < mImageContextModHandleArraySize; Index++, Array++) {
687 if (Array->ImageContext == NULL) {
688 //
689 // Make a copy of the stirng and store the ModHandle
690 //
691 Array->ImageContext = ImageContext;
692 Array->ModHandle = ModHandle;
693 return EFI_SUCCESS;
694 }
695 }
696
697 //
698 // No free space in mImageContextModHandleArray so grow it by
699 // IMAGE_CONTEXT_TO_MOD_HANDLE entires. realloc will
700 // copy the old values to the new locaiton. But it does
701 // not zero the new memory area.
702 //
703 PreviousSize = mImageContextModHandleArraySize * sizeof (IMAGE_CONTEXT_TO_MOD_HANDLE);
704 mImageContextModHandleArraySize += MAX_IMAGE_CONTEXT_TO_MOD_HANDLE_ARRAY_SIZE;
705
706 mImageContextModHandleArray = realloc (mImageContextModHandleArray, mImageContextModHandleArraySize * sizeof (IMAGE_CONTEXT_TO_MOD_HANDLE));
707 if (mImageContextModHandleArray == NULL) {
708 ASSERT (FALSE);
709 return EFI_OUT_OF_RESOURCES;
710 }
711
712 memset (mImageContextModHandleArray + PreviousSize, 0, MAX_IMAGE_CONTEXT_TO_MOD_HANDLE_ARRAY_SIZE * sizeof (IMAGE_CONTEXT_TO_MOD_HANDLE));
713
714 return AddHandle (ImageContext, ModHandle);
715}
716
717
949f388f 718/*++
719
720Routine Description:
721 Return the ModHandle and delete the entry in the array.
722
723Arguments:
724 ImageContext - Input data returned from PE Laoder Library. Used to find the
725 .PDB file name of the PE Image.
726
727Returns:
728 ModHandle - ModHandle assoicated with ImageContext is returned
729 NULL - No ModHandle associated with ImageContext
730
731**/
65e3f333 732VOID *
733RemoveHandle (
734 IN PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
735 )
949f388f 736{
737 UINTN Index;
738 IMAGE_CONTEXT_TO_MOD_HANDLE *Array;
739
740 if (ImageContext->PdbPointer == NULL) {
741 //
742 // If no PDB pointer there is no ModHandle so return NULL
743 //
744 return NULL;
745 }
746
747 Array = mImageContextModHandleArray;
748 for (Index = 0; Index < mImageContextModHandleArraySize; Index++, Array++) {
749 if (Array->ImageContext == ImageContext) {
750 //
751 // If you find a match return it and delete the entry
752 //
753 Array->ImageContext = NULL;
754 return Array->ModHandle;
755 }
756 }
757
758 return NULL;
759}
760
761
762
763//
764// Target for gdb breakpoint in a script that uses gGdbWorkingFileName to source a
765// add-symbol-file command. Hey what can you say scripting in gdb is not that great....
766//
767// Put .gdbinit in the CWD where you do gdb SecMain.dll for source level debug
768//
769// cat .gdbinit
770// b SecGdbScriptBreak
771// command
772// silent
65e3f333 773// source SecMain.gdb
949f388f 774// c
775// end
776//
777VOID
778SecGdbScriptBreak (
779 VOID
780 )
781{
782}
783
784VOID
785SecUnixLoaderBreak (
786 VOID
787 )
788{
789}
790
791BOOLEAN
792IsPdbFile (
793 IN CHAR8 *PdbFileName
794 )
795{
796 UINTN Len;
797
798 if (PdbFileName == NULL) {
799 return FALSE;
800 }
801
802 Len = strlen (PdbFileName);
803 if ((Len < 5)|| (PdbFileName[Len - 4] != '.')) {
804 return FALSE;
805 }
806
807 if ((PdbFileName[Len - 3] == 'P' || PdbFileName[Len - 3] == 'p') &&
808 (PdbFileName[Len - 2] == 'D' || PdbFileName[Len - 2] == 'd') &&
809 (PdbFileName[Len - 1] == 'B' || PdbFileName[Len - 1] == 'b')) {
810 return TRUE;
811 }
812
813 return FALSE;
814}
815
816
817#define MAX_SPRINT_BUFFER_SIZE 0x200
818
819void
820PrintLoadAddress (
821 IN PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
822 )
823{
824 if (ImageContext->PdbPointer == NULL) {
825 fprintf (stderr,
826 "0x%08lx Loading NO DEBUG with entry point 0x%08lx\n",
827 (unsigned long)(ImageContext->ImageAddress),
828 (unsigned long)ImageContext->EntryPoint
829 );
830 } else {
831 fprintf (stderr,
832 "0x%08lx Loading %s with entry point 0x%08lx\n",
833 (unsigned long)(ImageContext->ImageAddress + ImageContext->SizeOfHeaders),
834 ImageContext->PdbPointer,
835 (unsigned long)ImageContext->EntryPoint
836 );
837 }
838 // Keep output synced up
839 fflush (stderr);
840}
841
842
843VOID
844EFIAPI
845SecPeCoffRelocateImageExtraAction (
846 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
847 )
848{
849
850#ifdef __APPLE__
851 BOOLEAN EnabledOnEntry;
852
853 //
854 // Make sure writting of the file is an atomic operation
855 //
856 if (SecInterruptEanbled ()) {
857 SecDisableInterrupt ();
858 EnabledOnEntry = TRUE;
859 } else {
860 EnabledOnEntry = FALSE;
861 }
862
863 PrintLoadAddress (ImageContext);
864
865 //
866 // In mach-o (OS X executable) dlopen() can only load files in the MH_DYLIB of MH_BUNDLE format.
867 // To convert to PE/COFF we need to construct a mach-o with the MH_PRELOAD format. We create
868 // .dSYM files for the PE/COFF images that can be used by gdb for source level debugging.
869 //
870 FILE *GdbTempFile;
871
872 //
873 // In the Mach-O to PE/COFF conversion the size of the PE/COFF headers is not accounted for.
874 // Thus we need to skip over the PE/COFF header when giving load addresses for our symbol table.
875 //
876 if (ImageContext->PdbPointer != NULL && !IsPdbFile (ImageContext->PdbPointer)) {
877 //
878 // Now we have a database of the images that are currently loaded
879 //
880
881 //
882 // 'symbol-file' will clear out currnet symbol mappings in gdb.
883 // you can do a 'add-symbol-file filename address' for every image we loaded to get source
884 // level debug in gdb. Note Sec, being a true application will work differently.
885 //
886 // We add the PE/COFF header size into the image as the mach-O does not have a header in
887 // loaded into system memory.
888 //
889 // This gives us a data base of gdb commands and after something is unloaded that entry will be
890 // removed. We don't yet have the scheme of how to comunicate with gdb, but we have the
891 // data base of info ready to roll.
892 //
893 // We could use qXfer:libraries:read, but OS X GDB does not currently support it.
894 // <library-list>
895 // <library name="/lib/libc.so.6"> // ImageContext->PdbPointer
896 // <segment address="0x10000000"/> // ImageContext->ImageAddress + ImageContext->SizeOfHeaders
897 // </library>
898 // </library-list>
899 //
900
901 //
902 // Write the file we need for the gdb script
903 //
904 GdbTempFile = fopen (gGdbWorkingFileName, "w");
905 if (GdbTempFile != NULL) {
906 fprintf (GdbTempFile, "add-symbol-file %s 0x%08lx\n", ImageContext->PdbPointer, (long unsigned int)(ImageContext->ImageAddress + ImageContext->SizeOfHeaders));
907 fclose (GdbTempFile);
908
909 //
910 // Target for gdb breakpoint in a script that uses gGdbWorkingFileName to set a breakpoint.
911 // Hey what can you say scripting in gdb is not that great....
912 //
913 SecGdbScriptBreak ();
914 } else {
915 ASSERT (FALSE);
916 }
917
918 AddHandle (ImageContext, ImageContext->PdbPointer);
919
920 if (EnabledOnEntry) {
921 SecEnableInterrupt ();
922 }
923
924
925 }
926
927#else
928
929 void *Handle = NULL;
930 void *Entry = NULL;
931
932 if (ImageContext->PdbPointer == NULL) {
933 return;
934 }
935
936 if (!IsPdbFile (ImageContext->PdbPointer)) {
937 return;
938 }
939
65e3f333 940 fprintf (
941 stderr,
949f388f 942 "Loading %s 0x%08lx - entry point 0x%08lx\n",
943 ImageContext->PdbPointer,
944 (unsigned long)ImageContext->ImageAddress,
65e3f333 945 (unsigned long)ImageContext->EntryPoint
946 );
949f388f 947
948 Handle = dlopen (ImageContext->PdbPointer, RTLD_NOW);
949
950 if (Handle) {
951 Entry = dlsym (Handle, "_ModuleEntryPoint");
952 } else {
953 printf("%s\n", dlerror());
954 }
955
956 if (Entry != NULL) {
957 ImageContext->EntryPoint = (UINTN)Entry;
65e3f333 958 printf ("Change %s Entrypoint to :0x%08lx\n", ImageContext->PdbPointer, (unsigned long)Entry);
949f388f 959 }
960
961 SecUnixLoaderBreak ();
962
963#endif
964
965 return;
966}
967
968
969VOID
970EFIAPI
971SecPeCoffUnloadImageExtraAction (
972 IN PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
973 )
974{
975 VOID *Handle;
976
977 Handle = RemoveHandle (ImageContext);
978
979#ifdef __APPLE__
980 FILE *GdbTempFile;
981 BOOLEAN EnabledOnEntry;
982
983 if (Handle != NULL) {
984 //
985 // Need to skip .PDB files created from VC++
986 //
987 if (!IsPdbFile (ImageContext->PdbPointer)) {
988 if (SecInterruptEanbled ()) {
989 SecDisableInterrupt ();
990 EnabledOnEntry = TRUE;
991 } else {
992 EnabledOnEntry = FALSE;
993 }
994
995 //
996 // Write the file we need for the gdb script
997 //
998 GdbTempFile = fopen (gGdbWorkingFileName, "w");
999 if (GdbTempFile != NULL) {
1000 fprintf (GdbTempFile, "remove-symbol-file %s\n", ImageContext->PdbPointer);
1001 fclose (GdbTempFile);
1002
1003 //
1004 // Target for gdb breakpoint in a script that uses gGdbWorkingFileName to set a breakpoint.
1005 // Hey what can you say scripting in gdb is not that great....
1006 //
1007 SecGdbScriptBreak ();
1008 } else {
1009 ASSERT (FALSE);
1010 }
1011
1012 if (EnabledOnEntry) {
1013 SecEnableInterrupt ();
1014 }
1015 }
1016 }
1017
1018#else
1019 //
1020 // Don't want to confuse gdb with symbols for something that got unloaded
1021 //
1022 if (Handle != NULL) {
1023 dlclose (Handle);
1024 }
1025
1026#endif
1027 return;
1028}
1029
1030