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