]> git.proxmox.com Git - mirror_edk2.git/blame - InOsEmuPkg/Unix/Sec/SecMain.c
Fix bug in SerialRead returning error if no data was present.
[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
8052c4a2 215 if (Index == 0) {
216 // Map FV Recovery Read Only and other areas Read/Write
217 Status = MapFd0 (
218 FileName,
219 &gFdInfo[0].Address,
220 &gFdInfo[0].Size
221 );
222 } else {
223 //
224 // Open the FD and remmeber where it got mapped into our processes address space
225 // Maps Read Only
226 //
227 Status = MapFile (
228 FileName,
229 &gFdInfo[Index].Address,
230 &gFdInfo[Index].Size
231 );
232 }
949f388f 233 if (EFI_ERROR (Status)) {
234 printf ("ERROR : Can not open Firmware Device File %s (%x). Exiting.\n", FileName, (unsigned int)Status);
235 exit (1);
236 }
237
65e3f333 238 printf (" FD loaded from %s at 0x%08lx",FileName, (unsigned long)gFdInfo[Index].Address);
949f388f 239
65e3f333 240 if (SecFile == NULL) {
949f388f 241 //
65e3f333 242 // Assume the beginning of the FD is an FV and look for the SEC Core.
949f388f 243 // Load the first one we find.
244 //
65e3f333 245 FileHandle = NULL;
246 Status = PeiServicesFfsFindNextFile (
247 EFI_FV_FILETYPE_SECURITY_CORE,
248 (EFI_PEI_FV_HANDLE)(UINTN)gFdInfo[Index].Address,
249 &FileHandle
250 );
949f388f 251 if (!EFI_ERROR (Status)) {
65e3f333 252 Status = PeiServicesFfsFindSectionData (EFI_SECTION_PE32, FileHandle, &SecFile);
253 if (!EFI_ERROR (Status)) {
254 PeiIndex = Index;
255 printf (" contains SEC Core");
256 }
949f388f 257 }
258 }
259
260 printf ("\n");
261 }
262 //
263 // Calculate memory regions and store the information in the gSystemMemory
264 // global for later use. The autosizing code will use this data to
265 // map this memory into the SEC process memory space.
266 //
267 Index1 = 0;
268 Index = 0;
269 while (1) {
270 UINTN val = 0;
271 //
272 // Save the size of the memory.
273 //
274 while (MemorySizeStr[Index1] >= '0' && MemorySizeStr[Index1] <= '9') {
275 val = val * 10 + MemorySizeStr[Index1] - '0';
276 Index1++;
277 }
278 gSystemMemory[Index++].Size = val * 0x100000;
65e3f333 279 if (MemorySizeStr[Index1] == 0) {
949f388f 280 break;
65e3f333 281 }
949f388f 282 Index1++;
283 }
284
285 printf ("\n");
286
287 //
65e3f333 288 // Hand off to SEC
949f388f 289 //
65e3f333 290 SecLoadFromCore ((UINTN) InitialStackMemory, (UINTN) InitialStackMemorySize, (UINTN) gFdInfo[0].Address, SecFile);
949f388f 291
292 //
65e3f333 293 // If we get here, then the SEC Core returned. This is an error as SEC should
294 // always hand off to PEI Core and then on to DXE Core.
949f388f 295 //
65e3f333 296 printf ("ERROR : SEC returned\n");
949f388f 297 exit (1);
298}
299
65e3f333 300
949f388f 301EFI_PHYSICAL_ADDRESS *
302MapMemory (
303 INTN fd,
304 UINT64 length,
305 INTN prot,
306 INTN flags)
307{
308 STATIC UINTN base = 0x40000000;
309 CONST UINTN align = (1 << 24);
310 VOID *res = NULL;
311 BOOLEAN isAligned = 0;
312
313 //
314 // Try to get an aligned block somewhere in the address space of this
315 // process.
316 //
317 while((!isAligned) && (base != 0)) {
318 res = mmap ((void *)base, length, prot, flags, fd, 0);
319 if (res == MAP_FAILED) {
320 return NULL;
321 }
322 if ((((UINTN)res) & ~(align-1)) == (UINTN)res) {
323 isAligned=1;
65e3f333 324 } else {
949f388f 325 munmap(res, length);
326 base += align;
327 }
328 }
329 return res;
330}
331
65e3f333 332
949f388f 333/*++
334
335Routine Description:
336 Opens and memory maps a file using Unix services. If BaseAddress is non zero
337 the process will try and allocate the memory starting at BaseAddress.
338
339Arguments:
340 FileName - The name of the file to open and map
341 MapSize - The amount of the file to map in bytes
342 CreationDisposition - The flags to pass to CreateFile(). Use to create new files for
343 memory emulation, and exiting files for firmware volume emulation
344 BaseAddress - The base address of the mapped file in the user address space.
345 If passed in as NULL the a new memory region is used.
346 If passed in as non NULL the request memory region is used for
347 the mapping of the file into the process space.
348 Length - The size of the mapped region in bytes
349
350Returns:
351 EFI_SUCCESS - The file was opened and mapped.
352 EFI_NOT_FOUND - FileName was not found in the current directory
353 EFI_DEVICE_ERROR - An error occured attempting to map the opened file
354
355**/
65e3f333 356EFI_STATUS
357MapFile (
358 IN CHAR8 *FileName,
359 IN OUT EFI_PHYSICAL_ADDRESS *BaseAddress,
360 OUT UINT64 *Length
361 )
949f388f 362{
8052c4a2 363 int fd;
949f388f 364 VOID *res;
365 UINTN FileSize;
366
7e284acb 367 fd = open (FileName, O_RDWR);
65e3f333 368 if (fd < 0) {
949f388f 369 return EFI_NOT_FOUND;
65e3f333 370 }
949f388f 371 FileSize = lseek (fd, 0, SEEK_END);
372
373
8052c4a2 374 res = MapMemory (fd, FileSize, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE);
949f388f 375
376 close (fd);
377
7e284acb 378 if (res == NULL) {
379 perror ("MapFile() Failed");
949f388f 380 return EFI_DEVICE_ERROR;
65e3f333 381 }
8052c4a2 382
949f388f 383 *Length = (UINT64) FileSize;
384 *BaseAddress = (EFI_PHYSICAL_ADDRESS) (UINTN) res;
385
386 return EFI_SUCCESS;
387}
388
8052c4a2 389EFI_STATUS
390MapFd0 (
391 IN CHAR8 *FileName,
392 IN OUT EFI_PHYSICAL_ADDRESS *BaseAddress,
393 OUT UINT64 *Length
394 )
395{
396 int fd;
397 VOID *res, *res2;
398 UINTN FileSize;
399 UINTN FvSize;
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_WRITE | PROT_EXEC,
414 MAP_PRIVATE,
415 fd,
416 0
417 );
418 if (res == MAP_FAILED) {
419 perror ("MapFile() Failed res =");
420 close (fd);
421 return EFI_DEVICE_ERROR;
422 }
423
424 // Map the rest of the FD as read/write
425 res2 = mmap (
426 (void *)(FixedPcdGet64 (PcdEmuFlashFvRecoveryBase) + FvSize),
427 FileSize - FvSize,
428 PROT_READ | PROT_WRITE | PROT_EXEC,
429 MAP_SHARED,
430 fd,
431 FvSize
432 );
433 close (fd);
434 if (res2 == MAP_FAILED) {
435 perror ("MapFile() Failed res2 =");
436 return EFI_DEVICE_ERROR;
437 }
438
439 *Length = (UINT64) FileSize;
440 *BaseAddress = (EFI_PHYSICAL_ADDRESS) (UINTN) res;
441
442 return EFI_SUCCESS;
443}
949f388f 444
445
949f388f 446/*++
447
448Routine Description:
65e3f333 449 This is the service to load the SEC Core from the Firmware Volume
949f388f 450
451Arguments:
65e3f333 452 LargestRegion - Memory to use for SEC.
949f388f 453 LargestRegionSize - Size of Memory to use for PEI
454 BootFirmwareVolumeBase - Start of the Boot FV
65e3f333 455 PeiCorePe32File - SEC PE32
949f388f 456
457Returns:
458 Success means control is transfered and thus we should never return
459
460**/
65e3f333 461VOID
462SecLoadFromCore (
463 IN UINTN LargestRegion,
464 IN UINTN LargestRegionSize,
465 IN UINTN BootFirmwareVolumeBase,
466 IN VOID *PeiCorePe32File
467 )
949f388f 468{
469 EFI_STATUS Status;
470 EFI_PHYSICAL_ADDRESS TopOfMemory;
471 VOID *TopOfStack;
949f388f 472 EFI_PHYSICAL_ADDRESS PeiCoreEntryPoint;
949f388f 473 EFI_SEC_PEI_HAND_OFF *SecCoreData;
474 UINTN PeiStackSize;
475
476 //
477 // Compute Top Of Memory for Stack and PEI Core Allocations
478 //
479 TopOfMemory = LargestRegion + LargestRegionSize;
480 PeiStackSize = (UINTN)RShiftU64((UINT64)STACK_SIZE,1);
481
482 //
483 // |-----------| <---- TemporaryRamBase + TemporaryRamSize
484 // | Heap |
485 // | |
486 // |-----------| <---- StackBase / PeiTemporaryMemoryBase
487 // | |
488 // | Stack |
489 // |-----------| <---- TemporaryRamBase
490 //
491 TopOfStack = (VOID *)(LargestRegion + PeiStackSize);
492 TopOfMemory = LargestRegion + PeiStackSize;
493
494 //
495 // Reservet space for storing PeiCore's parament in stack.
496 //
497 TopOfStack = (VOID *)((UINTN)TopOfStack - sizeof (EFI_SEC_PEI_HAND_OFF) - CPU_STACK_ALIGNMENT);
498 TopOfStack = ALIGN_POINTER (TopOfStack, CPU_STACK_ALIGNMENT);
499
500
501 //
502 // Bind this information into the SEC hand-off state
503 //
65e3f333 504 SecCoreData = (EFI_SEC_PEI_HAND_OFF*)(UINTN) TopOfStack;
949f388f 505 SecCoreData->DataSize = sizeof(EFI_SEC_PEI_HAND_OFF);
506 SecCoreData->BootFirmwareVolumeBase = (VOID*)BootFirmwareVolumeBase;
507 SecCoreData->BootFirmwareVolumeSize = PcdGet32 (PcdEmuFirmwareFdSize);
508 SecCoreData->TemporaryRamBase = (VOID*)(UINTN)LargestRegion;
509 SecCoreData->TemporaryRamSize = STACK_SIZE;
510 SecCoreData->StackBase = SecCoreData->TemporaryRamBase;
511 SecCoreData->StackSize = PeiStackSize;
512 SecCoreData->PeiTemporaryRamBase = (VOID*) ((UINTN) SecCoreData->TemporaryRamBase + PeiStackSize);
513 SecCoreData->PeiTemporaryRamSize = STACK_SIZE - PeiStackSize;
514
515 //
65e3f333 516 // Find the SEC Core Entry Point
949f388f 517 //
65e3f333 518 Status = SecPeCoffGetEntryPoint (PeiCorePe32File, (VOID **)&PeiCoreEntryPoint);
949f388f 519 if (EFI_ERROR (Status)) {
520 return ;
521 }
522
523 //
65e3f333 524 // Transfer control to the SEC Core
949f388f 525 //
526 PeiSwitchStacks (
527 (SWITCH_STACK_ENTRY_POINT) (UINTN) PeiCoreEntryPoint,
528 SecCoreData,
65e3f333 529 (VOID *)gPpiList,
949f388f 530 TopOfStack
531 );
532 //
65e3f333 533 // If we get here, then the SEC Core returned. This is an error
949f388f 534 //
535 return ;
536}
537
65e3f333 538
949f388f 539/*++
540
541Routine Description:
542 This service is called from Index == 0 until it returns EFI_UNSUPPORTED.
543 It allows discontiguous memory regions to be supported by the emulator.
544 It uses gSystemMemory[] and gSystemMemoryCount that were created by
545 parsing the host environment variable EFI_MEMORY_SIZE.
546 The size comes from the varaible and the address comes from the call to
547 UnixOpenFile.
548
549Arguments:
550 Index - Which memory region to use
551 MemoryBase - Return Base address of memory region
552 MemorySize - Return size in bytes of the memory region
553
554Returns:
555 EFI_SUCCESS - If memory region was mapped
556 EFI_UNSUPPORTED - If Index is not supported
557
558**/
65e3f333 559EFI_STATUS
560EFIAPI
561SecUnixPeiAutoScan (
562 IN UINTN Index,
563 OUT EFI_PHYSICAL_ADDRESS *MemoryBase,
564 OUT UINT64 *MemorySize
565 )
949f388f 566{
567 void *res;
568
569 if (Index >= gSystemMemoryCount) {
570 return EFI_UNSUPPORTED;
571 }
572
573 *MemoryBase = 0;
65e3f333 574 res = MapMemory (
575 0, gSystemMemory[Index].Size,
576 PROT_READ | PROT_WRITE | PROT_EXEC,
577 MAP_PRIVATE | MAP_ANONYMOUS
578 );
579 if (res == MAP_FAILED) {
949f388f 580 return EFI_DEVICE_ERROR;
65e3f333 581 }
949f388f 582 *MemorySize = gSystemMemory[Index].Size;
583 *MemoryBase = (UINTN)res;
584 gSystemMemory[Index].Memory = *MemoryBase;
585
586 return EFI_SUCCESS;
587}
588
65e3f333 589
949f388f 590/*++
591
592Routine Description:
593 Since the SEC is the only Unix program in stack it must export
594 an interface to do POSIX calls. gUnix is initailized in UnixThunk.c.
595
596Arguments:
597 InterfaceSize - sizeof (EFI_WIN_NT_THUNK_PROTOCOL);
598 InterfaceBase - Address of the gUnix global
599
600Returns:
601 EFI_SUCCESS - Data returned
602
603**/
65e3f333 604VOID *
605EFIAPI
606SecEmuThunkAddress (
607 VOID
608 )
949f388f 609{
610 return &gEmuThunkProtocol;
611}
612
613
949f388f 614
615RETURN_STATUS
616EFIAPI
617SecPeCoffGetEntryPoint (
618 IN VOID *Pe32Data,
619 IN OUT VOID **EntryPoint
620 )
621{
65e3f333 622 EFI_STATUS Status;
623 PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;
0ede3853 624
625 ZeroMem (&ImageContext, sizeof (ImageContext));
626 ImageContext.Handle = Pe32Data;
627 ImageContext.ImageRead = (PE_COFF_LOADER_READ_FILE) SecImageRead;
628
629 Status = PeCoffLoaderGetImageInfo (&ImageContext);
630 if (EFI_ERROR (Status)) {
631 return Status;
632 }
633
634 //
635 // Relocate image to match the address where it resides
636 //
8f0067d7 637 ImageContext.ImageAddress = (UINTN)Pe32Data;
0ede3853 638 Status = PeCoffLoaderLoadImage (&ImageContext);
639 if (EFI_ERROR (Status)) {
65e3f333 640 return Status;
641 }
949f388f 642
0ede3853 643 Status = PeCoffLoaderRelocateImage (&ImageContext);
644 if (EFI_ERROR (Status)) {
645 return Status;
646 }
949f388f 647
65e3f333 648 // On Unix a dlopen is done that will change the entry point
649 SecPeCoffRelocateImageExtraAction (&ImageContext);
650 *EntryPoint = (VOID *)(UINTN)ImageContext.EntryPoint;
651
949f388f 652 return Status;
653}
654
655
656
949f388f 657/*++
658
659Routine Description:
660 Return the FD Size and base address. Since the FD is loaded from a
661 file into host memory only the SEC will know it's address.
662
663Arguments:
664 Index - Which FD, starts at zero.
665 FdSize - Size of the FD in bytes
666 FdBase - Start address of the FD. Assume it points to an FV Header
667 FixUp - Difference between actual FD address and build address
668
669Returns:
670 EFI_SUCCESS - Return the Base address and size of the FV
671 EFI_UNSUPPORTED - Index does nto map to an FD in the system
672
673**/
65e3f333 674EFI_STATUS
675EFIAPI
676SecUnixFdAddress (
677 IN UINTN Index,
678 IN OUT EFI_PHYSICAL_ADDRESS *FdBase,
679 IN OUT UINT64 *FdSize,
680 IN OUT EFI_PHYSICAL_ADDRESS *FixUp
681 )
949f388f 682{
683 if (Index >= gFdInfoCount) {
684 return EFI_UNSUPPORTED;
685 }
686
687 *FdBase = gFdInfo[Index].Address;
688 *FdSize = gFdInfo[Index].Size;
689 *FixUp = 0;
690
691 if (*FdBase == 0 && *FdSize == 0) {
692 return EFI_UNSUPPORTED;
693 }
694
695 if (Index == 0) {
696 //
697 // FD 0 has XIP code and well known PCD values
698 // If the memory buffer could not be allocated at the FD build address
699 // the Fixup is the difference.
700 //
701 *FixUp = *FdBase - PcdGet64 (PcdEmuFdBaseAddress);
702 }
703
704 return EFI_SUCCESS;
705}
706
949f388f 707
949f388f 708/*++
709
710Routine Description:
711 Count the number of seperators in String
712
713Arguments:
714 String - String to process
715 Seperator - Item to count
716
717Returns:
718 Number of Seperator in String
719
720**/
65e3f333 721UINTN
722CountSeperatorsInString (
723 IN const CHAR16 *String,
724 IN CHAR16 Seperator
725 )
949f388f 726{
727 UINTN Count;
728
729 for (Count = 0; *String != '\0'; String++) {
730 if (*String == Seperator) {
731 Count++;
732 }
733 }
734
735 return Count;
736}
737
738
0ede3853 739EFI_STATUS
740EFIAPI
741SecImageRead (
742 IN VOID *FileHandle,
743 IN UINTN FileOffset,
744 IN OUT UINTN *ReadSize,
745 OUT VOID *Buffer
746 )
747/*++
748
749Routine Description:
750 Support routine for the PE/COFF Loader that reads a buffer from a PE/COFF file
751
752Arguments:
753 FileHandle - The handle to the PE/COFF file
754 FileOffset - The offset, in bytes, into the file to read
755 ReadSize - The number of bytes to read from the file starting at FileOffset
756 Buffer - A pointer to the buffer to read the data into.
757
758Returns:
759 EFI_SUCCESS - ReadSize bytes of data were read into Buffer from the PE/COFF file starting at FileOffset
760
761**/
762{
763 CHAR8 *Destination8;
764 CHAR8 *Source8;
765 UINTN Length;
766
767 Destination8 = Buffer;
768 Source8 = (CHAR8 *) ((UINTN) FileHandle + FileOffset);
769 Length = *ReadSize;
770 while (Length--) {
771 *(Destination8++) = *(Source8++);
772 }
773
774 return EFI_SUCCESS;
775}
776
777
949f388f 778/*++
779
780Routine Description:
781 Store the ModHandle in an array indexed by the Pdb File name.
782 The ModHandle is needed to unload the image.
783
784Arguments:
785 ImageContext - Input data returned from PE Laoder Library. Used to find the
786 .PDB file name of the PE Image.
787 ModHandle - Returned from LoadLibraryEx() and stored for call to
788 FreeLibrary().
789
790Returns:
791 EFI_SUCCESS - ModHandle was stored.
792
793**/
65e3f333 794EFI_STATUS
795AddHandle (
796 IN PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext,
797 IN VOID *ModHandle
798 )
949f388f 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
949f388f 838/*++
839
840Routine Description:
841 Return the ModHandle and delete the entry in the array.
842
843Arguments:
844 ImageContext - Input data returned from PE Laoder Library. Used to find the
845 .PDB file name of the PE Image.
846
847Returns:
848 ModHandle - ModHandle assoicated with ImageContext is returned
849 NULL - No ModHandle associated with ImageContext
850
851**/
65e3f333 852VOID *
853RemoveHandle (
854 IN PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
855 )
949f388f 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
65e3f333 893// source SecMain.gdb
949f388f 894// c
895// end
896//
897VOID
898SecGdbScriptBreak (
899 VOID
900 )
901{
902}
903
904VOID
905SecUnixLoaderBreak (
906 VOID
907 )
908{
909}
910
911BOOLEAN
912IsPdbFile (
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
939void
940PrintLoadAddress (
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
963VOID
964EFIAPI
965SecPeCoffRelocateImageExtraAction (
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
65e3f333 1060 fprintf (
1061 stderr,
949f388f 1062 "Loading %s 0x%08lx - entry point 0x%08lx\n",
1063 ImageContext->PdbPointer,
1064 (unsigned long)ImageContext->ImageAddress,
65e3f333 1065 (unsigned long)ImageContext->EntryPoint
1066 );
949f388f 1067
1068 Handle = dlopen (ImageContext->PdbPointer, RTLD_NOW);
1069
1070 if (Handle) {
1071 Entry = dlsym (Handle, "_ModuleEntryPoint");
1072 } else {
1073 printf("%s\n", dlerror());
1074 }
1075
1076 if (Entry != NULL) {
1077 ImageContext->EntryPoint = (UINTN)Entry;
65e3f333 1078 printf ("Change %s Entrypoint to :0x%08lx\n", ImageContext->PdbPointer, (unsigned long)Entry);
949f388f 1079 }
1080
1081 SecUnixLoaderBreak ();
1082
1083#endif
1084
1085 return;
1086}
1087
1088
1089VOID
1090EFIAPI
1091SecPeCoffUnloadImageExtraAction (
1092 IN PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
1093 )
1094{
1095 VOID *Handle;
1096
1097 Handle = RemoveHandle (ImageContext);
1098
1099#ifdef __APPLE__
1100 FILE *GdbTempFile;
1101 BOOLEAN EnabledOnEntry;
1102
1103 if (Handle != NULL) {
1104 //
1105 // Need to skip .PDB files created from VC++
1106 //
1107 if (!IsPdbFile (ImageContext->PdbPointer)) {
1108 if (SecInterruptEanbled ()) {
1109 SecDisableInterrupt ();
1110 EnabledOnEntry = TRUE;
1111 } else {
1112 EnabledOnEntry = FALSE;
1113 }
1114
1115 //
1116 // Write the file we need for the gdb script
1117 //
1118 GdbTempFile = fopen (gGdbWorkingFileName, "w");
1119 if (GdbTempFile != NULL) {
1120 fprintf (GdbTempFile, "remove-symbol-file %s\n", ImageContext->PdbPointer);
1121 fclose (GdbTempFile);
1122
1123 //
1124 // Target for gdb breakpoint in a script that uses gGdbWorkingFileName to set a breakpoint.
1125 // Hey what can you say scripting in gdb is not that great....
1126 //
1127 SecGdbScriptBreak ();
1128 } else {
1129 ASSERT (FALSE);
1130 }
1131
1132 if (EnabledOnEntry) {
1133 SecEnableInterrupt ();
1134 }
1135 }
1136 }
1137
1138#else
1139 //
1140 // Don't want to confuse gdb with symbols for something that got unloaded
1141 //
1142 if (Handle != NULL) {
1143 dlclose (Handle);
1144 }
1145
1146#endif
1147 return;
1148}
1149
1150