]> git.proxmox.com Git - mirror_edk2.git/blob - InOsEmuPkg/Unix/Sec/SecMain.c
InOsEmuPkg/Unix: Auto-load symbols files in gdb
[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 #endif
20
21
22 //
23 // Globals
24 //
25
26 EMU_THUNK_PPI mSecEmuThunkPpi = {
27 GasketSecUnixPeiAutoScan,
28 GasketSecUnixFdAddress,
29 GasketSecEmuThunkAddress
30 };
31
32 char *gGdbWorkingFileName = NULL;
33 UINTN mScriptSymbolChangesCount = 0;
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 EFI_PEI_PPI_DESCRIPTOR *gPpiList;
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 FILE *GdbTempFile;
99
100 setbuf (stdout, 0);
101 setbuf (stderr, 0);
102
103 MemorySizeStr = (CHAR16 *) PcdGetPtr (PcdEmuMemorySize);
104 FirmwareVolumesStr = (CHAR16 *) PcdGetPtr (PcdEmuFirmwareVolume);
105
106 printf ("\nEDK II UNIX Emulation Environment from edk2.sourceforge.net\n");
107
108 //
109 // PPIs pased into PEI_CORE
110 //
111 AddThunkPpi (EFI_PEI_PPI_DESCRIPTOR_PPI, &gEmuThunkPpiGuid, &mSecEmuThunkPpi);
112
113 SecInitThunkProtocol ();
114
115 //
116 // Emulator Bus Driver Thunks
117 //
118 AddThunkProtocol (&gX11ThunkIo, (CHAR16 *)PcdGetPtr (PcdEmuGop), TRUE);
119 AddThunkProtocol (&gPosixFileSystemThunkIo, (CHAR16 *)PcdGetPtr (PcdEmuFileSystem), TRUE);
120 AddThunkProtocol (&gBlockIoThunkIo, (CHAR16 *)PcdGetPtr (PcdEmuVirtualDisk), TRUE);
121 AddThunkProtocol (&gSnpThunkIo, (CHAR16 *)PcdGetPtr (PcdEmuNetworkInterface), TRUE);
122
123 //
124 // Emulator other Thunks
125 //
126 AddThunkProtocol (&gPthreadThunkIo, (CHAR16 *)PcdGetPtr (PcdEmuApCount), FALSE);
127
128 // EmuSecLibConstructor ();
129
130 gPpiList = GetThunkPpiList ();
131
132 //
133 // If dlopen doesn't work, then we build a gdb script to allow the
134 // symbols to be loaded.
135 //
136 Index = strlen (*Argv);
137 gGdbWorkingFileName = AllocatePool (Index + strlen(".gdb") + 1);
138 strcpy (gGdbWorkingFileName, *Argv);
139 strcat (gGdbWorkingFileName, ".gdb");
140
141 //
142 // Empty out the gdb symbols script file.
143 //
144 GdbTempFile = fopen (gGdbWorkingFileName, "w");
145 if (GdbTempFile != NULL) {
146 fclose (GdbTempFile);
147 }
148
149 //
150 // Allocate space for gSystemMemory Array
151 //
152 gSystemMemoryCount = CountSeperatorsInString (MemorySizeStr, '!') + 1;
153 gSystemMemory = AllocateZeroPool (gSystemMemoryCount * sizeof (EMU_SYSTEM_MEMORY));
154 if (gSystemMemory == NULL) {
155 printf ("ERROR : Can not allocate memory for system. Exiting.\n");
156 exit (1);
157 }
158 //
159 // Allocate space for gSystemMemory Array
160 //
161 gFdInfoCount = CountSeperatorsInString (FirmwareVolumesStr, '!') + 1;
162 gFdInfo = AllocateZeroPool (gFdInfoCount * sizeof (EMU_FD_INFO));
163 if (gFdInfo == NULL) {
164 printf ("ERROR : Can not allocate memory for fd info. Exiting.\n");
165 exit (1);
166 }
167
168 printf (" BootMode 0x%02x\n", (unsigned int)PcdGet32 (PcdEmuBootMode));
169
170 //
171 // Open up a 128K file to emulate temp memory for SEC.
172 // on a real platform this would be SRAM, or using the cache as RAM.
173 // Set InitialStackMemory to zero so UnixOpenFile will allocate a new mapping
174 //
175 InitialStackMemorySize = STACK_SIZE;
176 InitialStackMemory = (UINTN)MapMemory (
177 0, (UINT32) InitialStackMemorySize,
178 PROT_READ | PROT_WRITE | PROT_EXEC, MAP_ANONYMOUS | MAP_PRIVATE
179 );
180 if (InitialStackMemory == 0) {
181 printf ("ERROR : Can not open SecStack Exiting\n");
182 exit (1);
183 }
184
185 printf (" OS Emulator passing in %u KB of temp RAM at 0x%08lx to SEC\n",
186 (unsigned int)(InitialStackMemorySize / 1024),
187 (unsigned long)InitialStackMemory
188 );
189
190 for (StackPointer = (UINTN*) (UINTN) InitialStackMemory;
191 StackPointer < (UINTN*)(UINTN)((UINTN) InitialStackMemory + (UINT64) InitialStackMemorySize);
192 StackPointer ++) {
193 *StackPointer = 0x5AA55AA5;
194 }
195
196 //
197 // Open All the firmware volumes and remember the info in the gFdInfo global
198 //
199 FileName = (CHAR8 *) AllocatePool (StrLen (FirmwareVolumesStr) + 1);
200 if (FileName == NULL) {
201 printf ("ERROR : Can not allocate memory for firmware volume string\n");
202 exit (1);
203 }
204
205 Index2 = 0;
206 for (Done = FALSE, Index = 0, PeiIndex = 0, SecFile = NULL;
207 FirmwareVolumesStr[Index2] != 0;
208 Index++) {
209 for (Index1 = 0; (FirmwareVolumesStr[Index2] != '!') && (FirmwareVolumesStr[Index2] != 0); Index2++) {
210 FileName[Index1++] = FirmwareVolumesStr[Index2];
211 }
212 if (FirmwareVolumesStr[Index2] == '!') {
213 Index2++;
214 }
215 FileName[Index1] = '\0';
216
217 if (Index == 0) {
218 // Map FV Recovery Read Only and other areas Read/Write
219 Status = MapFd0 (
220 FileName,
221 &gFdInfo[0].Address,
222 &gFdInfo[0].Size
223 );
224 } else {
225 //
226 // Open the FD and remmeber where it got mapped into our processes address space
227 // Maps Read Only
228 //
229 Status = MapFile (
230 FileName,
231 &gFdInfo[Index].Address,
232 &gFdInfo[Index].Size
233 );
234 }
235 if (EFI_ERROR (Status)) {
236 printf ("ERROR : Can not open Firmware Device File %s (%x). Exiting.\n", FileName, (unsigned int)Status);
237 exit (1);
238 }
239
240 printf (" FD loaded from %s at 0x%08lx",FileName, (unsigned long)gFdInfo[Index].Address);
241
242 if (SecFile == NULL) {
243 //
244 // Assume the beginning of the FD is an FV and look for the SEC Core.
245 // Load the first one we find.
246 //
247 FileHandle = NULL;
248 Status = PeiServicesFfsFindNextFile (
249 EFI_FV_FILETYPE_SECURITY_CORE,
250 (EFI_PEI_FV_HANDLE)(UINTN)gFdInfo[Index].Address,
251 &FileHandle
252 );
253 if (!EFI_ERROR (Status)) {
254 Status = PeiServicesFfsFindSectionData (EFI_SECTION_PE32, FileHandle, &SecFile);
255 if (!EFI_ERROR (Status)) {
256 PeiIndex = Index;
257 printf (" contains SEC Core");
258 }
259 }
260 }
261
262 printf ("\n");
263 }
264 //
265 // Calculate memory regions and store the information in the gSystemMemory
266 // global for later use. The autosizing code will use this data to
267 // map this memory into the SEC process memory space.
268 //
269 Index1 = 0;
270 Index = 0;
271 while (1) {
272 UINTN val = 0;
273 //
274 // Save the size of the memory.
275 //
276 while (MemorySizeStr[Index1] >= '0' && MemorySizeStr[Index1] <= '9') {
277 val = val * 10 + MemorySizeStr[Index1] - '0';
278 Index1++;
279 }
280 gSystemMemory[Index++].Size = val * 0x100000;
281 if (MemorySizeStr[Index1] == 0) {
282 break;
283 }
284 Index1++;
285 }
286
287 printf ("\n");
288
289 //
290 // Hand off to SEC
291 //
292 SecLoadFromCore ((UINTN) InitialStackMemory, (UINTN) InitialStackMemorySize, (UINTN) gFdInfo[0].Address, SecFile);
293
294 //
295 // If we get here, then the SEC Core returned. This is an error as SEC should
296 // always hand off to PEI Core and then on to DXE Core.
297 //
298 printf ("ERROR : SEC returned\n");
299 exit (1);
300 }
301
302
303 EFI_PHYSICAL_ADDRESS *
304 MapMemory (
305 IN INTN fd,
306 IN UINT64 length,
307 IN INTN prot,
308 IN INTN flags
309 )
310 {
311 STATIC UINTN base = 0x40000000;
312 CONST UINTN align = (1 << 24);
313 VOID *res = NULL;
314 BOOLEAN isAligned = 0;
315
316 //
317 // Try to get an aligned block somewhere in the address space of this
318 // process.
319 //
320 while((!isAligned) && (base != 0)) {
321 res = mmap ((void *)base, length, prot, flags, fd, 0);
322 if (res == MAP_FAILED) {
323 return NULL;
324 }
325 if ((((UINTN)res) & ~(align-1)) == (UINTN)res) {
326 isAligned=1;
327 } else {
328 munmap(res, length);
329 base += align;
330 }
331 }
332 return res;
333 }
334
335
336 /*++
337
338 Routine Description:
339 Opens and memory maps a file using Unix services. If BaseAddress is non zero
340 the process will try and allocate the memory starting at BaseAddress.
341
342 Arguments:
343 FileName - The name of the file to open and map
344 MapSize - The amount of the file to map in bytes
345 CreationDisposition - The flags to pass to CreateFile(). Use to create new files for
346 memory emulation, and exiting files for firmware volume emulation
347 BaseAddress - The base address of the mapped file in the user address space.
348 If passed in as NULL the a new memory region is used.
349 If passed in as non NULL the request memory region is used for
350 the mapping of the file into the process space.
351 Length - The size of the mapped region in bytes
352
353 Returns:
354 EFI_SUCCESS - The file was opened and mapped.
355 EFI_NOT_FOUND - FileName was not found in the current directory
356 EFI_DEVICE_ERROR - An error occured attempting to map the opened file
357
358 **/
359 EFI_STATUS
360 MapFile (
361 IN CHAR8 *FileName,
362 IN OUT EFI_PHYSICAL_ADDRESS *BaseAddress,
363 OUT UINT64 *Length
364 )
365 {
366 int fd;
367 VOID *res;
368 UINTN FileSize;
369
370 fd = open (FileName, O_RDWR);
371 if (fd < 0) {
372 return EFI_NOT_FOUND;
373 }
374 FileSize = lseek (fd, 0, SEEK_END);
375
376
377 res = MapMemory (fd, FileSize, PROT_READ | PROT_EXEC, MAP_PRIVATE);
378
379 close (fd);
380
381 if (res == NULL) {
382 perror ("MapFile() Failed");
383 return EFI_DEVICE_ERROR;
384 }
385
386 *Length = (UINT64) FileSize;
387 *BaseAddress = (EFI_PHYSICAL_ADDRESS) (UINTN) res;
388
389 return EFI_SUCCESS;
390 }
391
392 EFI_STATUS
393 MapFd0 (
394 IN CHAR8 *FileName,
395 IN OUT EFI_PHYSICAL_ADDRESS *BaseAddress,
396 OUT UINT64 *Length
397 )
398 {
399 int fd;
400 void *res, *res2, *res3;
401 UINTN FileSize;
402 UINTN FvSize;
403 void *EmuMagicPage;
404
405 fd = open (FileName, O_RDWR);
406 if (fd < 0) {
407 return EFI_NOT_FOUND;
408 }
409 FileSize = lseek (fd, 0, SEEK_END);
410
411 FvSize = FixedPcdGet64 (PcdEmuFlashFvRecoverySize);
412
413 // Assume start of FD is Recovery FV, and make it write protected
414 res = mmap (
415 (void *)(UINTN)FixedPcdGet64 (PcdEmuFlashFvRecoveryBase),
416 FvSize,
417 PROT_READ | PROT_EXEC,
418 MAP_PRIVATE,
419 fd,
420 0
421 );
422 if (res == MAP_FAILED) {
423 perror ("MapFd0() Failed res =");
424 close (fd);
425 return EFI_DEVICE_ERROR;
426 } else if (res != (void *)(UINTN)FixedPcdGet64 (PcdEmuFlashFvRecoveryBase)) {
427 // We could not load at the build address, so we need to allow writes
428 munmap (res, FvSize);
429 res = mmap (
430 (void *)(UINTN)FixedPcdGet64 (PcdEmuFlashFvRecoveryBase),
431 FvSize,
432 PROT_READ | PROT_WRITE | PROT_EXEC,
433 MAP_PRIVATE,
434 fd,
435 0
436 );
437 if (res == MAP_FAILED) {
438 perror ("MapFd0() Failed res =");
439 close (fd);
440 return EFI_DEVICE_ERROR;
441 }
442 }
443
444 // Map the rest of the FD as read/write
445 res2 = mmap (
446 (void *)(UINTN)(FixedPcdGet64 (PcdEmuFlashFvRecoveryBase) + FvSize),
447 FileSize - FvSize,
448 PROT_READ | PROT_WRITE | PROT_EXEC,
449 MAP_SHARED,
450 fd,
451 FvSize
452 );
453 close (fd);
454 if (res2 == MAP_FAILED) {
455 perror ("MapFd0() Failed res2 =");
456 return EFI_DEVICE_ERROR;
457 }
458
459 //
460 // If enabled use the magic page to communicate between modules
461 // This replaces the PI PeiServicesTable pointer mechanism that
462 // deos not work in the emulator. It also allows the removal of
463 // writable globals from SEC, PEI_CORE (libraries), PEIMs
464 //
465 EmuMagicPage = (void *)(UINTN)FixedPcdGet64 (PcdPeiServicesTablePage);
466 if (EmuMagicPage != NULL) {
467 res3 = mmap (
468 (void *)EmuMagicPage,
469 4096,
470 PROT_READ | PROT_WRITE,
471 MAP_PRIVATE | MAP_ANONYMOUS,
472 0,
473 0
474 );
475 if (res3 != EmuMagicPage) {
476 printf ("MapFd0(): Could not allocate PeiServicesTablePage @ %lx\n", (long unsigned int)EmuMagicPage);
477 return EFI_DEVICE_ERROR;
478 }
479 }
480
481 *Length = (UINT64) FileSize;
482 *BaseAddress = (EFI_PHYSICAL_ADDRESS) (UINTN) res;
483
484 return EFI_SUCCESS;
485 }
486
487
488 /*++
489
490 Routine Description:
491 This is the service to load the SEC Core from the Firmware Volume
492
493 Arguments:
494 LargestRegion - Memory to use for SEC.
495 LargestRegionSize - Size of Memory to use for PEI
496 BootFirmwareVolumeBase - Start of the Boot FV
497 PeiCorePe32File - SEC PE32
498
499 Returns:
500 Success means control is transfered and thus we should never return
501
502 **/
503 VOID
504 SecLoadFromCore (
505 IN UINTN LargestRegion,
506 IN UINTN LargestRegionSize,
507 IN UINTN BootFirmwareVolumeBase,
508 IN VOID *PeiCorePe32File
509 )
510 {
511 EFI_STATUS Status;
512 EFI_PHYSICAL_ADDRESS TopOfMemory;
513 VOID *TopOfStack;
514 EFI_PHYSICAL_ADDRESS PeiCoreEntryPoint;
515 EFI_SEC_PEI_HAND_OFF *SecCoreData;
516 UINTN PeiStackSize;
517
518 //
519 // Compute Top Of Memory for Stack and PEI Core Allocations
520 //
521 TopOfMemory = LargestRegion + LargestRegionSize;
522 PeiStackSize = (UINTN)RShiftU64((UINT64)STACK_SIZE,1);
523
524 //
525 // |-----------| <---- TemporaryRamBase + TemporaryRamSize
526 // | Heap |
527 // | |
528 // |-----------| <---- StackBase / PeiTemporaryMemoryBase
529 // | |
530 // | Stack |
531 // |-----------| <---- TemporaryRamBase
532 //
533 TopOfStack = (VOID *)(LargestRegion + PeiStackSize);
534 TopOfMemory = LargestRegion + PeiStackSize;
535
536 //
537 // Reservet space for storing PeiCore's parament in stack.
538 //
539 TopOfStack = (VOID *)((UINTN)TopOfStack - sizeof (EFI_SEC_PEI_HAND_OFF) - CPU_STACK_ALIGNMENT);
540 TopOfStack = ALIGN_POINTER (TopOfStack, CPU_STACK_ALIGNMENT);
541
542
543 //
544 // Bind this information into the SEC hand-off state
545 //
546 SecCoreData = (EFI_SEC_PEI_HAND_OFF*)(UINTN) TopOfStack;
547 SecCoreData->DataSize = sizeof(EFI_SEC_PEI_HAND_OFF);
548 SecCoreData->BootFirmwareVolumeBase = (VOID*)BootFirmwareVolumeBase;
549 SecCoreData->BootFirmwareVolumeSize = PcdGet32 (PcdEmuFirmwareFdSize);
550 SecCoreData->TemporaryRamBase = (VOID*)(UINTN)LargestRegion;
551 SecCoreData->TemporaryRamSize = STACK_SIZE;
552 SecCoreData->StackBase = SecCoreData->TemporaryRamBase;
553 SecCoreData->StackSize = PeiStackSize;
554 SecCoreData->PeiTemporaryRamBase = (VOID*) ((UINTN) SecCoreData->TemporaryRamBase + PeiStackSize);
555 SecCoreData->PeiTemporaryRamSize = STACK_SIZE - PeiStackSize;
556
557 //
558 // Find the SEC Core Entry Point
559 //
560 Status = SecPeCoffGetEntryPoint (PeiCorePe32File, (VOID **)&PeiCoreEntryPoint);
561 if (EFI_ERROR (Status)) {
562 return ;
563 }
564
565 //
566 // Transfer control to the SEC Core
567 //
568 PeiSwitchStacks (
569 (SWITCH_STACK_ENTRY_POINT) (UINTN) PeiCoreEntryPoint,
570 SecCoreData,
571 (VOID *)gPpiList,
572 TopOfStack
573 );
574 //
575 // If we get here, then the SEC Core returned. This is an error
576 //
577 return ;
578 }
579
580
581 /*++
582
583 Routine Description:
584 This service is called from Index == 0 until it returns EFI_UNSUPPORTED.
585 It allows discontiguous memory regions to be supported by the emulator.
586 It uses gSystemMemory[] and gSystemMemoryCount that were created by
587 parsing the host environment variable EFI_MEMORY_SIZE.
588 The size comes from the varaible and the address comes from the call to
589 UnixOpenFile.
590
591 Arguments:
592 Index - Which memory region to use
593 MemoryBase - Return Base address of memory region
594 MemorySize - Return size in bytes of the memory region
595
596 Returns:
597 EFI_SUCCESS - If memory region was mapped
598 EFI_UNSUPPORTED - If Index is not supported
599
600 **/
601 EFI_STATUS
602 SecUnixPeiAutoScan (
603 IN UINTN Index,
604 OUT EFI_PHYSICAL_ADDRESS *MemoryBase,
605 OUT UINT64 *MemorySize
606 )
607 {
608 void *res;
609
610 if (Index >= gSystemMemoryCount) {
611 return EFI_UNSUPPORTED;
612 }
613
614 *MemoryBase = 0;
615 res = MapMemory (
616 0, gSystemMemory[Index].Size,
617 PROT_READ | PROT_WRITE | PROT_EXEC,
618 MAP_PRIVATE | MAP_ANONYMOUS
619 );
620 if (res == MAP_FAILED) {
621 return EFI_DEVICE_ERROR;
622 }
623 *MemorySize = gSystemMemory[Index].Size;
624 *MemoryBase = (UINTN)res;
625 gSystemMemory[Index].Memory = *MemoryBase;
626
627 return EFI_SUCCESS;
628 }
629
630
631 /*++
632
633 Routine Description:
634 Check to see if an address range is in the EFI GCD memory map.
635
636 This is all of GCD for system memory passed to DXE Core. FV
637 mapping and other device mapped into system memory are not
638 inlcuded in the check.
639
640 Arguments:
641 Index - Which memory region to use
642 MemoryBase - Return Base address of memory region
643 MemorySize - Return size in bytes of the memory region
644
645 Returns:
646 TRUE - Address is in the EFI GCD memory map
647 FALSE - Address is NOT in memory map
648
649 **/
650 BOOLEAN
651 EfiSystemMemoryRange (
652 IN VOID *MemoryAddress
653 )
654 {
655 UINTN Index;
656 EFI_PHYSICAL_ADDRESS MemoryBase;
657
658 MemoryBase = (EFI_PHYSICAL_ADDRESS)(UINTN)MemoryAddress;
659 for (Index = 0; Index < gSystemMemoryCount; Index++) {
660 if ((MemoryBase >= gSystemMemory[Index].Memory) &&
661 (MemoryBase < (gSystemMemory[Index].Memory + gSystemMemory[Index].Size)) ) {
662 return TRUE;
663 }
664 }
665
666 return FALSE;
667 }
668
669
670 /*++
671
672 Routine Description:
673 Since the SEC is the only Unix program in stack it must export
674 an interface to do POSIX calls. gUnix is initailized in UnixThunk.c.
675
676 Arguments:
677 InterfaceSize - sizeof (EFI_WIN_NT_THUNK_PROTOCOL);
678 InterfaceBase - Address of the gUnix global
679
680 Returns:
681 EFI_SUCCESS - Data returned
682
683 **/
684 VOID *
685 SecEmuThunkAddress (
686 VOID
687 )
688 {
689 return &gEmuThunkProtocol;
690 }
691
692
693
694 RETURN_STATUS
695 EFIAPI
696 SecPeCoffGetEntryPoint (
697 IN VOID *Pe32Data,
698 IN OUT VOID **EntryPoint
699 )
700 {
701 EFI_STATUS Status;
702 PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;
703
704 ZeroMem (&ImageContext, sizeof (ImageContext));
705 ImageContext.Handle = Pe32Data;
706 ImageContext.ImageRead = (PE_COFF_LOADER_READ_FILE) SecImageRead;
707
708 Status = PeCoffLoaderGetImageInfo (&ImageContext);
709 if (EFI_ERROR (Status)) {
710 return Status;
711 }
712
713 if (ImageContext.ImageAddress != (UINTN)Pe32Data) {
714 //
715 // Relocate image to match the address where it resides
716 //
717 ImageContext.ImageAddress = (UINTN)Pe32Data;
718 Status = PeCoffLoaderLoadImage (&ImageContext);
719 if (EFI_ERROR (Status)) {
720 return Status;
721 }
722
723 Status = PeCoffLoaderRelocateImage (&ImageContext);
724 if (EFI_ERROR (Status)) {
725 return Status;
726 }
727 } else {
728 //
729 // Or just return image entry point
730 //
731 ImageContext.PdbPointer = PeCoffLoaderGetPdbPointer (Pe32Data);
732 Status = PeCoffLoaderGetEntryPoint (Pe32Data, EntryPoint);
733 if (EFI_ERROR (Status)) {
734 return Status;
735 }
736 ImageContext.EntryPoint = (UINTN)*EntryPoint;
737 }
738
739 // On Unix a dlopen is done that will change the entry point
740 SecPeCoffRelocateImageExtraAction (&ImageContext);
741 *EntryPoint = (VOID *)(UINTN)ImageContext.EntryPoint;
742
743 return Status;
744 }
745
746
747
748 /*++
749
750 Routine Description:
751 Return the FD Size and base address. Since the FD is loaded from a
752 file into host memory only the SEC will know it's address.
753
754 Arguments:
755 Index - Which FD, starts at zero.
756 FdSize - Size of the FD in bytes
757 FdBase - Start address of the FD. Assume it points to an FV Header
758 FixUp - Difference between actual FD address and build address
759
760 Returns:
761 EFI_SUCCESS - Return the Base address and size of the FV
762 EFI_UNSUPPORTED - Index does nto map to an FD in the system
763
764 **/
765 EFI_STATUS
766 SecUnixFdAddress (
767 IN UINTN Index,
768 IN OUT EFI_PHYSICAL_ADDRESS *FdBase,
769 IN OUT UINT64 *FdSize,
770 IN OUT EFI_PHYSICAL_ADDRESS *FixUp
771 )
772 {
773 if (Index >= gFdInfoCount) {
774 return EFI_UNSUPPORTED;
775 }
776
777 *FdBase = gFdInfo[Index].Address;
778 *FdSize = gFdInfo[Index].Size;
779 *FixUp = 0;
780
781 if (*FdBase == 0 && *FdSize == 0) {
782 return EFI_UNSUPPORTED;
783 }
784
785 if (Index == 0) {
786 //
787 // FD 0 has XIP code and well known PCD values
788 // If the memory buffer could not be allocated at the FD build address
789 // the Fixup is the difference.
790 //
791 *FixUp = *FdBase - PcdGet64 (PcdEmuFdBaseAddress);
792 }
793
794 return EFI_SUCCESS;
795 }
796
797
798 /*++
799
800 Routine Description:
801 Count the number of seperators in String
802
803 Arguments:
804 String - String to process
805 Seperator - Item to count
806
807 Returns:
808 Number of Seperator in String
809
810 **/
811 UINTN
812 CountSeperatorsInString (
813 IN const CHAR16 *String,
814 IN CHAR16 Seperator
815 )
816 {
817 UINTN Count;
818
819 for (Count = 0; *String != '\0'; String++) {
820 if (*String == Seperator) {
821 Count++;
822 }
823 }
824
825 return Count;
826 }
827
828
829 EFI_STATUS
830 EFIAPI
831 SecImageRead (
832 IN VOID *FileHandle,
833 IN UINTN FileOffset,
834 IN OUT UINTN *ReadSize,
835 OUT VOID *Buffer
836 )
837 /*++
838
839 Routine Description:
840 Support routine for the PE/COFF Loader that reads a buffer from a PE/COFF file
841
842 Arguments:
843 FileHandle - The handle to the PE/COFF file
844 FileOffset - The offset, in bytes, into the file to read
845 ReadSize - The number of bytes to read from the file starting at FileOffset
846 Buffer - A pointer to the buffer to read the data into.
847
848 Returns:
849 EFI_SUCCESS - ReadSize bytes of data were read into Buffer from the PE/COFF file starting at FileOffset
850
851 **/
852 {
853 CHAR8 *Destination8;
854 CHAR8 *Source8;
855 UINTN Length;
856
857 Destination8 = Buffer;
858 Source8 = (CHAR8 *) ((UINTN) FileHandle + FileOffset);
859 Length = *ReadSize;
860 while (Length--) {
861 *(Destination8++) = *(Source8++);
862 }
863
864 return EFI_SUCCESS;
865 }
866
867
868 /*++
869
870 Routine Description:
871 Store the ModHandle in an array indexed by the Pdb File name.
872 The ModHandle is needed to unload the image.
873
874 Arguments:
875 ImageContext - Input data returned from PE Laoder Library. Used to find the
876 .PDB file name of the PE Image.
877 ModHandle - Returned from LoadLibraryEx() and stored for call to
878 FreeLibrary().
879
880 Returns:
881 EFI_SUCCESS - ModHandle was stored.
882
883 **/
884 EFI_STATUS
885 AddHandle (
886 IN PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext,
887 IN VOID *ModHandle
888 )
889 {
890 UINTN Index;
891 IMAGE_CONTEXT_TO_MOD_HANDLE *Array;
892 UINTN PreviousSize;
893
894
895 Array = mImageContextModHandleArray;
896 for (Index = 0; Index < mImageContextModHandleArraySize; Index++, Array++) {
897 if (Array->ImageContext == NULL) {
898 //
899 // Make a copy of the stirng and store the ModHandle
900 //
901 Array->ImageContext = ImageContext;
902 Array->ModHandle = ModHandle;
903 return EFI_SUCCESS;
904 }
905 }
906
907 //
908 // No free space in mImageContextModHandleArray so grow it by
909 // IMAGE_CONTEXT_TO_MOD_HANDLE entires. realloc will
910 // copy the old values to the new locaiton. But it does
911 // not zero the new memory area.
912 //
913 PreviousSize = mImageContextModHandleArraySize * sizeof (IMAGE_CONTEXT_TO_MOD_HANDLE);
914 mImageContextModHandleArraySize += MAX_IMAGE_CONTEXT_TO_MOD_HANDLE_ARRAY_SIZE;
915
916 mImageContextModHandleArray = ReallocatePool (
917 (mImageContextModHandleArraySize - 1) * sizeof (IMAGE_CONTEXT_TO_MOD_HANDLE),
918 mImageContextModHandleArraySize * sizeof (IMAGE_CONTEXT_TO_MOD_HANDLE),
919 mImageContextModHandleArray
920 );
921 if (mImageContextModHandleArray == NULL) {
922 ASSERT (FALSE);
923 return EFI_OUT_OF_RESOURCES;
924 }
925
926 memset (mImageContextModHandleArray + PreviousSize, 0, MAX_IMAGE_CONTEXT_TO_MOD_HANDLE_ARRAY_SIZE * sizeof (IMAGE_CONTEXT_TO_MOD_HANDLE));
927
928 return AddHandle (ImageContext, ModHandle);
929 }
930
931
932 /*++
933
934 Routine Description:
935 Return the ModHandle and delete the entry in the array.
936
937 Arguments:
938 ImageContext - Input data returned from PE Laoder Library. Used to find the
939 .PDB file name of the PE Image.
940
941 Returns:
942 ModHandle - ModHandle assoicated with ImageContext is returned
943 NULL - No ModHandle associated with ImageContext
944
945 **/
946 VOID *
947 RemoveHandle (
948 IN PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
949 )
950 {
951 UINTN Index;
952 IMAGE_CONTEXT_TO_MOD_HANDLE *Array;
953
954 if (ImageContext->PdbPointer == NULL) {
955 //
956 // If no PDB pointer there is no ModHandle so return NULL
957 //
958 return NULL;
959 }
960
961 Array = mImageContextModHandleArray;
962 for (Index = 0; Index < mImageContextModHandleArraySize; Index++, Array++) {
963 if (Array->ImageContext == ImageContext) {
964 //
965 // If you find a match return it and delete the entry
966 //
967 Array->ImageContext = NULL;
968 return Array->ModHandle;
969 }
970 }
971
972 return NULL;
973 }
974
975
976
977 //
978 // Target for gdb breakpoint in a script that uses gGdbWorkingFileName to source a
979 // add-symbol-file command. Hey what can you say scripting in gdb is not that great....
980 //
981 // Put .gdbinit in the CWD where you do gdb SecMain.dll for source level debug
982 //
983 // cat .gdbinit
984 // b SecGdbScriptBreak
985 // command
986 // silent
987 // source SecMain.gdb
988 // c
989 // end
990 //
991 VOID
992 SecGdbScriptBreak (
993 VOID
994 )
995 {
996 }
997
998 VOID
999 SecUnixLoaderBreak (
1000 VOID
1001 )
1002 {
1003 }
1004
1005 BOOLEAN
1006 IsPdbFile (
1007 IN CHAR8 *PdbFileName
1008 )
1009 {
1010 UINTN Len;
1011
1012 if (PdbFileName == NULL) {
1013 return FALSE;
1014 }
1015
1016 Len = strlen (PdbFileName);
1017 if ((Len < 5)|| (PdbFileName[Len - 4] != '.')) {
1018 return FALSE;
1019 }
1020
1021 if ((PdbFileName[Len - 3] == 'P' || PdbFileName[Len - 3] == 'p') &&
1022 (PdbFileName[Len - 2] == 'D' || PdbFileName[Len - 2] == 'd') &&
1023 (PdbFileName[Len - 1] == 'B' || PdbFileName[Len - 1] == 'b')) {
1024 return TRUE;
1025 }
1026
1027 return FALSE;
1028 }
1029
1030
1031 #define MAX_SPRINT_BUFFER_SIZE 0x200
1032
1033 void
1034 PrintLoadAddress (
1035 IN PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
1036 )
1037 {
1038 if (ImageContext->PdbPointer == NULL) {
1039 fprintf (stderr,
1040 "0x%08lx Loading NO DEBUG with entry point 0x%08lx\n",
1041 (unsigned long)(ImageContext->ImageAddress),
1042 (unsigned long)ImageContext->EntryPoint
1043 );
1044 } else {
1045 fprintf (stderr,
1046 "0x%08lx Loading %s with entry point 0x%08lx\n",
1047 (unsigned long)(ImageContext->ImageAddress + ImageContext->SizeOfHeaders),
1048 ImageContext->PdbPointer,
1049 (unsigned long)ImageContext->EntryPoint
1050 );
1051 }
1052 // Keep output synced up
1053 fflush (stderr);
1054 }
1055
1056
1057 /**
1058 Loads the image using dlopen so symbols will be automatically
1059 loaded by gdb.
1060
1061 @param ImageContext The PE/COFF image context
1062
1063 @retval TRUE - The image was successfully loaded
1064 @retval FALSE - The image was successfully loaded
1065
1066 **/
1067 BOOLEAN
1068 DlLoadImage (
1069 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
1070 )
1071 {
1072
1073 #ifdef __APPLE__
1074
1075 return FALSE;
1076
1077 #else
1078
1079 void *Handle = NULL;
1080 void *Entry = NULL;
1081
1082 if (ImageContext->PdbPointer == NULL) {
1083 return FALSE;
1084 }
1085
1086 if (!IsPdbFile (ImageContext->PdbPointer)) {
1087 return FALSE;
1088 }
1089
1090 fprintf (
1091 stderr,
1092 "Loading %s 0x%08lx - entry point 0x%08lx\n",
1093 ImageContext->PdbPointer,
1094 (unsigned long)ImageContext->ImageAddress,
1095 (unsigned long)ImageContext->EntryPoint
1096 );
1097
1098 Handle = dlopen (ImageContext->PdbPointer, RTLD_NOW);
1099
1100 if (Handle) {
1101 Entry = dlsym (Handle, "_ModuleEntryPoint");
1102 } else {
1103 printf("%s\n", dlerror());
1104 }
1105
1106 if (Entry != NULL) {
1107 ImageContext->EntryPoint = (UINTN)Entry;
1108 printf ("Change %s Entrypoint to :0x%08lx\n", ImageContext->PdbPointer, (unsigned long)Entry);
1109 return TRUE;
1110 } else {
1111 return FALSE;
1112 }
1113
1114 #endif
1115 }
1116
1117
1118 /**
1119 Adds the image to a gdb script so it's symbols can be loaded.
1120 The AddFirmwareSymbolFile helper macro is used.
1121
1122 @param ImageContext The PE/COFF image context
1123
1124 **/
1125 VOID
1126 GdbScriptAddImage (
1127 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
1128 )
1129 {
1130 BOOLEAN InterruptsWereEnabled;
1131
1132 //
1133 // Disable interrupts to make sure writing of the .gdb file
1134 // is an atomic operation.
1135 //
1136 if (SecInterruptEanbled ()) {
1137 SecDisableInterrupt ();
1138 InterruptsWereEnabled = TRUE;
1139 } else {
1140 InterruptsWereEnabled = FALSE;
1141 }
1142
1143 PrintLoadAddress (ImageContext);
1144
1145 if (ImageContext->PdbPointer != NULL && !IsPdbFile (ImageContext->PdbPointer)) {
1146 FILE *GdbTempFile;
1147 GdbTempFile = fopen (gGdbWorkingFileName, "a");
1148 if (GdbTempFile != NULL) {
1149 long unsigned int SymbolsAddr = (long unsigned int)(ImageContext->ImageAddress + ImageContext->SizeOfHeaders);
1150 mScriptSymbolChangesCount++;
1151 fprintf (
1152 GdbTempFile,
1153 "AddFirmwareSymbolFile 0x%x %s 0x%08lx\n",
1154 mScriptSymbolChangesCount,
1155 ImageContext->PdbPointer,
1156 SymbolsAddr
1157 );
1158 fclose (GdbTempFile);
1159 } else {
1160 ASSERT (FALSE);
1161 }
1162
1163 AddHandle (ImageContext, ImageContext->PdbPointer);
1164
1165 if (InterruptsWereEnabled) {
1166 SecEnableInterrupt ();
1167 }
1168
1169 }
1170 }
1171
1172
1173 VOID
1174 EFIAPI
1175 SecPeCoffRelocateImageExtraAction (
1176 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
1177 )
1178 {
1179 if (!DlLoadImage (ImageContext)) {
1180 GdbScriptAddImage (ImageContext);
1181 }
1182 }
1183
1184
1185 /**
1186 Adds the image to a gdb script so it's symbols can be unloaded.
1187 The RemoveFirmwareSymbolFile helper macro is used.
1188
1189 @param ImageContext The PE/COFF image context
1190
1191 **/
1192 VOID
1193 GdbScriptRemoveImage (
1194 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
1195 )
1196 {
1197 FILE *GdbTempFile;
1198 BOOLEAN InterruptsWereEnabled;
1199
1200 //
1201 // Need to skip .PDB files created from VC++
1202 //
1203 if (IsPdbFile (ImageContext->PdbPointer)) {
1204 return;
1205 }
1206
1207 if (SecInterruptEanbled ()) {
1208 SecDisableInterrupt ();
1209 InterruptsWereEnabled = TRUE;
1210 } else {
1211 InterruptsWereEnabled = FALSE;
1212 }
1213
1214 //
1215 // Write the file we need for the gdb script
1216 //
1217 GdbTempFile = fopen (gGdbWorkingFileName, "a");
1218 if (GdbTempFile != NULL) {
1219 mScriptSymbolChangesCount++;
1220 fprintf (
1221 GdbTempFile,
1222 "RemoveFirmwareSymbolFile 0x%x %s\n",
1223 mScriptSymbolChangesCount,
1224 ImageContext->PdbPointer
1225 );
1226 fclose (GdbTempFile);
1227 } else {
1228 ASSERT (FALSE);
1229 }
1230
1231 if (InterruptsWereEnabled) {
1232 SecEnableInterrupt ();
1233 }
1234 }
1235
1236
1237 VOID
1238 EFIAPI
1239 SecPeCoffUnloadImageExtraAction (
1240 IN PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
1241 )
1242 {
1243 VOID *Handle;
1244
1245 //
1246 // Check to see if the image symbols were loaded with gdb script, or dlopen
1247 //
1248 Handle = RemoveHandle (ImageContext);
1249
1250 if (Handle == NULL) {
1251 #ifndef __APPLE__
1252 dlclose (Handle);
1253 #endif
1254 return;
1255 }
1256
1257 GdbScriptRemoveImage (ImageContext);
1258 }
1259
1260