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