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