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