]> git.proxmox.com Git - mirror_edk2.git/blame - InOsEmuPkg/Unix/Sec/SecMain.c
InOsEmuPkg/Unix/Sec: Fix EFIAPI usage inconsistencies
[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);
2b59fcd5 120 AddThunkProtocol (&gSnpThunkIo, (CHAR16 *)PcdGetPtr (PcdEmuNetworkInterface), TRUE);
033d0e5f 121
949f388f 122 //
123 // Emulator other Thunks
124 //
125 AddThunkProtocol (&gPthreadThunkIo, (CHAR16 *)PcdGetPtr (PcdEmuApCount), FALSE);
126
127 // EmuSecLibConstructor ();
65e3f333 128
65e3f333 129 gPpiList = GetThunkPpiList ();
130
949f388f 131
132#ifdef __APPLE__
133 //
134 // We can't use dlopen on OS X, so we need a scheme to get symboles into gdb
135 // We need to create a temp file that contains gdb commands so we can load
136 // symbols when we load every PE/COFF image.
137 //
138 Index = strlen (*Argv);
139 gGdbWorkingFileName = malloc (Index + strlen(".gdb") + 1);
140 strcpy (gGdbWorkingFileName, *Argv);
141 strcat (gGdbWorkingFileName, ".gdb");
142#endif
143
144
145 //
146 // Allocate space for gSystemMemory Array
147 //
148 gSystemMemoryCount = CountSeperatorsInString (MemorySizeStr, '!') + 1;
149 gSystemMemory = calloc (gSystemMemoryCount, sizeof (EMU_SYSTEM_MEMORY));
150 if (gSystemMemory == NULL) {
151 printf ("ERROR : Can not allocate memory for system. Exiting.\n");
152 exit (1);
153 }
154 //
155 // Allocate space for gSystemMemory Array
156 //
157 gFdInfoCount = CountSeperatorsInString (FirmwareVolumesStr, '!') + 1;
158 gFdInfo = calloc (gFdInfoCount, sizeof (EMU_FD_INFO));
159 if (gFdInfo == NULL) {
160 printf ("ERROR : Can not allocate memory for fd info. Exiting.\n");
161 exit (1);
162 }
163
164 printf (" BootMode 0x%02x\n", (unsigned int)PcdGet32 (PcdEmuBootMode));
165
166 //
65e3f333 167 // Open up a 128K file to emulate temp memory for SEC.
949f388f 168 // on a real platform this would be SRAM, or using the cache as RAM.
169 // Set InitialStackMemory to zero so UnixOpenFile will allocate a new mapping
170 //
171 InitialStackMemorySize = STACK_SIZE;
65e3f333 172 InitialStackMemory = (UINTN)MapMemory (
173 0, (UINT32) InitialStackMemorySize,
174 PROT_READ | PROT_WRITE | PROT_EXEC, MAP_ANONYMOUS | MAP_PRIVATE
175 );
949f388f 176 if (InitialStackMemory == 0) {
177 printf ("ERROR : Can not open SecStack Exiting\n");
178 exit (1);
179 }
180
65e3f333 181 printf (" OS Emulator passing in %u KB of temp RAM at 0x%08lx to SEC\n",
949f388f 182 (unsigned int)(InitialStackMemorySize / 1024),
65e3f333 183 (unsigned long)InitialStackMemory
184 );
949f388f 185
186 for (StackPointer = (UINTN*) (UINTN) InitialStackMemory;
187 StackPointer < (UINTN*)(UINTN)((UINTN) InitialStackMemory + (UINT64) InitialStackMemorySize);
188 StackPointer ++) {
189 *StackPointer = 0x5AA55AA5;
190 }
191
192 //
193 // Open All the firmware volumes and remember the info in the gFdInfo global
194 //
195 FileName = (CHAR8 *)malloc (StrLen (FirmwareVolumesStr) + 1);
196 if (FileName == NULL) {
197 printf ("ERROR : Can not allocate memory for firmware volume string\n");
198 exit (1);
199 }
200
201 Index2 = 0;
65e3f333 202 for (Done = FALSE, Index = 0, PeiIndex = 0, SecFile = NULL;
949f388f 203 FirmwareVolumesStr[Index2] != 0;
204 Index++) {
65e3f333 205 for (Index1 = 0; (FirmwareVolumesStr[Index2] != '!') && (FirmwareVolumesStr[Index2] != 0); Index2++) {
949f388f 206 FileName[Index1++] = FirmwareVolumesStr[Index2];
65e3f333 207 }
208 if (FirmwareVolumesStr[Index2] == '!') {
949f388f 209 Index2++;
65e3f333 210 }
949f388f 211 FileName[Index1] = '\0';
212
8052c4a2 213 if (Index == 0) {
214 // Map FV Recovery Read Only and other areas Read/Write
215 Status = MapFd0 (
216 FileName,
217 &gFdInfo[0].Address,
218 &gFdInfo[0].Size
219 );
220 } else {
221 //
222 // Open the FD and remmeber where it got mapped into our processes address space
223 // Maps Read Only
224 //
225 Status = MapFile (
226 FileName,
227 &gFdInfo[Index].Address,
228 &gFdInfo[Index].Size
229 );
230 }
949f388f 231 if (EFI_ERROR (Status)) {
232 printf ("ERROR : Can not open Firmware Device File %s (%x). Exiting.\n", FileName, (unsigned int)Status);
233 exit (1);
234 }
235
65e3f333 236 printf (" FD loaded from %s at 0x%08lx",FileName, (unsigned long)gFdInfo[Index].Address);
949f388f 237
65e3f333 238 if (SecFile == NULL) {
949f388f 239 //
65e3f333 240 // Assume the beginning of the FD is an FV and look for the SEC Core.
949f388f 241 // Load the first one we find.
242 //
65e3f333 243 FileHandle = NULL;
244 Status = PeiServicesFfsFindNextFile (
245 EFI_FV_FILETYPE_SECURITY_CORE,
246 (EFI_PEI_FV_HANDLE)(UINTN)gFdInfo[Index].Address,
247 &FileHandle
248 );
949f388f 249 if (!EFI_ERROR (Status)) {
65e3f333 250 Status = PeiServicesFfsFindSectionData (EFI_SECTION_PE32, FileHandle, &SecFile);
251 if (!EFI_ERROR (Status)) {
252 PeiIndex = Index;
253 printf (" contains SEC Core");
254 }
949f388f 255 }
256 }
257
258 printf ("\n");
259 }
260 //
261 // Calculate memory regions and store the information in the gSystemMemory
262 // global for later use. The autosizing code will use this data to
263 // map this memory into the SEC process memory space.
264 //
265 Index1 = 0;
266 Index = 0;
267 while (1) {
268 UINTN val = 0;
269 //
270 // Save the size of the memory.
271 //
272 while (MemorySizeStr[Index1] >= '0' && MemorySizeStr[Index1] <= '9') {
273 val = val * 10 + MemorySizeStr[Index1] - '0';
274 Index1++;
275 }
276 gSystemMemory[Index++].Size = val * 0x100000;
65e3f333 277 if (MemorySizeStr[Index1] == 0) {
949f388f 278 break;
65e3f333 279 }
949f388f 280 Index1++;
281 }
282
283 printf ("\n");
284
285 //
65e3f333 286 // Hand off to SEC
949f388f 287 //
65e3f333 288 SecLoadFromCore ((UINTN) InitialStackMemory, (UINTN) InitialStackMemorySize, (UINTN) gFdInfo[0].Address, SecFile);
949f388f 289
290 //
65e3f333 291 // If we get here, then the SEC Core returned. This is an error as SEC should
292 // always hand off to PEI Core and then on to DXE Core.
949f388f 293 //
65e3f333 294 printf ("ERROR : SEC returned\n");
949f388f 295 exit (1);
296}
297
65e3f333 298
949f388f 299EFI_PHYSICAL_ADDRESS *
300MapMemory (
bfa084fa 301 IN INTN fd,
302 IN UINT64 length,
303 IN INTN prot,
304 IN INTN flags
305 )
949f388f 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 (
112a857f 442 (void *)(UINTN)(FixedPcdGet64 (PcdEmuFlashFvRecoveryBase) + FvSize),
8052c4a2 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
65e3f333 598SecUnixPeiAutoScan (
599 IN UINTN Index,
600 OUT EFI_PHYSICAL_ADDRESS *MemoryBase,
601 OUT UINT64 *MemorySize
602 )
949f388f 603{
604 void *res;
605
606 if (Index >= gSystemMemoryCount) {
607 return EFI_UNSUPPORTED;
608 }
609
610 *MemoryBase = 0;
65e3f333 611 res = MapMemory (
612 0, gSystemMemory[Index].Size,
613 PROT_READ | PROT_WRITE | PROT_EXEC,
614 MAP_PRIVATE | MAP_ANONYMOUS
615 );
616 if (res == MAP_FAILED) {
949f388f 617 return EFI_DEVICE_ERROR;
65e3f333 618 }
949f388f 619 *MemorySize = gSystemMemory[Index].Size;
620 *MemoryBase = (UINTN)res;
621 gSystemMemory[Index].Memory = *MemoryBase;
622
623 return EFI_SUCCESS;
624}
625
65e3f333 626
949f388f 627/*++
628
629Routine Description:
630 Since the SEC is the only Unix program in stack it must export
631 an interface to do POSIX calls. gUnix is initailized in UnixThunk.c.
632
633Arguments:
634 InterfaceSize - sizeof (EFI_WIN_NT_THUNK_PROTOCOL);
635 InterfaceBase - Address of the gUnix global
636
637Returns:
638 EFI_SUCCESS - Data returned
639
640**/
65e3f333 641VOID *
65e3f333 642SecEmuThunkAddress (
643 VOID
644 )
949f388f 645{
646 return &gEmuThunkProtocol;
647}
648
649
949f388f 650
651RETURN_STATUS
652EFIAPI
653SecPeCoffGetEntryPoint (
654 IN VOID *Pe32Data,
655 IN OUT VOID **EntryPoint
656 )
657{
65e3f333 658 EFI_STATUS Status;
659 PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;
0ede3853 660
661 ZeroMem (&ImageContext, sizeof (ImageContext));
662 ImageContext.Handle = Pe32Data;
663 ImageContext.ImageRead = (PE_COFF_LOADER_READ_FILE) SecImageRead;
664
665 Status = PeCoffLoaderGetImageInfo (&ImageContext);
666 if (EFI_ERROR (Status)) {
667 return Status;
668 }
669
946bfba2 670 if (ImageContext.ImageAddress != (UINTN)Pe32Data) {
e7523e06 671 //
672 // Relocate image to match the address where it resides
673 //
674 ImageContext.ImageAddress = (UINTN)Pe32Data;
675 Status = PeCoffLoaderLoadImage (&ImageContext);
676 if (EFI_ERROR (Status)) {
677 return Status;
678 }
949f388f 679
e7523e06 680 Status = PeCoffLoaderRelocateImage (&ImageContext);
681 if (EFI_ERROR (Status)) {
682 return Status;
683 }
946bfba2 684 } else {
685 //
686 // Or just return image entry point
687 //
688 ImageContext.PdbPointer = PeCoffLoaderGetPdbPointer (Pe32Data);
689 Status = PeCoffLoaderGetEntryPoint (Pe32Data, EntryPoint);
690 if (EFI_ERROR (Status)) {
691 return Status;
692 }
693 ImageContext.EntryPoint = (UINTN)*EntryPoint;
694 }
949f388f 695
65e3f333 696 // On Unix a dlopen is done that will change the entry point
697 SecPeCoffRelocateImageExtraAction (&ImageContext);
698 *EntryPoint = (VOID *)(UINTN)ImageContext.EntryPoint;
699
949f388f 700 return Status;
701}
702
703
704
949f388f 705/*++
706
707Routine Description:
708 Return the FD Size and base address. Since the FD is loaded from a
709 file into host memory only the SEC will know it's address.
710
711Arguments:
712 Index - Which FD, starts at zero.
713 FdSize - Size of the FD in bytes
714 FdBase - Start address of the FD. Assume it points to an FV Header
715 FixUp - Difference between actual FD address and build address
716
717Returns:
718 EFI_SUCCESS - Return the Base address and size of the FV
719 EFI_UNSUPPORTED - Index does nto map to an FD in the system
720
721**/
65e3f333 722EFI_STATUS
65e3f333 723SecUnixFdAddress (
724 IN UINTN Index,
725 IN OUT EFI_PHYSICAL_ADDRESS *FdBase,
726 IN OUT UINT64 *FdSize,
727 IN OUT EFI_PHYSICAL_ADDRESS *FixUp
728 )
949f388f 729{
730 if (Index >= gFdInfoCount) {
731 return EFI_UNSUPPORTED;
732 }
733
734 *FdBase = gFdInfo[Index].Address;
735 *FdSize = gFdInfo[Index].Size;
736 *FixUp = 0;
737
738 if (*FdBase == 0 && *FdSize == 0) {
739 return EFI_UNSUPPORTED;
740 }
741
742 if (Index == 0) {
743 //
744 // FD 0 has XIP code and well known PCD values
745 // If the memory buffer could not be allocated at the FD build address
746 // the Fixup is the difference.
747 //
748 *FixUp = *FdBase - PcdGet64 (PcdEmuFdBaseAddress);
749 }
750
751 return EFI_SUCCESS;
752}
753
949f388f 754
949f388f 755/*++
756
757Routine Description:
758 Count the number of seperators in String
759
760Arguments:
761 String - String to process
762 Seperator - Item to count
763
764Returns:
765 Number of Seperator in String
766
767**/
65e3f333 768UINTN
769CountSeperatorsInString (
770 IN const CHAR16 *String,
771 IN CHAR16 Seperator
772 )
949f388f 773{
774 UINTN Count;
775
776 for (Count = 0; *String != '\0'; String++) {
777 if (*String == Seperator) {
778 Count++;
779 }
780 }
781
782 return Count;
783}
784
785
0ede3853 786EFI_STATUS
7af94c1d 787EFIAPI
0ede3853 788SecImageRead (
789 IN VOID *FileHandle,
790 IN UINTN FileOffset,
791 IN OUT UINTN *ReadSize,
792 OUT VOID *Buffer
793 )
794/*++
795
796Routine Description:
797 Support routine for the PE/COFF Loader that reads a buffer from a PE/COFF file
798
799Arguments:
800 FileHandle - The handle to the PE/COFF file
801 FileOffset - The offset, in bytes, into the file to read
802 ReadSize - The number of bytes to read from the file starting at FileOffset
803 Buffer - A pointer to the buffer to read the data into.
804
805Returns:
806 EFI_SUCCESS - ReadSize bytes of data were read into Buffer from the PE/COFF file starting at FileOffset
807
808**/
809{
810 CHAR8 *Destination8;
811 CHAR8 *Source8;
812 UINTN Length;
813
814 Destination8 = Buffer;
815 Source8 = (CHAR8 *) ((UINTN) FileHandle + FileOffset);
816 Length = *ReadSize;
817 while (Length--) {
818 *(Destination8++) = *(Source8++);
819 }
820
821 return EFI_SUCCESS;
822}
823
824
949f388f 825/*++
826
827Routine Description:
828 Store the ModHandle in an array indexed by the Pdb File name.
829 The ModHandle is needed to unload the image.
830
831Arguments:
832 ImageContext - Input data returned from PE Laoder Library. Used to find the
833 .PDB file name of the PE Image.
834 ModHandle - Returned from LoadLibraryEx() and stored for call to
835 FreeLibrary().
836
837Returns:
838 EFI_SUCCESS - ModHandle was stored.
839
840**/
65e3f333 841EFI_STATUS
842AddHandle (
843 IN PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext,
844 IN VOID *ModHandle
845 )
949f388f 846{
847 UINTN Index;
848 IMAGE_CONTEXT_TO_MOD_HANDLE *Array;
849 UINTN PreviousSize;
850
851
852 Array = mImageContextModHandleArray;
853 for (Index = 0; Index < mImageContextModHandleArraySize; Index++, Array++) {
854 if (Array->ImageContext == NULL) {
855 //
856 // Make a copy of the stirng and store the ModHandle
857 //
858 Array->ImageContext = ImageContext;
859 Array->ModHandle = ModHandle;
860 return EFI_SUCCESS;
861 }
862 }
863
864 //
865 // No free space in mImageContextModHandleArray so grow it by
866 // IMAGE_CONTEXT_TO_MOD_HANDLE entires. realloc will
867 // copy the old values to the new locaiton. But it does
868 // not zero the new memory area.
869 //
870 PreviousSize = mImageContextModHandleArraySize * sizeof (IMAGE_CONTEXT_TO_MOD_HANDLE);
871 mImageContextModHandleArraySize += MAX_IMAGE_CONTEXT_TO_MOD_HANDLE_ARRAY_SIZE;
872
873 mImageContextModHandleArray = realloc (mImageContextModHandleArray, mImageContextModHandleArraySize * sizeof (IMAGE_CONTEXT_TO_MOD_HANDLE));
874 if (mImageContextModHandleArray == NULL) {
875 ASSERT (FALSE);
876 return EFI_OUT_OF_RESOURCES;
877 }
878
879 memset (mImageContextModHandleArray + PreviousSize, 0, MAX_IMAGE_CONTEXT_TO_MOD_HANDLE_ARRAY_SIZE * sizeof (IMAGE_CONTEXT_TO_MOD_HANDLE));
880
881 return AddHandle (ImageContext, ModHandle);
882}
883
884
949f388f 885/*++
886
887Routine Description:
888 Return the ModHandle and delete the entry in the array.
889
890Arguments:
891 ImageContext - Input data returned from PE Laoder Library. Used to find the
892 .PDB file name of the PE Image.
893
894Returns:
895 ModHandle - ModHandle assoicated with ImageContext is returned
896 NULL - No ModHandle associated with ImageContext
897
898**/
65e3f333 899VOID *
900RemoveHandle (
901 IN PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
902 )
949f388f 903{
904 UINTN Index;
905 IMAGE_CONTEXT_TO_MOD_HANDLE *Array;
906
907 if (ImageContext->PdbPointer == NULL) {
908 //
909 // If no PDB pointer there is no ModHandle so return NULL
910 //
911 return NULL;
912 }
913
914 Array = mImageContextModHandleArray;
915 for (Index = 0; Index < mImageContextModHandleArraySize; Index++, Array++) {
916 if (Array->ImageContext == ImageContext) {
917 //
918 // If you find a match return it and delete the entry
919 //
920 Array->ImageContext = NULL;
921 return Array->ModHandle;
922 }
923 }
924
925 return NULL;
926}
927
928
929
930//
931// Target for gdb breakpoint in a script that uses gGdbWorkingFileName to source a
932// add-symbol-file command. Hey what can you say scripting in gdb is not that great....
933//
934// Put .gdbinit in the CWD where you do gdb SecMain.dll for source level debug
935//
936// cat .gdbinit
937// b SecGdbScriptBreak
938// command
939// silent
65e3f333 940// source SecMain.gdb
949f388f 941// c
942// end
943//
944VOID
945SecGdbScriptBreak (
946 VOID
947 )
948{
949}
950
951VOID
952SecUnixLoaderBreak (
953 VOID
954 )
955{
956}
957
958BOOLEAN
959IsPdbFile (
960 IN CHAR8 *PdbFileName
961 )
962{
963 UINTN Len;
964
965 if (PdbFileName == NULL) {
966 return FALSE;
967 }
968
969 Len = strlen (PdbFileName);
970 if ((Len < 5)|| (PdbFileName[Len - 4] != '.')) {
971 return FALSE;
972 }
973
974 if ((PdbFileName[Len - 3] == 'P' || PdbFileName[Len - 3] == 'p') &&
975 (PdbFileName[Len - 2] == 'D' || PdbFileName[Len - 2] == 'd') &&
976 (PdbFileName[Len - 1] == 'B' || PdbFileName[Len - 1] == 'b')) {
977 return TRUE;
978 }
979
980 return FALSE;
981}
982
983
984#define MAX_SPRINT_BUFFER_SIZE 0x200
985
986void
987PrintLoadAddress (
988 IN PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
989 )
990{
991 if (ImageContext->PdbPointer == NULL) {
992 fprintf (stderr,
993 "0x%08lx Loading NO DEBUG with entry point 0x%08lx\n",
994 (unsigned long)(ImageContext->ImageAddress),
995 (unsigned long)ImageContext->EntryPoint
996 );
997 } else {
998 fprintf (stderr,
999 "0x%08lx Loading %s with entry point 0x%08lx\n",
1000 (unsigned long)(ImageContext->ImageAddress + ImageContext->SizeOfHeaders),
1001 ImageContext->PdbPointer,
1002 (unsigned long)ImageContext->EntryPoint
1003 );
1004 }
1005 // Keep output synced up
1006 fflush (stderr);
1007}
1008
1009
1010VOID
1011EFIAPI
1012SecPeCoffRelocateImageExtraAction (
1013 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
1014 )
1015{
1016
1017#ifdef __APPLE__
1018 BOOLEAN EnabledOnEntry;
1019
1020 //
1021 // Make sure writting of the file is an atomic operation
1022 //
1023 if (SecInterruptEanbled ()) {
1024 SecDisableInterrupt ();
1025 EnabledOnEntry = TRUE;
1026 } else {
1027 EnabledOnEntry = FALSE;
1028 }
1029
1030 PrintLoadAddress (ImageContext);
1031
1032 //
1033 // In mach-o (OS X executable) dlopen() can only load files in the MH_DYLIB of MH_BUNDLE format.
1034 // To convert to PE/COFF we need to construct a mach-o with the MH_PRELOAD format. We create
1035 // .dSYM files for the PE/COFF images that can be used by gdb for source level debugging.
1036 //
1037 FILE *GdbTempFile;
1038
1039 //
1040 // In the Mach-O to PE/COFF conversion the size of the PE/COFF headers is not accounted for.
1041 // Thus we need to skip over the PE/COFF header when giving load addresses for our symbol table.
1042 //
1043 if (ImageContext->PdbPointer != NULL && !IsPdbFile (ImageContext->PdbPointer)) {
1044 //
1045 // Now we have a database of the images that are currently loaded
1046 //
1047
1048 //
1049 // 'symbol-file' will clear out currnet symbol mappings in gdb.
1050 // you can do a 'add-symbol-file filename address' for every image we loaded to get source
1051 // level debug in gdb. Note Sec, being a true application will work differently.
1052 //
1053 // We add the PE/COFF header size into the image as the mach-O does not have a header in
1054 // loaded into system memory.
1055 //
1056 // This gives us a data base of gdb commands and after something is unloaded that entry will be
1057 // removed. We don't yet have the scheme of how to comunicate with gdb, but we have the
1058 // data base of info ready to roll.
1059 //
1060 // We could use qXfer:libraries:read, but OS X GDB does not currently support it.
1061 // <library-list>
1062 // <library name="/lib/libc.so.6"> // ImageContext->PdbPointer
1063 // <segment address="0x10000000"/> // ImageContext->ImageAddress + ImageContext->SizeOfHeaders
1064 // </library>
1065 // </library-list>
1066 //
1067
1068 //
1069 // Write the file we need for the gdb script
1070 //
1071 GdbTempFile = fopen (gGdbWorkingFileName, "w");
1072 if (GdbTempFile != NULL) {
1073 fprintf (GdbTempFile, "add-symbol-file %s 0x%08lx\n", ImageContext->PdbPointer, (long unsigned int)(ImageContext->ImageAddress + ImageContext->SizeOfHeaders));
1074 fclose (GdbTempFile);
1075
1076 //
1077 // Target for gdb breakpoint in a script that uses gGdbWorkingFileName to set a breakpoint.
1078 // Hey what can you say scripting in gdb is not that great....
1079 //
1080 SecGdbScriptBreak ();
1081 } else {
1082 ASSERT (FALSE);
1083 }
1084
1085 AddHandle (ImageContext, ImageContext->PdbPointer);
1086
1087 if (EnabledOnEntry) {
1088 SecEnableInterrupt ();
1089 }
1090
1091
1092 }
1093
1094#else
1095
1096 void *Handle = NULL;
1097 void *Entry = NULL;
1098
1099 if (ImageContext->PdbPointer == NULL) {
1100 return;
1101 }
1102
1103 if (!IsPdbFile (ImageContext->PdbPointer)) {
1104 return;
1105 }
1106
65e3f333 1107 fprintf (
1108 stderr,
949f388f 1109 "Loading %s 0x%08lx - entry point 0x%08lx\n",
1110 ImageContext->PdbPointer,
1111 (unsigned long)ImageContext->ImageAddress,
65e3f333 1112 (unsigned long)ImageContext->EntryPoint
1113 );
949f388f 1114
1115 Handle = dlopen (ImageContext->PdbPointer, RTLD_NOW);
1116
1117 if (Handle) {
1118 Entry = dlsym (Handle, "_ModuleEntryPoint");
1119 } else {
1120 printf("%s\n", dlerror());
1121 }
1122
1123 if (Entry != NULL) {
1124 ImageContext->EntryPoint = (UINTN)Entry;
65e3f333 1125 printf ("Change %s Entrypoint to :0x%08lx\n", ImageContext->PdbPointer, (unsigned long)Entry);
949f388f 1126 }
1127
1128 SecUnixLoaderBreak ();
1129
1130#endif
1131
1132 return;
1133}
1134
1135
1136VOID
1137EFIAPI
1138SecPeCoffUnloadImageExtraAction (
1139 IN PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
1140 )
1141{
1142 VOID *Handle;
1143
1144 Handle = RemoveHandle (ImageContext);
1145
1146#ifdef __APPLE__
1147 FILE *GdbTempFile;
1148 BOOLEAN EnabledOnEntry;
1149
1150 if (Handle != NULL) {
1151 //
1152 // Need to skip .PDB files created from VC++
1153 //
1154 if (!IsPdbFile (ImageContext->PdbPointer)) {
1155 if (SecInterruptEanbled ()) {
1156 SecDisableInterrupt ();
1157 EnabledOnEntry = TRUE;
1158 } else {
1159 EnabledOnEntry = FALSE;
1160 }
1161
1162 //
1163 // Write the file we need for the gdb script
1164 //
1165 GdbTempFile = fopen (gGdbWorkingFileName, "w");
1166 if (GdbTempFile != NULL) {
1167 fprintf (GdbTempFile, "remove-symbol-file %s\n", ImageContext->PdbPointer);
1168 fclose (GdbTempFile);
1169
1170 //
1171 // Target for gdb breakpoint in a script that uses gGdbWorkingFileName to set a breakpoint.
1172 // Hey what can you say scripting in gdb is not that great....
1173 //
1174 SecGdbScriptBreak ();
1175 } else {
1176 ASSERT (FALSE);
1177 }
1178
1179 if (EnabledOnEntry) {
1180 SecEnableInterrupt ();
1181 }
1182 }
1183 }
1184
1185#else
1186 //
1187 // Don't want to confuse gdb with symbols for something that got unloaded
1188 //
1189 if (Handle != NULL) {
1190 dlclose (Handle);
1191 }
1192
1193#endif
1194 return;
1195}
1196
1197