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