]> git.proxmox.com Git - mirror_edk2.git/blame - EmulatorPkg/Unix/Host/Host.c
Add an error print and exit if SEC core is not found.
[mirror_edk2.git] / EmulatorPkg / Unix / Host / Host.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
59ad461d 15#include "Host.h"
949f388f 16
17#ifdef __APPLE__
18#define MAP_ANONYMOUS MAP_ANON
949f388f 19#endif
20
21
22//
23// Globals
24//
25
26EMU_THUNK_PPI mSecEmuThunkPpi = {
27 GasketSecUnixPeiAutoScan,
28 GasketSecUnixFdAddress,
65e3f333 29 GasketSecEmuThunkAddress
949f388f 30};
31
0bc9421b 32char *gGdbWorkingFileName = NULL;
febb2276 33unsigned int mScriptSymbolChangesCount = 0;
949f388f 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
f70c2a12 62
63int gInXcode = 0;
64
65
66/*++
67 Breakpoint target for Xcode project. Set in the Xcode XML
d18d8a1d 68
59ad461d 69 Xcode breakpoint will 'source Host.gdb'
70 gGdbWorkingFileName is set to Host.gdb
f70c2a12 71
72**/
73VOID
74SecGdbConfigBreak (
75 VOID
76 )
77{
78}
79
80
81
949f388f 82/*++
83
84Routine Description:
85 Main entry point to SEC for Unix. This is a unix program
86
87Arguments:
88 Argc - Number of command line arguments
89 Argv - Array of command line argument strings
90 Envp - Array of environmemt variable strings
91
92Returns:
93 0 - Normal exit
94 1 - Abnormal exit
95
96**/
65e3f333 97int
98main (
99 IN int Argc,
100 IN char **Argv,
101 IN char **Envp
102 )
949f388f 103{
104 EFI_STATUS Status;
105 EFI_PHYSICAL_ADDRESS InitialStackMemory;
106 UINT64 InitialStackMemorySize;
107 UINTN Index;
108 UINTN Index1;
109 UINTN Index2;
110 UINTN PeiIndex;
111 CHAR8 *FileName;
112 BOOLEAN Done;
65e3f333 113 EFI_PEI_FILE_HANDLE FileHandle;
114 VOID *SecFile;
949f388f 115 CHAR16 *MemorySizeStr;
116 CHAR16 *FirmwareVolumesStr;
117 UINTN *StackPointer;
0bc9421b 118 FILE *GdbTempFile;
d18d8a1d 119
f70c2a12 120 //
d18d8a1d 121 // Xcode does not support sourcing gdb scripts directly, so the Xcode XML
f70c2a12 122 // has a break point script to source the GdbRun script.
123 //
124 SecGdbConfigBreak ();
d18d8a1d 125
f70c2a12 126 //
127 // If dlopen doesn't work, then we build a gdb script to allow the
128 // symbols to be loaded.
129 //
130 Index = strlen (*Argv);
131 gGdbWorkingFileName = AllocatePool (Index + strlen(".gdb") + 1);
132 strcpy (gGdbWorkingFileName, *Argv);
133 strcat (gGdbWorkingFileName, ".gdb");
134
135 //
136 // Empty out the gdb symbols script file.
137 //
138 GdbTempFile = fopen (gGdbWorkingFileName, "w");
139 if (GdbTempFile != NULL) {
140 fclose (GdbTempFile);
141 }
949f388f 142
f70c2a12 143 printf ("\nEDK II UNIX Host Emulation Environment from edk2.sourceforge.net\n");
d18d8a1d 144
65e3f333 145 setbuf (stdout, 0);
146 setbuf (stderr, 0);
949f388f 147
148 MemorySizeStr = (CHAR16 *) PcdGetPtr (PcdEmuMemorySize);
149 FirmwareVolumesStr = (CHAR16 *) PcdGetPtr (PcdEmuFirmwareVolume);
150
949f388f 151 //
152 // PPIs pased into PEI_CORE
153 //
949f388f 154 AddThunkPpi (EFI_PEI_PPI_DESCRIPTOR_PPI, &gEmuThunkPpiGuid, &mSecEmuThunkPpi);
949f388f 155
156 SecInitThunkProtocol ();
d18d8a1d 157
949f388f 158 //
159 // Emulator Bus Driver Thunks
160 //
d18d8a1d 161 AddThunkProtocol (&gX11ThunkIo, (CHAR16 *)PcdGetPtr (PcdEmuGop), TRUE);
162 AddThunkProtocol (&gPosixFileSystemThunkIo, (CHAR16 *)PcdGetPtr (PcdEmuFileSystem), TRUE);
163 AddThunkProtocol (&gBlockIoThunkIo, (CHAR16 *)PcdGetPtr (PcdEmuVirtualDisk), TRUE);
164 AddThunkProtocol (&gSnpThunkIo, (CHAR16 *)PcdGetPtr (PcdEmuNetworkInterface), TRUE);
033d0e5f 165
949f388f 166 //
167 // Emulator other Thunks
168 //
d18d8a1d 169 AddThunkProtocol (&gPthreadThunkIo, (CHAR16 *)PcdGetPtr (PcdEmuApCount), FALSE);
949f388f 170
171 // EmuSecLibConstructor ();
d18d8a1d 172
173 gPpiList = GetThunkPpiList ();
65e3f333 174
949f388f 175 //
176 // Allocate space for gSystemMemory Array
177 //
178 gSystemMemoryCount = CountSeperatorsInString (MemorySizeStr, '!') + 1;
b8800fc5 179 gSystemMemory = AllocateZeroPool (gSystemMemoryCount * sizeof (EMU_SYSTEM_MEMORY));
949f388f 180 if (gSystemMemory == NULL) {
181 printf ("ERROR : Can not allocate memory for system. Exiting.\n");
182 exit (1);
183 }
184 //
185 // Allocate space for gSystemMemory Array
186 //
187 gFdInfoCount = CountSeperatorsInString (FirmwareVolumesStr, '!') + 1;
b8800fc5 188 gFdInfo = AllocateZeroPool (gFdInfoCount * sizeof (EMU_FD_INFO));
949f388f 189 if (gFdInfo == NULL) {
190 printf ("ERROR : Can not allocate memory for fd info. Exiting.\n");
191 exit (1);
192 }
193
194 printf (" BootMode 0x%02x\n", (unsigned int)PcdGet32 (PcdEmuBootMode));
195
196 //
65e3f333 197 // Open up a 128K file to emulate temp memory for SEC.
949f388f 198 // on a real platform this would be SRAM, or using the cache as RAM.
199 // Set InitialStackMemory to zero so UnixOpenFile will allocate a new mapping
200 //
201 InitialStackMemorySize = STACK_SIZE;
65e3f333 202 InitialStackMemory = (UINTN)MapMemory (
203 0, (UINT32) InitialStackMemorySize,
204 PROT_READ | PROT_WRITE | PROT_EXEC, MAP_ANONYMOUS | MAP_PRIVATE
205 );
949f388f 206 if (InitialStackMemory == 0) {
207 printf ("ERROR : Can not open SecStack Exiting\n");
208 exit (1);
209 }
210
65e3f333 211 printf (" OS Emulator passing in %u KB of temp RAM at 0x%08lx to SEC\n",
949f388f 212 (unsigned int)(InitialStackMemorySize / 1024),
65e3f333 213 (unsigned long)InitialStackMemory
214 );
949f388f 215
216 for (StackPointer = (UINTN*) (UINTN) InitialStackMemory;
217 StackPointer < (UINTN*)(UINTN)((UINTN) InitialStackMemory + (UINT64) InitialStackMemorySize);
218 StackPointer ++) {
219 *StackPointer = 0x5AA55AA5;
220 }
221
222 //
223 // Open All the firmware volumes and remember the info in the gFdInfo global
224 //
b8800fc5 225 FileName = (CHAR8 *) AllocatePool (StrLen (FirmwareVolumesStr) + 1);
949f388f 226 if (FileName == NULL) {
227 printf ("ERROR : Can not allocate memory for firmware volume string\n");
228 exit (1);
229 }
230
231 Index2 = 0;
65e3f333 232 for (Done = FALSE, Index = 0, PeiIndex = 0, SecFile = NULL;
949f388f 233 FirmwareVolumesStr[Index2] != 0;
234 Index++) {
65e3f333 235 for (Index1 = 0; (FirmwareVolumesStr[Index2] != '!') && (FirmwareVolumesStr[Index2] != 0); Index2++) {
949f388f 236 FileName[Index1++] = FirmwareVolumesStr[Index2];
65e3f333 237 }
238 if (FirmwareVolumesStr[Index2] == '!') {
949f388f 239 Index2++;
65e3f333 240 }
949f388f 241 FileName[Index1] = '\0';
242
8052c4a2 243 if (Index == 0) {
244 // Map FV Recovery Read Only and other areas Read/Write
245 Status = MapFd0 (
246 FileName,
247 &gFdInfo[0].Address,
248 &gFdInfo[0].Size
249 );
250 } else {
251 //
252 // Open the FD and remmeber where it got mapped into our processes address space
253 // Maps Read Only
254 //
255 Status = MapFile (
256 FileName,
257 &gFdInfo[Index].Address,
258 &gFdInfo[Index].Size
259 );
260 }
949f388f 261 if (EFI_ERROR (Status)) {
262 printf ("ERROR : Can not open Firmware Device File %s (%x). Exiting.\n", FileName, (unsigned int)Status);
263 exit (1);
264 }
265
65e3f333 266 printf (" FD loaded from %s at 0x%08lx",FileName, (unsigned long)gFdInfo[Index].Address);
949f388f 267
65e3f333 268 if (SecFile == NULL) {
949f388f 269 //
65e3f333 270 // Assume the beginning of the FD is an FV and look for the SEC Core.
949f388f 271 // Load the first one we find.
272 //
65e3f333 273 FileHandle = NULL;
274 Status = PeiServicesFfsFindNextFile (
d18d8a1d 275 EFI_FV_FILETYPE_SECURITY_CORE,
276 (EFI_PEI_FV_HANDLE)(UINTN)gFdInfo[Index].Address,
65e3f333 277 &FileHandle
278 );
949f388f 279 if (!EFI_ERROR (Status)) {
65e3f333 280 Status = PeiServicesFfsFindSectionData (EFI_SECTION_PE32, FileHandle, &SecFile);
281 if (!EFI_ERROR (Status)) {
282 PeiIndex = Index;
283 printf (" contains SEC Core");
284 }
949f388f 285 }
286 }
287
288 printf ("\n");
289 }
9cf20bbf 290
291 if (SecFile == NULL) {
292 printf ("ERROR : SEC not found!\n");
293 exit (1);
294 }
295
949f388f 296 //
297 // Calculate memory regions and store the information in the gSystemMemory
298 // global for later use. The autosizing code will use this data to
299 // map this memory into the SEC process memory space.
300 //
301 Index1 = 0;
302 Index = 0;
303 while (1) {
304 UINTN val = 0;
305 //
306 // Save the size of the memory.
307 //
308 while (MemorySizeStr[Index1] >= '0' && MemorySizeStr[Index1] <= '9') {
309 val = val * 10 + MemorySizeStr[Index1] - '0';
310 Index1++;
311 }
312 gSystemMemory[Index++].Size = val * 0x100000;
65e3f333 313 if (MemorySizeStr[Index1] == 0) {
949f388f 314 break;
65e3f333 315 }
949f388f 316 Index1++;
317 }
318
319 printf ("\n");
320
321 //
65e3f333 322 // Hand off to SEC
949f388f 323 //
65e3f333 324 SecLoadFromCore ((UINTN) InitialStackMemory, (UINTN) InitialStackMemorySize, (UINTN) gFdInfo[0].Address, SecFile);
949f388f 325
326 //
65e3f333 327 // If we get here, then the SEC Core returned. This is an error as SEC should
328 // always hand off to PEI Core and then on to DXE Core.
949f388f 329 //
65e3f333 330 printf ("ERROR : SEC returned\n");
949f388f 331 exit (1);
332}
333
65e3f333 334
949f388f 335EFI_PHYSICAL_ADDRESS *
336MapMemory (
bfa084fa 337 IN INTN fd,
338 IN UINT64 length,
339 IN INTN prot,
340 IN INTN flags
341 )
949f388f 342{
343 STATIC UINTN base = 0x40000000;
344 CONST UINTN align = (1 << 24);
345 VOID *res = NULL;
346 BOOLEAN isAligned = 0;
347
348 //
349 // Try to get an aligned block somewhere in the address space of this
350 // process.
351 //
352 while((!isAligned) && (base != 0)) {
353 res = mmap ((void *)base, length, prot, flags, fd, 0);
354 if (res == MAP_FAILED) {
355 return NULL;
356 }
357 if ((((UINTN)res) & ~(align-1)) == (UINTN)res) {
358 isAligned=1;
65e3f333 359 } else {
949f388f 360 munmap(res, length);
361 base += align;
362 }
363 }
364 return res;
365}
366
65e3f333 367
949f388f 368/*++
369
370Routine Description:
371 Opens and memory maps a file using Unix services. If BaseAddress is non zero
372 the process will try and allocate the memory starting at BaseAddress.
373
374Arguments:
375 FileName - The name of the file to open and map
376 MapSize - The amount of the file to map in bytes
377 CreationDisposition - The flags to pass to CreateFile(). Use to create new files for
378 memory emulation, and exiting files for firmware volume emulation
379 BaseAddress - The base address of the mapped file in the user address space.
380 If passed in as NULL the a new memory region is used.
381 If passed in as non NULL the request memory region is used for
382 the mapping of the file into the process space.
383 Length - The size of the mapped region in bytes
384
385Returns:
386 EFI_SUCCESS - The file was opened and mapped.
387 EFI_NOT_FOUND - FileName was not found in the current directory
388 EFI_DEVICE_ERROR - An error occured attempting to map the opened file
389
390**/
65e3f333 391EFI_STATUS
392MapFile (
393 IN CHAR8 *FileName,
394 IN OUT EFI_PHYSICAL_ADDRESS *BaseAddress,
395 OUT UINT64 *Length
396 )
949f388f 397{
8052c4a2 398 int fd;
949f388f 399 VOID *res;
400 UINTN FileSize;
401
7e284acb 402 fd = open (FileName, O_RDWR);
65e3f333 403 if (fd < 0) {
949f388f 404 return EFI_NOT_FOUND;
65e3f333 405 }
949f388f 406 FileSize = lseek (fd, 0, SEEK_END);
407
408
946bfba2 409 res = MapMemory (fd, FileSize, PROT_READ | PROT_EXEC, MAP_PRIVATE);
949f388f 410
411 close (fd);
412
7e284acb 413 if (res == NULL) {
414 perror ("MapFile() Failed");
949f388f 415 return EFI_DEVICE_ERROR;
65e3f333 416 }
d18d8a1d 417
949f388f 418 *Length = (UINT64) FileSize;
419 *BaseAddress = (EFI_PHYSICAL_ADDRESS) (UINTN) res;
420
421 return EFI_SUCCESS;
422}
423
8052c4a2 424EFI_STATUS
425MapFd0 (
426 IN CHAR8 *FileName,
427 IN OUT EFI_PHYSICAL_ADDRESS *BaseAddress,
428 OUT UINT64 *Length
429 )
430{
431 int fd;
946bfba2 432 void *res, *res2, *res3;
8052c4a2 433 UINTN FileSize;
434 UINTN FvSize;
946bfba2 435 void *EmuMagicPage;
8052c4a2 436
437 fd = open (FileName, O_RDWR);
438 if (fd < 0) {
439 return EFI_NOT_FOUND;
440 }
441 FileSize = lseek (fd, 0, SEEK_END);
d18d8a1d 442
8052c4a2 443 FvSize = FixedPcdGet64 (PcdEmuFlashFvRecoverySize);
444
445 // Assume start of FD is Recovery FV, and make it write protected
446 res = mmap (
d18d8a1d 447 (void *)(UINTN)FixedPcdGet64 (PcdEmuFlashFvRecoveryBase),
448 FvSize,
449 PROT_READ | PROT_EXEC,
450 MAP_PRIVATE,
451 fd,
8052c4a2 452 0
453 );
454 if (res == MAP_FAILED) {
946bfba2 455 perror ("MapFd0() Failed res =");
8052c4a2 456 close (fd);
457 return EFI_DEVICE_ERROR;
946bfba2 458 } else if (res != (void *)(UINTN)FixedPcdGet64 (PcdEmuFlashFvRecoveryBase)) {
459 // We could not load at the build address, so we need to allow writes
460 munmap (res, FvSize);
461 res = mmap (
d18d8a1d 462 (void *)(UINTN)FixedPcdGet64 (PcdEmuFlashFvRecoveryBase),
463 FvSize,
464 PROT_READ | PROT_WRITE | PROT_EXEC,
465 MAP_PRIVATE,
466 fd,
946bfba2 467 0
468 );
469 if (res == MAP_FAILED) {
470 perror ("MapFd0() Failed res =");
471 close (fd);
472 return EFI_DEVICE_ERROR;
473 }
8052c4a2 474 }
d18d8a1d 475
8052c4a2 476 // Map the rest of the FD as read/write
477 res2 = mmap (
d18d8a1d 478 (void *)(UINTN)(FixedPcdGet64 (PcdEmuFlashFvRecoveryBase) + FvSize),
479 FileSize - FvSize,
480 PROT_READ | PROT_WRITE | PROT_EXEC,
8052c4a2 481 MAP_SHARED,
d18d8a1d 482 fd,
8052c4a2 483 FvSize
484 );
485 close (fd);
486 if (res2 == MAP_FAILED) {
946bfba2 487 perror ("MapFd0() Failed res2 =");
8052c4a2 488 return EFI_DEVICE_ERROR;
489 }
490
946bfba2 491 //
d18d8a1d 492 // If enabled use the magic page to communicate between modules
946bfba2 493 // This replaces the PI PeiServicesTable pointer mechanism that
494 // deos not work in the emulator. It also allows the removal of
495 // writable globals from SEC, PEI_CORE (libraries), PEIMs
496 //
497 EmuMagicPage = (void *)(UINTN)FixedPcdGet64 (PcdPeiServicesTablePage);
498 if (EmuMagicPage != NULL) {
499 res3 = mmap (
d18d8a1d 500 (void *)EmuMagicPage,
501 4096,
502 PROT_READ | PROT_WRITE,
946bfba2 503 MAP_PRIVATE | MAP_ANONYMOUS,
d18d8a1d 504 0,
946bfba2 505 0
506 );
507 if (res3 != EmuMagicPage) {
508 printf ("MapFd0(): Could not allocate PeiServicesTablePage @ %lx\n", (long unsigned int)EmuMagicPage);
509 return EFI_DEVICE_ERROR;
510 }
511 }
d18d8a1d 512
8052c4a2 513 *Length = (UINT64) FileSize;
514 *BaseAddress = (EFI_PHYSICAL_ADDRESS) (UINTN) res;
515
d18d8a1d 516 return EFI_SUCCESS;
8052c4a2 517}
949f388f 518
519
949f388f 520/*++
521
522Routine Description:
65e3f333 523 This is the service to load the SEC Core from the Firmware Volume
949f388f 524
525Arguments:
65e3f333 526 LargestRegion - Memory to use for SEC.
949f388f 527 LargestRegionSize - Size of Memory to use for PEI
528 BootFirmwareVolumeBase - Start of the Boot FV
65e3f333 529 PeiCorePe32File - SEC PE32
949f388f 530
531Returns:
532 Success means control is transfered and thus we should never return
533
534**/
65e3f333 535VOID
536SecLoadFromCore (
537 IN UINTN LargestRegion,
538 IN UINTN LargestRegionSize,
539 IN UINTN BootFirmwareVolumeBase,
540 IN VOID *PeiCorePe32File
541 )
949f388f 542{
543 EFI_STATUS Status;
544 EFI_PHYSICAL_ADDRESS TopOfMemory;
545 VOID *TopOfStack;
949f388f 546 EFI_PHYSICAL_ADDRESS PeiCoreEntryPoint;
949f388f 547 EFI_SEC_PEI_HAND_OFF *SecCoreData;
548 UINTN PeiStackSize;
549
550 //
551 // Compute Top Of Memory for Stack and PEI Core Allocations
552 //
553 TopOfMemory = LargestRegion + LargestRegionSize;
554 PeiStackSize = (UINTN)RShiftU64((UINT64)STACK_SIZE,1);
555
556 //
557 // |-----------| <---- TemporaryRamBase + TemporaryRamSize
558 // | Heap |
559 // | |
560 // |-----------| <---- StackBase / PeiTemporaryMemoryBase
561 // | |
562 // | Stack |
563 // |-----------| <---- TemporaryRamBase
564 //
565 TopOfStack = (VOID *)(LargestRegion + PeiStackSize);
566 TopOfMemory = LargestRegion + PeiStackSize;
567
568 //
569 // Reservet space for storing PeiCore's parament in stack.
570 //
571 TopOfStack = (VOID *)((UINTN)TopOfStack - sizeof (EFI_SEC_PEI_HAND_OFF) - CPU_STACK_ALIGNMENT);
572 TopOfStack = ALIGN_POINTER (TopOfStack, CPU_STACK_ALIGNMENT);
573
574
575 //
576 // Bind this information into the SEC hand-off state
577 //
65e3f333 578 SecCoreData = (EFI_SEC_PEI_HAND_OFF*)(UINTN) TopOfStack;
949f388f 579 SecCoreData->DataSize = sizeof(EFI_SEC_PEI_HAND_OFF);
580 SecCoreData->BootFirmwareVolumeBase = (VOID*)BootFirmwareVolumeBase;
581 SecCoreData->BootFirmwareVolumeSize = PcdGet32 (PcdEmuFirmwareFdSize);
582 SecCoreData->TemporaryRamBase = (VOID*)(UINTN)LargestRegion;
583 SecCoreData->TemporaryRamSize = STACK_SIZE;
584 SecCoreData->StackBase = SecCoreData->TemporaryRamBase;
585 SecCoreData->StackSize = PeiStackSize;
586 SecCoreData->PeiTemporaryRamBase = (VOID*) ((UINTN) SecCoreData->TemporaryRamBase + PeiStackSize);
587 SecCoreData->PeiTemporaryRamSize = STACK_SIZE - PeiStackSize;
588
589 //
65e3f333 590 // Find the SEC Core Entry Point
949f388f 591 //
65e3f333 592 Status = SecPeCoffGetEntryPoint (PeiCorePe32File, (VOID **)&PeiCoreEntryPoint);
949f388f 593 if (EFI_ERROR (Status)) {
594 return ;
595 }
596
597 //
65e3f333 598 // Transfer control to the SEC Core
949f388f 599 //
600 PeiSwitchStacks (
601 (SWITCH_STACK_ENTRY_POINT) (UINTN) PeiCoreEntryPoint,
602 SecCoreData,
65e3f333 603 (VOID *)gPpiList,
949f388f 604 TopOfStack
605 );
606 //
65e3f333 607 // If we get here, then the SEC Core returned. This is an error
949f388f 608 //
609 return ;
610}
611
65e3f333 612
949f388f 613/*++
614
615Routine Description:
616 This service is called from Index == 0 until it returns EFI_UNSUPPORTED.
617 It allows discontiguous memory regions to be supported by the emulator.
618 It uses gSystemMemory[] and gSystemMemoryCount that were created by
619 parsing the host environment variable EFI_MEMORY_SIZE.
620 The size comes from the varaible and the address comes from the call to
621 UnixOpenFile.
622
623Arguments:
624 Index - Which memory region to use
625 MemoryBase - Return Base address of memory region
626 MemorySize - Return size in bytes of the memory region
627
628Returns:
629 EFI_SUCCESS - If memory region was mapped
630 EFI_UNSUPPORTED - If Index is not supported
631
632**/
65e3f333 633EFI_STATUS
65e3f333 634SecUnixPeiAutoScan (
635 IN UINTN Index,
636 OUT EFI_PHYSICAL_ADDRESS *MemoryBase,
637 OUT UINT64 *MemorySize
638 )
949f388f 639{
640 void *res;
641
642 if (Index >= gSystemMemoryCount) {
643 return EFI_UNSUPPORTED;
644 }
645
646 *MemoryBase = 0;
65e3f333 647 res = MapMemory (
648 0, gSystemMemory[Index].Size,
649 PROT_READ | PROT_WRITE | PROT_EXEC,
650 MAP_PRIVATE | MAP_ANONYMOUS
651 );
652 if (res == MAP_FAILED) {
949f388f 653 return EFI_DEVICE_ERROR;
65e3f333 654 }
949f388f 655 *MemorySize = gSystemMemory[Index].Size;
656 *MemoryBase = (UINTN)res;
657 gSystemMemory[Index].Memory = *MemoryBase;
658
659 return EFI_SUCCESS;
660}
661
65e3f333 662
1d7ac5a6 663/*++
664
665Routine Description:
666 Check to see if an address range is in the EFI GCD memory map.
d18d8a1d 667
668 This is all of GCD for system memory passed to DXE Core. FV
1d7ac5a6 669 mapping and other device mapped into system memory are not
d18d8a1d 670 inlcuded in the check.
1d7ac5a6 671
672Arguments:
673 Index - Which memory region to use
674 MemoryBase - Return Base address of memory region
675 MemorySize - Return size in bytes of the memory region
676
677Returns:
678 TRUE - Address is in the EFI GCD memory map
679 FALSE - Address is NOT in memory map
680
681**/
682BOOLEAN
683EfiSystemMemoryRange (
684 IN VOID *MemoryAddress
685 )
686{
687 UINTN Index;
688 EFI_PHYSICAL_ADDRESS MemoryBase;
d18d8a1d 689
1d7ac5a6 690 MemoryBase = (EFI_PHYSICAL_ADDRESS)(UINTN)MemoryAddress;
691 for (Index = 0; Index < gSystemMemoryCount; Index++) {
692 if ((MemoryBase >= gSystemMemory[Index].Memory) &&
693 (MemoryBase < (gSystemMemory[Index].Memory + gSystemMemory[Index].Size)) ) {
694 return TRUE;
695 }
696 }
d18d8a1d 697
1d7ac5a6 698 return FALSE;
699}
700
701
949f388f 702/*++
703
704Routine Description:
705 Since the SEC is the only Unix program in stack it must export
706 an interface to do POSIX calls. gUnix is initailized in UnixThunk.c.
707
708Arguments:
709 InterfaceSize - sizeof (EFI_WIN_NT_THUNK_PROTOCOL);
710 InterfaceBase - Address of the gUnix global
711
712Returns:
713 EFI_SUCCESS - Data returned
714
715**/
65e3f333 716VOID *
65e3f333 717SecEmuThunkAddress (
718 VOID
719 )
949f388f 720{
721 return &gEmuThunkProtocol;
722}
723
724
949f388f 725
726RETURN_STATUS
727EFIAPI
728SecPeCoffGetEntryPoint (
729 IN VOID *Pe32Data,
730 IN OUT VOID **EntryPoint
731 )
732{
65e3f333 733 EFI_STATUS Status;
734 PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;
0ede3853 735
736 ZeroMem (&ImageContext, sizeof (ImageContext));
737 ImageContext.Handle = Pe32Data;
738 ImageContext.ImageRead = (PE_COFF_LOADER_READ_FILE) SecImageRead;
739
740 Status = PeCoffLoaderGetImageInfo (&ImageContext);
741 if (EFI_ERROR (Status)) {
742 return Status;
743 }
744
946bfba2 745 if (ImageContext.ImageAddress != (UINTN)Pe32Data) {
e7523e06 746 //
747 // Relocate image to match the address where it resides
748 //
749 ImageContext.ImageAddress = (UINTN)Pe32Data;
750 Status = PeCoffLoaderLoadImage (&ImageContext);
751 if (EFI_ERROR (Status)) {
752 return Status;
753 }
949f388f 754
e7523e06 755 Status = PeCoffLoaderRelocateImage (&ImageContext);
756 if (EFI_ERROR (Status)) {
757 return Status;
758 }
946bfba2 759 } else {
760 //
761 // Or just return image entry point
762 //
763 ImageContext.PdbPointer = PeCoffLoaderGetPdbPointer (Pe32Data);
764 Status = PeCoffLoaderGetEntryPoint (Pe32Data, EntryPoint);
765 if (EFI_ERROR (Status)) {
766 return Status;
767 }
768 ImageContext.EntryPoint = (UINTN)*EntryPoint;
769 }
949f388f 770
65e3f333 771 // On Unix a dlopen is done that will change the entry point
772 SecPeCoffRelocateImageExtraAction (&ImageContext);
773 *EntryPoint = (VOID *)(UINTN)ImageContext.EntryPoint;
d18d8a1d 774
949f388f 775 return Status;
776}
777
778
779
949f388f 780/*++
781
782Routine Description:
783 Return the FD Size and base address. Since the FD is loaded from a
784 file into host memory only the SEC will know it's address.
785
786Arguments:
787 Index - Which FD, starts at zero.
788 FdSize - Size of the FD in bytes
789 FdBase - Start address of the FD. Assume it points to an FV Header
790 FixUp - Difference between actual FD address and build address
791
792Returns:
793 EFI_SUCCESS - Return the Base address and size of the FV
794 EFI_UNSUPPORTED - Index does nto map to an FD in the system
795
796**/
65e3f333 797EFI_STATUS
65e3f333 798SecUnixFdAddress (
799 IN UINTN Index,
800 IN OUT EFI_PHYSICAL_ADDRESS *FdBase,
801 IN OUT UINT64 *FdSize,
802 IN OUT EFI_PHYSICAL_ADDRESS *FixUp
803 )
949f388f 804{
805 if (Index >= gFdInfoCount) {
806 return EFI_UNSUPPORTED;
807 }
808
809 *FdBase = gFdInfo[Index].Address;
810 *FdSize = gFdInfo[Index].Size;
811 *FixUp = 0;
812
813 if (*FdBase == 0 && *FdSize == 0) {
814 return EFI_UNSUPPORTED;
815 }
816
817 if (Index == 0) {
818 //
819 // FD 0 has XIP code and well known PCD values
820 // If the memory buffer could not be allocated at the FD build address
821 // the Fixup is the difference.
822 //
823 *FixUp = *FdBase - PcdGet64 (PcdEmuFdBaseAddress);
824 }
825
826 return EFI_SUCCESS;
827}
828
949f388f 829
949f388f 830/*++
831
832Routine Description:
833 Count the number of seperators in String
834
835Arguments:
836 String - String to process
837 Seperator - Item to count
838
839Returns:
840 Number of Seperator in String
841
842**/
65e3f333 843UINTN
844CountSeperatorsInString (
845 IN const CHAR16 *String,
846 IN CHAR16 Seperator
847 )
949f388f 848{
849 UINTN Count;
850
851 for (Count = 0; *String != '\0'; String++) {
852 if (*String == Seperator) {
853 Count++;
854 }
855 }
856
857 return Count;
858}
859
860
0ede3853 861EFI_STATUS
7af94c1d 862EFIAPI
0ede3853 863SecImageRead (
864 IN VOID *FileHandle,
865 IN UINTN FileOffset,
866 IN OUT UINTN *ReadSize,
867 OUT VOID *Buffer
868 )
869/*++
870
871Routine Description:
872 Support routine for the PE/COFF Loader that reads a buffer from a PE/COFF file
873
874Arguments:
875 FileHandle - The handle to the PE/COFF file
876 FileOffset - The offset, in bytes, into the file to read
877 ReadSize - The number of bytes to read from the file starting at FileOffset
878 Buffer - A pointer to the buffer to read the data into.
879
880Returns:
881 EFI_SUCCESS - ReadSize bytes of data were read into Buffer from the PE/COFF file starting at FileOffset
882
883**/
884{
885 CHAR8 *Destination8;
886 CHAR8 *Source8;
887 UINTN Length;
888
889 Destination8 = Buffer;
890 Source8 = (CHAR8 *) ((UINTN) FileHandle + FileOffset);
891 Length = *ReadSize;
892 while (Length--) {
893 *(Destination8++) = *(Source8++);
894 }
895
896 return EFI_SUCCESS;
897}
898
899
949f388f 900/*++
901
902Routine Description:
903 Store the ModHandle in an array indexed by the Pdb File name.
904 The ModHandle is needed to unload the image.
905
906Arguments:
907 ImageContext - Input data returned from PE Laoder Library. Used to find the
908 .PDB file name of the PE Image.
909 ModHandle - Returned from LoadLibraryEx() and stored for call to
910 FreeLibrary().
911
912Returns:
913 EFI_SUCCESS - ModHandle was stored.
914
915**/
65e3f333 916EFI_STATUS
917AddHandle (
918 IN PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext,
919 IN VOID *ModHandle
920 )
949f388f 921{
922 UINTN Index;
923 IMAGE_CONTEXT_TO_MOD_HANDLE *Array;
924 UINTN PreviousSize;
925
926
927 Array = mImageContextModHandleArray;
928 for (Index = 0; Index < mImageContextModHandleArraySize; Index++, Array++) {
929 if (Array->ImageContext == NULL) {
930 //
931 // Make a copy of the stirng and store the ModHandle
932 //
933 Array->ImageContext = ImageContext;
934 Array->ModHandle = ModHandle;
935 return EFI_SUCCESS;
936 }
937 }
938
939 //
940 // No free space in mImageContextModHandleArray so grow it by
941 // IMAGE_CONTEXT_TO_MOD_HANDLE entires. realloc will
942 // copy the old values to the new locaiton. But it does
943 // not zero the new memory area.
944 //
945 PreviousSize = mImageContextModHandleArraySize * sizeof (IMAGE_CONTEXT_TO_MOD_HANDLE);
946 mImageContextModHandleArraySize += MAX_IMAGE_CONTEXT_TO_MOD_HANDLE_ARRAY_SIZE;
947
b8800fc5 948 mImageContextModHandleArray = ReallocatePool (
949 (mImageContextModHandleArraySize - 1) * sizeof (IMAGE_CONTEXT_TO_MOD_HANDLE),
950 mImageContextModHandleArraySize * sizeof (IMAGE_CONTEXT_TO_MOD_HANDLE),
951 mImageContextModHandleArray
952 );
949f388f 953 if (mImageContextModHandleArray == NULL) {
954 ASSERT (FALSE);
955 return EFI_OUT_OF_RESOURCES;
956 }
957
958 memset (mImageContextModHandleArray + PreviousSize, 0, MAX_IMAGE_CONTEXT_TO_MOD_HANDLE_ARRAY_SIZE * sizeof (IMAGE_CONTEXT_TO_MOD_HANDLE));
959
960 return AddHandle (ImageContext, ModHandle);
961}
962
963
949f388f 964/*++
965
966Routine Description:
967 Return the ModHandle and delete the entry in the array.
968
969Arguments:
970 ImageContext - Input data returned from PE Laoder Library. Used to find the
971 .PDB file name of the PE Image.
972
973Returns:
974 ModHandle - ModHandle assoicated with ImageContext is returned
975 NULL - No ModHandle associated with ImageContext
976
977**/
65e3f333 978VOID *
979RemoveHandle (
980 IN PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
981 )
949f388f 982{
983 UINTN Index;
984 IMAGE_CONTEXT_TO_MOD_HANDLE *Array;
985
986 if (ImageContext->PdbPointer == NULL) {
987 //
988 // If no PDB pointer there is no ModHandle so return NULL
989 //
990 return NULL;
991 }
992
993 Array = mImageContextModHandleArray;
994 for (Index = 0; Index < mImageContextModHandleArraySize; Index++, Array++) {
995 if (Array->ImageContext == ImageContext) {
996 //
997 // If you find a match return it and delete the entry
998 //
999 Array->ImageContext = NULL;
1000 return Array->ModHandle;
1001 }
1002 }
1003
1004 return NULL;
1005}
1006
1007
1008
949f388f 1009BOOLEAN
1010IsPdbFile (
1011 IN CHAR8 *PdbFileName
1012 )
1013{
1014 UINTN Len;
1015
1016 if (PdbFileName == NULL) {
1017 return FALSE;
1018 }
1019
1020 Len = strlen (PdbFileName);
1021 if ((Len < 5)|| (PdbFileName[Len - 4] != '.')) {
1022 return FALSE;
1023 }
1024
1025 if ((PdbFileName[Len - 3] == 'P' || PdbFileName[Len - 3] == 'p') &&
1026 (PdbFileName[Len - 2] == 'D' || PdbFileName[Len - 2] == 'd') &&
1027 (PdbFileName[Len - 1] == 'B' || PdbFileName[Len - 1] == 'b')) {
1028 return TRUE;
1029 }
1030
1031 return FALSE;
1032}
1033
1034
1035#define MAX_SPRINT_BUFFER_SIZE 0x200
1036
1037void
1038PrintLoadAddress (
1039 IN PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
1040 )
1041{
1042 if (ImageContext->PdbPointer == NULL) {
1043 fprintf (stderr,
1044 "0x%08lx Loading NO DEBUG with entry point 0x%08lx\n",
1045 (unsigned long)(ImageContext->ImageAddress),
1046 (unsigned long)ImageContext->EntryPoint
1047 );
1048 } else {
1049 fprintf (stderr,
1050 "0x%08lx Loading %s with entry point 0x%08lx\n",
1051 (unsigned long)(ImageContext->ImageAddress + ImageContext->SizeOfHeaders),
1052 ImageContext->PdbPointer,
1053 (unsigned long)ImageContext->EntryPoint
1054 );
1055 }
1056 // Keep output synced up
1057 fflush (stderr);
1058}
1059
1060
0bc9421b 1061/**
1062 Loads the image using dlopen so symbols will be automatically
1063 loaded by gdb.
1064
1065 @param ImageContext The PE/COFF image context
1066
1067 @retval TRUE - The image was successfully loaded
1068 @retval FALSE - The image was successfully loaded
1069
1070**/
1071BOOLEAN
1072DlLoadImage (
949f388f 1073 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
1074 )
1075{
1076
1077#ifdef __APPLE__
949f388f 1078
0bc9421b 1079 return FALSE;
949f388f 1080
1081#else
1082
1083 void *Handle = NULL;
1084 void *Entry = NULL;
1085
1086 if (ImageContext->PdbPointer == NULL) {
0bc9421b 1087 return FALSE;
949f388f 1088 }
1089
1090 if (!IsPdbFile (ImageContext->PdbPointer)) {
0bc9421b 1091 return FALSE;
949f388f 1092 }
1093
65e3f333 1094 fprintf (
1095 stderr,
949f388f 1096 "Loading %s 0x%08lx - entry point 0x%08lx\n",
1097 ImageContext->PdbPointer,
1098 (unsigned long)ImageContext->ImageAddress,
65e3f333 1099 (unsigned long)ImageContext->EntryPoint
1100 );
949f388f 1101
1102 Handle = dlopen (ImageContext->PdbPointer, RTLD_NOW);
f70c2a12 1103 if (Handle != NULL) {
949f388f 1104 Entry = dlsym (Handle, "_ModuleEntryPoint");
f70c2a12 1105 AddHandle (ImageContext, Handle);
949f388f 1106 } else {
1107 printf("%s\n", dlerror());
1108 }
1109
1110 if (Entry != NULL) {
1111 ImageContext->EntryPoint = (UINTN)Entry;
65e3f333 1112 printf ("Change %s Entrypoint to :0x%08lx\n", ImageContext->PdbPointer, (unsigned long)Entry);
0bc9421b 1113 return TRUE;
1114 } else {
1115 return FALSE;
949f388f 1116 }
1117
949f388f 1118#endif
0bc9421b 1119}
1120
1121
dd6f7d02 1122VOID
1123SecGdbScriptBreak (
1124 char *FileName,
1125 int FileNameLength,
1126 long unsigned int LoadAddress,
1127 int AddSymbolFlag
1128 )
1129{
1130 return;
1131}
1132
1133
0bc9421b 1134/**
1135 Adds the image to a gdb script so it's symbols can be loaded.
1136 The AddFirmwareSymbolFile helper macro is used.
1137
1138 @param ImageContext The PE/COFF image context
1139
1140**/
1141VOID
1142GdbScriptAddImage (
1143 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
1144 )
1145{
0bc9421b 1146
1147 PrintLoadAddress (ImageContext);
1148
1149 if (ImageContext->PdbPointer != NULL && !IsPdbFile (ImageContext->PdbPointer)) {
1150 FILE *GdbTempFile;
dd6f7d02 1151 if (FeaturePcdGet (PcdEmulatorLazyLoadSymbols)) {
1152 GdbTempFile = fopen (gGdbWorkingFileName, "a");
1153 if (GdbTempFile != NULL) {
1154 long unsigned int SymbolsAddr = (long unsigned int)(ImageContext->ImageAddress + ImageContext->SizeOfHeaders);
1155 mScriptSymbolChangesCount++;
1156 fprintf (
1157 GdbTempFile,
1158 "AddFirmwareSymbolFile 0x%x %s 0x%08lx\n",
1159 mScriptSymbolChangesCount,
1160 ImageContext->PdbPointer,
1161 SymbolsAddr
1162 );
1163 fclose (GdbTempFile);
1164 } else {
1165 ASSERT (FALSE);
1166 }
0bc9421b 1167 } else {
dd6f7d02 1168 GdbTempFile = fopen (gGdbWorkingFileName, "w");
1169 if (GdbTempFile != NULL) {
1170 fprintf (
1171 GdbTempFile,
1172 "add-symbol-file %s 0x%08lx\n",
1173 ImageContext->PdbPointer,
1174 (long unsigned int)(ImageContext->ImageAddress + ImageContext->SizeOfHeaders)
1175 );
1176 fclose (GdbTempFile);
1177
1178 //
1179 // Target for gdb breakpoint in a script that uses gGdbWorkingFileName to set a breakpoint.
1180 // Hey what can you say scripting in gdb is not that great....
1181 //
1182 SecGdbScriptBreak (ImageContext->PdbPointer, strlen (ImageContext->PdbPointer), (long unsigned int)(ImageContext->ImageAddress + ImageContext->SizeOfHeaders), 1);
1183 } else {
1184 ASSERT (FALSE);
1185 }
0bc9421b 1186 }
0bc9421b 1187 }
949f388f 1188}
1189
1190
1191VOID
1192EFIAPI
0bc9421b 1193SecPeCoffRelocateImageExtraAction (
1194 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
949f388f 1195 )
1196{
0bc9421b 1197 if (!DlLoadImage (ImageContext)) {
1198 GdbScriptAddImage (ImageContext);
1199 }
1200}
949f388f 1201
949f388f 1202
0bc9421b 1203/**
1204 Adds the image to a gdb script so it's symbols can be unloaded.
1205 The RemoveFirmwareSymbolFile helper macro is used.
1206
1207 @param ImageContext The PE/COFF image context
1208
1209**/
1210VOID
1211GdbScriptRemoveImage (
1212 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
1213 )
1214{
949f388f 1215 FILE *GdbTempFile;
949f388f 1216
0bc9421b 1217 //
1218 // Need to skip .PDB files created from VC++
1219 //
1220 if (IsPdbFile (ImageContext->PdbPointer)) {
1221 return;
1222 }
1223
dd6f7d02 1224 if (FeaturePcdGet (PcdEmulatorLazyLoadSymbols)) {
1225 //
1226 // Write the file we need for the gdb script
1227 //
1228 GdbTempFile = fopen (gGdbWorkingFileName, "a");
1229 if (GdbTempFile != NULL) {
1230 mScriptSymbolChangesCount++;
1231 fprintf (
1232 GdbTempFile,
1233 "RemoveFirmwareSymbolFile 0x%x %s\n",
1234 mScriptSymbolChangesCount,
1235 ImageContext->PdbPointer
1236 );
1237 fclose (GdbTempFile);
1238 } else {
1239 ASSERT (FALSE);
1240 }
0bc9421b 1241 } else {
dd6f7d02 1242 GdbTempFile = fopen (gGdbWorkingFileName, "w");
1243 if (GdbTempFile != NULL) {
1244 fprintf (GdbTempFile, "remove-symbol-file %s\n", ImageContext->PdbPointer);
1245 fclose (GdbTempFile);
1246
1247 //
1248 // Target for gdb breakpoint in a script that uses gGdbWorkingFileName to set a breakpoint.
1249 // Hey what can you say scripting in gdb is not that great....
1250 //
1251 SecGdbScriptBreak (ImageContext->PdbPointer, strlen (ImageContext->PdbPointer), 0, 0);
1252 } else {
1253 ASSERT (FALSE);
1254 }
0bc9421b 1255 }
0bc9421b 1256}
1257
949f388f 1258
0bc9421b 1259VOID
1260EFIAPI
1261SecPeCoffUnloadImageExtraAction (
1262 IN PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
1263 )
1264{
1265 VOID *Handle;
1266
1267 //
1268 // Check to see if the image symbols were loaded with gdb script, or dlopen
1269 //
1270 Handle = RemoveHandle (ImageContext);
febb2276 1271 if (Handle != NULL) {
0bc9421b 1272#ifndef __APPLE__
1273 dlclose (Handle);
949f388f 1274#endif
0bc9421b 1275 return;
1276 }
1277
1278 GdbScriptRemoveImage (ImageContext);
949f388f 1279}
1280
1281