]> git.proxmox.com Git - mirror_edk2.git/blame - UnixPkg/Sec/SecMain.c
Refine code.
[mirror_edk2.git] / UnixPkg / Sec / SecMain.c
CommitLineData
804405e7 1/*++
2
f9b8ab56
HT
3Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>
4Portions copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR>
5This program and the accompanying materials
804405e7 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
13Module Name:
14
15 SecMain.c
16
17Abstract:
ccd55824 18 Unix emulator of SEC phase. It's really a Posix application, but this is
804405e7 19 Ok since all the other modules for NT32 are NOT Posix applications.
20
21 This program processes host environment variables and figures out
22 what the memory layout will be, how may FD's will be loaded and also
23 what the boot mode is.
24
25 The SEC registers a set of services with the SEC core. gPrivateDispatchTable
26 is a list of PPI's produced by the SEC that are availble for usage in PEI.
27
28 This code produces 128 K of temporary memory for the PEI stack by opening a
29 host file and mapping it directly to memory addresses.
30
31 The system.cmd script is used to set host environment variables that drive
32 the configuration opitons of the SEC.
33
34--*/
35
36#include "SecMain.h"
37#include <sys/mman.h>
38#include <Ppi/UnixPeiLoadFile.h>
804405e7 39#include <Ppi/TemporaryRamSupport.h>
40#include <dlfcn.h>
ccd55824 41
42#ifdef __APPLE__
43#define MAP_ANONYMOUS MAP_ANON
44char *gGdbWorkingFileName = NULL;
45#endif
46
47
804405e7 48//
49// Globals
50//
804405e7 51
ccd55824 52UNIX_PEI_LOAD_FILE_PPI mSecUnixLoadFilePpi = { SecUnixPeiLoadFile };
804405e7 53
ccd55824 54PEI_UNIX_AUTOSCAN_PPI mSecUnixAutoScanPpi = { SecUnixPeiAutoScan };
804405e7 55
ccd55824 56PEI_UNIX_THUNK_PPI mSecUnixThunkPpi = { SecUnixUnixThunkAddress };
804405e7 57
73aa7f04 58EFI_PEI_PROGRESS_CODE_PPI mSecStatusCodePpi = { SecPeiReportStatusCode };
804405e7 59
ccd55824 60UNIX_FWH_PPI mSecFwhInformationPpi = { SecUnixFdAddress };
804405e7 61
62TEMPORARY_RAM_SUPPORT_PPI mSecTemporaryRamSupportPpi = {SecTemporaryRamSupport};
63
64EFI_PEI_PPI_DESCRIPTOR gPrivateDispatchTable[] = {
804405e7 65 {
66 EFI_PEI_PPI_DESCRIPTOR_PPI,
67 &gUnixPeiLoadFilePpiGuid,
ccd55824 68 &mSecUnixLoadFilePpi
804405e7 69 },
70 {
71 EFI_PEI_PPI_DESCRIPTOR_PPI,
72 &gPeiUnixAutoScanPpiGuid,
ccd55824 73 &mSecUnixAutoScanPpi
804405e7 74 },
75 {
76 EFI_PEI_PPI_DESCRIPTOR_PPI,
77 &gPeiUnixThunkPpiGuid,
ccd55824 78 &mSecUnixThunkPpi
804405e7 79 },
80 {
81 EFI_PEI_PPI_DESCRIPTOR_PPI,
82 &gEfiPeiStatusCodePpiGuid,
83 &mSecStatusCodePpi
84 },
85 {
86 EFI_PEI_PPI_DESCRIPTOR_PPI,
87 &gEfiTemporaryRamSupportPpiGuid,
88 &mSecTemporaryRamSupportPpi
89 },
90 {
804405e7 91 EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST,
92 &gUnixFwhPpiGuid,
93 &mSecFwhInformationPpi
94 }
95};
96
97
98//
99// Default information about where the FD is located.
100// This array gets filled in with information from EFI_FIRMWARE_VOLUMES
101// EFI_FIRMWARE_VOLUMES is a host environment variable set by system.cmd.
102// The number of array elements is allocated base on parsing
103// EFI_FIRMWARE_VOLUMES and the memory is never freed.
104//
105UINTN gFdInfoCount = 0;
106UNIX_FD_INFO *gFdInfo;
107
108//
109// Array that supports seperate memory rantes.
110// The memory ranges are set in system.cmd via the EFI_MEMORY_SIZE variable.
111// The number of array elements is allocated base on parsing
112// EFI_MEMORY_SIZE and the memory is never freed.
113//
114UINTN gSystemMemoryCount = 0;
115UNIX_SYSTEM_MEMORY *gSystemMemory;
116
ccd55824 117
118
119UINTN mImageContextModHandleArraySize = 0;
120IMAGE_CONTEXT_TO_MOD_HANDLE *mImageContextModHandleArray = NULL;
121
122
804405e7 123VOID
124EFIAPI
125SecSwitchStack (
126 UINT32 TemporaryMemoryBase,
127 UINT32 PermenentMemoryBase
128 );
129
804405e7 130EFI_PHYSICAL_ADDRESS *
131MapMemory (
132 INTN fd,
133 UINT64 length,
134 INTN prot,
135 INTN flags);
136
804405e7 137EFI_STATUS
138MapFile (
139 IN CHAR8 *FileName,
140 IN OUT EFI_PHYSICAL_ADDRESS *BaseAddress,
141 OUT UINT64 *Length
142 );
7ee3b613 143
398b646f 144EFI_STATUS
145EFIAPI
146SecNt32PeCoffRelocateImage (
147 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
148 );
804405e7 149
150
ccd55824 151int
804405e7 152main (
ccd55824 153 IN int Argc,
154 IN char **Argv,
155 IN char **Envp
804405e7 156 )
157/*++
158
159Routine Description:
ccd55824 160 Main entry point to SEC for Unix. This is a unix program
804405e7 161
162Arguments:
163 Argc - Number of command line arguments
164 Argv - Array of command line argument strings
165 Envp - Array of environmemt variable strings
166
167Returns:
168 0 - Normal exit
169 1 - Abnormal exit
170
171--*/
172{
173 EFI_STATUS Status;
174 EFI_PHYSICAL_ADDRESS InitialStackMemory;
175 UINT64 InitialStackMemorySize;
176 UINTN Index;
177 UINTN Index1;
178 UINTN Index2;
179 UINTN PeiIndex;
180 CHAR8 *FileName;
181 BOOLEAN Done;
182 VOID *PeiCoreFile;
183 CHAR16 *MemorySizeStr;
184 CHAR16 *FirmwareVolumesStr;
185 UINTN *StackPointer;
186
187 setbuf(stdout, 0);
188 setbuf(stderr, 0);
189
cdccd99e 190 MemorySizeStr = (CHAR16 *) PcdGetPtr (PcdUnixMemorySizeForSecMain);
191 FirmwareVolumesStr = (CHAR16 *) PcdGetPtr (PcdUnixFirmwareVolume);
804405e7 192
193 printf ("\nEDK SEC Main UNIX Emulation Environment from www.TianoCore.org\n");
194
ccd55824 195#ifdef __APPLE__
196 //
197 // We can't use dlopen on OS X, so we need a scheme to get symboles into gdb
198 // We need to create a temp file that contains gdb commands so we can load
199 // symbols when we load every PE/COFF image.
200 //
201 Index = strlen (*Argv);
7ee3b613 202 gGdbWorkingFileName = malloc (Index + strlen(".gdb") + 1);
ccd55824 203 strcpy (gGdbWorkingFileName, *Argv);
204 strcat (gGdbWorkingFileName, ".gdb");
205#endif
206
207
804405e7 208 //
209 // Allocate space for gSystemMemory Array
210 //
211 gSystemMemoryCount = CountSeperatorsInString (MemorySizeStr, '!') + 1;
212 gSystemMemory = calloc (gSystemMemoryCount, sizeof (UNIX_SYSTEM_MEMORY));
213 if (gSystemMemory == NULL) {
214 printf ("ERROR : Can not allocate memory for system. Exiting.\n");
215 exit (1);
216 }
217 //
218 // Allocate space for gSystemMemory Array
219 //
220 gFdInfoCount = CountSeperatorsInString (FirmwareVolumesStr, '!') + 1;
221 gFdInfo = calloc (gFdInfoCount, sizeof (UNIX_FD_INFO));
222 if (gFdInfo == NULL) {
223 printf ("ERROR : Can not allocate memory for fd info. Exiting.\n");
224 exit (1);
225 }
226 //
227 // Setup Boot Mode. If BootModeStr == "" then BootMode = 0 (BOOT_WITH_FULL_CONFIGURATION)
228 //
cdccd99e 229 printf (" BootMode 0x%02x\n", (unsigned int)PcdGet32 (PcdUnixBootMode));
804405e7 230
231 //
232 // Open up a 128K file to emulate temp memory for PEI.
233 // on a real platform this would be SRAM, or using the cache as RAM.
ccd55824 234 // Set InitialStackMemory to zero so UnixOpenFile will allocate a new mapping
804405e7 235 //
236 InitialStackMemorySize = STACK_SIZE;
237 InitialStackMemory = (UINTN)MapMemory(0,
238 (UINT32) InitialStackMemorySize,
239 PROT_READ | PROT_WRITE,
240 MAP_ANONYMOUS | MAP_PRIVATE);
241 if (InitialStackMemory == 0) {
242 printf ("ERROR : Can not open SecStack Exiting\n");
243 exit (1);
244 }
245
246 printf (" SEC passing in %u KB of temp RAM at 0x%08lx to PEI\n",
ccd55824 247 (unsigned int)(InitialStackMemorySize / 1024),
804405e7 248 (unsigned long)InitialStackMemory);
249
250 for (StackPointer = (UINTN*) (UINTN) InitialStackMemory;
ccd55824 251 StackPointer < (UINTN*)(UINTN)((UINTN) InitialStackMemory + (UINT64) InitialStackMemorySize);
804405e7 252 StackPointer ++) {
253 *StackPointer = 0x5AA55AA5;
254 }
255
256 //
257 // Open All the firmware volumes and remember the info in the gFdInfo global
258 //
259 FileName = (CHAR8 *)malloc (StrLen (FirmwareVolumesStr) + 1);
260 if (FileName == NULL) {
261 printf ("ERROR : Can not allocate memory for firmware volume string\n");
262 exit (1);
263 }
264
265 Index2 = 0;
266 for (Done = FALSE, Index = 0, PeiIndex = 0, PeiCoreFile = NULL;
267 FirmwareVolumesStr[Index2] != 0;
268 Index++) {
269 for (Index1 = 0; (FirmwareVolumesStr[Index2] != '!') && (FirmwareVolumesStr[Index2] != 0); Index2++)
270 FileName[Index1++] = FirmwareVolumesStr[Index2];
271 if (FirmwareVolumesStr[Index2] == '!')
272 Index2++;
273 FileName[Index1] = '\0';
274
275 //
276 // Open the FD and remmeber where it got mapped into our processes address space
277 //
278 Status = MapFile (
279 FileName,
280 &gFdInfo[Index].Address,
281 &gFdInfo[Index].Size
282 );
283 if (EFI_ERROR (Status)) {
ccd55824 284 printf ("ERROR : Can not open Firmware Device File %s (%x). Exiting.\n", FileName, (unsigned int)Status);
804405e7 285 exit (1);
286 }
287
288 printf (" FD loaded from %s at 0x%08lx",
289 FileName, (unsigned long)gFdInfo[Index].Address);
290
291 if (PeiCoreFile == NULL) {
292 //
293 // Assume the beginning of the FD is an FV and look for the PEI Core.
294 // Load the first one we find.
295 //
296 Status = SecFfsFindPeiCore ((EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) gFdInfo[Index].Address, &PeiCoreFile);
297 if (!EFI_ERROR (Status)) {
298 PeiIndex = Index;
299 printf (" contains SEC Core");
300 }
301 }
302
303 printf ("\n");
304 }
305 //
306 // Calculate memory regions and store the information in the gSystemMemory
307 // global for later use. The autosizing code will use this data to
308 // map this memory into the SEC process memory space.
309 //
310 Index1 = 0;
311 Index = 0;
312 while (1) {
313 UINTN val = 0;
314 //
315 // Save the size of the memory.
316 //
317 while (MemorySizeStr[Index1] >= '0' && MemorySizeStr[Index1] <= '9') {
318 val = val * 10 + MemorySizeStr[Index1] - '0';
319 Index1++;
320 }
321 gSystemMemory[Index++].Size = val * 0x100000;
322 if (MemorySizeStr[Index1] == 0)
323 break;
324 Index1++;
325 }
326
327 printf ("\n");
328
329 //
330 // Hand off to PEI Core
331 //
332 SecLoadFromCore ((UINTN) InitialStackMemory, (UINTN) InitialStackMemorySize, (UINTN) gFdInfo[0].Address, PeiCoreFile);
333
334 //
335 // If we get here, then the PEI Core returned. This is an error as PEI should
336 // always hand off to DXE.
337 //
338 printf ("ERROR : PEI Core returned\n");
339 exit (1);
340}
341
342EFI_PHYSICAL_ADDRESS *
343MapMemory (
344 INTN fd,
345 UINT64 length,
346 INTN prot,
347 INTN flags)
348{
349 STATIC UINTN base = 0x40000000;
350 CONST UINTN align = (1 << 24);
351 VOID *res = NULL;
352 BOOLEAN isAligned = 0;
353
354 //
355 // Try to get an aligned block somewhere in the address space of this
356 // process.
357 //
358 while((!isAligned) && (base != 0)) {
359 res = mmap ((void *)base, length, prot, flags, fd, 0);
360 if (res == MAP_FAILED) {
361 return NULL;
362 }
363 if ((((UINTN)res) & ~(align-1)) == (UINTN)res) {
364 isAligned=1;
365 }
366 else {
367 munmap(res, length);
368 base += align;
369 }
370 }
371 return res;
372}
373
374EFI_STATUS
375MapFile (
376 IN CHAR8 *FileName,
377 IN OUT EFI_PHYSICAL_ADDRESS *BaseAddress,
378 OUT UINT64 *Length
379 )
380/*++
381
382Routine Description:
ccd55824 383 Opens and memory maps a file using Unix services. If BaseAddress is non zero
804405e7 384 the process will try and allocate the memory starting at BaseAddress.
385
386Arguments:
387 FileName - The name of the file to open and map
388 MapSize - The amount of the file to map in bytes
389 CreationDisposition - The flags to pass to CreateFile(). Use to create new files for
390 memory emulation, and exiting files for firmware volume emulation
391 BaseAddress - The base address of the mapped file in the user address space.
392 If passed in as NULL the a new memory region is used.
393 If passed in as non NULL the request memory region is used for
394 the mapping of the file into the process space.
395 Length - The size of the mapped region in bytes
396
397Returns:
398 EFI_SUCCESS - The file was opened and mapped.
399 EFI_NOT_FOUND - FileName was not found in the current directory
400 EFI_DEVICE_ERROR - An error occured attempting to map the opened file
401
402--*/
403{
404 int fd;
405 VOID *res;
406 UINTN FileSize;
407
408 fd = open (FileName, O_RDONLY);
409 if (fd < 0)
410 return EFI_NOT_FOUND;
411 FileSize = lseek (fd, 0, SEEK_END);
412
413#if 0
414 if (IsMain)
415 {
416 /* Read entry address. */
417 lseek (fd, FileSize - 0x20, SEEK_SET);
418 if (read (fd, &EntryAddress, 4) != 4)
419 {
420 close (fd);
421 return EFI_DEVICE_ERROR;
422 }
423 }
424#endif
425
426 res = MapMemory(fd, FileSize, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE);
427
428 close (fd);
429
430 if (res == MAP_FAILED)
431 return EFI_DEVICE_ERROR;
432
433 *Length = (UINT64) FileSize;
434 *BaseAddress = (EFI_PHYSICAL_ADDRESS) (UINTN) res;
435
436 return EFI_SUCCESS;
437}
438
439#define BYTES_PER_RECORD 512
440
441EFI_STATUS
442EFIAPI
443SecPeiReportStatusCode (
ccd55824 444 IN CONST EFI_PEI_SERVICES **PeiServices,
804405e7 445 IN EFI_STATUS_CODE_TYPE CodeType,
446 IN EFI_STATUS_CODE_VALUE Value,
447 IN UINT32 Instance,
ccd55824 448 IN CONST EFI_GUID *CallerId,
449 IN CONST EFI_STATUS_CODE_DATA *Data OPTIONAL
804405e7 450 )
451/*++
452
453Routine Description:
454
455 This routine produces the ReportStatusCode PEI service. It's passed
456 up to the PEI Core via a PPI. T
457
458 This code currently uses the UNIX clib printf. This does not work the same way
459 as the EFI Print (), as %t, %g, %s as Unicode are not supported.
460
461Arguments:
462 (see EFI_PEI_REPORT_STATUS_CODE)
463
464Returns:
465 EFI_SUCCESS - Always return success
466
467--*/
468// TODO: PeiServices - add argument and description to function comment
469// TODO: CodeType - add argument and description to function comment
470// TODO: Value - add argument and description to function comment
471// TODO: Instance - add argument and description to function comment
472// TODO: CallerId - add argument and description to function comment
473// TODO: Data - add argument and description to function comment
474{
475 CHAR8 *Format;
9c98c8e1 476 BASE_LIST Marker;
804405e7 477 CHAR8 PrintBuffer[BYTES_PER_RECORD * 2];
478 CHAR8 *Filename;
479 CHAR8 *Description;
480 UINT32 LineNumber;
481 UINT32 ErrorLevel;
482
483
484 if (Data == NULL) {
485 } else if (ReportStatusCodeExtractAssertInfo (CodeType, Value, Data, &Filename, &Description, &LineNumber)) {
486 //
487 // Processes ASSERT ()
488 //
ccd55824 489 printf ("ASSERT %s(%d): %s\n", Filename, (int)LineNumber, Description);
804405e7 490
491 } else if (ReportStatusCodeExtractDebugInfo (Data, &ErrorLevel, &Marker, &Format)) {
492 //
493 // Process DEBUG () macro
494 //
9c98c8e1 495 AsciiBSPrint (PrintBuffer, BYTES_PER_RECORD, Format, Marker);
b7f76514 496 printf ("%s", PrintBuffer);
804405e7 497 }
498
499 return EFI_SUCCESS;
500}
501
502/**
503 Transfers control to a function starting with a new stack.
504
505 Transfers control to the function specified by EntryPoint using the new stack
506 specified by NewStack and passing in the parameters specified by Context1 and
507 Context2. Context1 and Context2 are optional and may be NULL. The function
508 EntryPoint must never return.
509
510 If EntryPoint is NULL, then ASSERT().
511 If NewStack is NULL, then ASSERT().
512
513 @param EntryPoint A pointer to function to call with the new stack.
514 @param Context1 A pointer to the context to pass into the EntryPoint
515 function.
516 @param Context2 A pointer to the context to pass into the EntryPoint
517 function.
518 @param NewStack A pointer to the new stack to use for the EntryPoint
519 function.
520 @param NewBsp A pointer to the new BSP for the EntryPoint on IPF. It's
521 Reserved on other architectures.
522
523**/
524VOID
525EFIAPI
526PeiSwitchStacks (
527 IN SWITCH_STACK_ENTRY_POINT EntryPoint,
528 IN VOID *Context1, OPTIONAL
529 IN VOID *Context2, OPTIONAL
530 IN VOID *Context3, OPTIONAL
531 IN VOID *NewStack
532 )
533{
534 BASE_LIBRARY_JUMP_BUFFER JumpBuffer;
535
536 ASSERT (EntryPoint != NULL);
537 ASSERT (NewStack != NULL);
538
539 //
540 // Stack should be aligned with CPU_STACK_ALIGNMENT
541 //
542 ASSERT (((UINTN)NewStack & (CPU_STACK_ALIGNMENT - 1)) == 0);
543
544 JumpBuffer.Eip = (UINTN)EntryPoint;
545 JumpBuffer.Esp = (UINTN)NewStack - sizeof (VOID*);
546 JumpBuffer.Esp -= sizeof (Context1) + sizeof (Context2) + sizeof(Context3);
547 ((VOID**)JumpBuffer.Esp)[1] = Context1;
548 ((VOID**)JumpBuffer.Esp)[2] = Context2;
549 ((VOID**)JumpBuffer.Esp)[3] = Context3;
550
551 LongJump (&JumpBuffer, (UINTN)-1);
552
553
554 //
555 // InternalSwitchStack () will never return
556 //
557 ASSERT (FALSE);
558}
559
560VOID
561SecLoadFromCore (
562 IN UINTN LargestRegion,
563 IN UINTN LargestRegionSize,
564 IN UINTN BootFirmwareVolumeBase,
565 IN VOID *PeiCorePe32File
566 )
567/*++
568
569Routine Description:
570 This is the service to load the PEI Core from the Firmware Volume
571
572Arguments:
573 LargestRegion - Memory to use for PEI.
574 LargestRegionSize - Size of Memory to use for PEI
575 BootFirmwareVolumeBase - Start of the Boot FV
576 PeiCorePe32File - PEI Core PE32
577
578Returns:
579 Success means control is transfered and thus we should never return
580
581--*/
582{
583 EFI_STATUS Status;
584 EFI_PHYSICAL_ADDRESS TopOfMemory;
585 VOID *TopOfStack;
586 UINT64 PeiCoreSize;
587 EFI_PHYSICAL_ADDRESS PeiCoreEntryPoint;
588 EFI_PHYSICAL_ADDRESS PeiImageAddress;
589 EFI_SEC_PEI_HAND_OFF *SecCoreData;
590 UINTN PeiStackSize;
591
592 //
593 // Compute Top Of Memory for Stack and PEI Core Allocations
594 //
595 TopOfMemory = LargestRegion + LargestRegionSize;
596 PeiStackSize = (UINTN)RShiftU64((UINT64)STACK_SIZE,1);
597
598 //
599 // |-----------| <---- TemporaryRamBase + TemporaryRamSize
600 // | Heap |
601 // | |
602 // |-----------| <---- StackBase / PeiTemporaryMemoryBase
603 // | |
604 // | Stack |
605 // |-----------| <---- TemporaryRamBase
606 //
607 TopOfStack = (VOID *)(LargestRegion + PeiStackSize);
608 TopOfMemory = LargestRegion + PeiStackSize;
609
610 //
611 // Reservet space for storing PeiCore's parament in stack.
612 //
613 TopOfStack = (VOID *)((UINTN)TopOfStack - sizeof (EFI_SEC_PEI_HAND_OFF) - CPU_STACK_ALIGNMENT);
614 TopOfStack = ALIGN_POINTER (TopOfStack, CPU_STACK_ALIGNMENT);
615
398b646f 616
804405e7 617 //
618 // Bind this information into the SEC hand-off state
619 //
620 SecCoreData = (EFI_SEC_PEI_HAND_OFF*)(UINTN) TopOfStack;
621 SecCoreData->DataSize = sizeof(EFI_SEC_PEI_HAND_OFF);
622 SecCoreData->BootFirmwareVolumeBase = (VOID*)BootFirmwareVolumeBase;
cdccd99e 623 SecCoreData->BootFirmwareVolumeSize = PcdGet32 (PcdUnixFirmwareFdSize);
804405e7 624 SecCoreData->TemporaryRamBase = (VOID*)(UINTN)LargestRegion;
625 SecCoreData->TemporaryRamSize = STACK_SIZE;
626 SecCoreData->StackBase = SecCoreData->TemporaryRamBase;
627 SecCoreData->StackSize = PeiStackSize;
628 SecCoreData->PeiTemporaryRamBase = (VOID*) ((UINTN) SecCoreData->TemporaryRamBase + PeiStackSize);
629 SecCoreData->PeiTemporaryRamSize = STACK_SIZE - PeiStackSize;
630
631 //
632 // Load the PEI Core from a Firmware Volume
633 //
ccd55824 634 Status = SecUnixPeiLoadFile (
804405e7 635 PeiCorePe32File,
636 &PeiImageAddress,
637 &PeiCoreSize,
638 &PeiCoreEntryPoint
639 );
640 if (EFI_ERROR (Status)) {
641 return ;
642 }
643
644 //
645 // Transfer control to the PEI Core
646 //
647 PeiSwitchStacks (
648 (SWITCH_STACK_ENTRY_POINT) (UINTN) PeiCoreEntryPoint,
649 SecCoreData,
650 (VOID *) (UINTN) ((EFI_PEI_PPI_DESCRIPTOR *) &gPrivateDispatchTable),
651 NULL,
652 TopOfStack
653 );
654 //
655 // If we get here, then the PEI Core returned. This is an error
656 //
657 return ;
658}
659
660EFI_STATUS
661EFIAPI
ccd55824 662SecUnixPeiAutoScan (
804405e7 663 IN UINTN Index,
664 OUT EFI_PHYSICAL_ADDRESS *MemoryBase,
665 OUT UINT64 *MemorySize
666 )
667/*++
668
669Routine Description:
670 This service is called from Index == 0 until it returns EFI_UNSUPPORTED.
671 It allows discontiguous memory regions to be supported by the emulator.
672 It uses gSystemMemory[] and gSystemMemoryCount that were created by
673 parsing the host environment variable EFI_MEMORY_SIZE.
674 The size comes from the varaible and the address comes from the call to
ccd55824 675 UnixOpenFile.
804405e7 676
677Arguments:
678 Index - Which memory region to use
679 MemoryBase - Return Base address of memory region
680 MemorySize - Return size in bytes of the memory region
681
682Returns:
683 EFI_SUCCESS - If memory region was mapped
684 EFI_UNSUPPORTED - If Index is not supported
685
686--*/
687{
688 void *res;
689
690 if (Index >= gSystemMemoryCount) {
691 return EFI_UNSUPPORTED;
692 }
693
694 *MemoryBase = 0;
695 res = MapMemory(0, gSystemMemory[Index].Size,
696 PROT_READ | PROT_WRITE | PROT_EXEC,
697 MAP_PRIVATE | MAP_ANONYMOUS);
698 if (res == MAP_FAILED)
699 return EFI_DEVICE_ERROR;
700 *MemorySize = gSystemMemory[Index].Size;
701 *MemoryBase = (UINTN)res;
702 gSystemMemory[Index].Memory = *MemoryBase;
703
704 return EFI_SUCCESS;
705}
706
707VOID *
708EFIAPI
ccd55824 709SecUnixUnixThunkAddress (
804405e7 710 VOID
711 )
712/*++
713
714Routine Description:
715 Since the SEC is the only Unix program in stack it must export
ccd55824 716 an interface to do POSIX calls. gUnix is initailized in UnixThunk.c.
804405e7 717
718Arguments:
719 InterfaceSize - sizeof (EFI_WIN_NT_THUNK_PROTOCOL);
ccd55824 720 InterfaceBase - Address of the gUnix global
804405e7 721
722Returns:
723 EFI_SUCCESS - Data returned
724
725--*/
726{
727 return gUnix;
728}
729
730
731EFI_STATUS
ccd55824 732SecUnixPeiLoadFile (
804405e7 733 IN VOID *Pe32Data,
ccd55824 734 OUT EFI_PHYSICAL_ADDRESS *ImageAddress,
735 OUT UINT64 *ImageSize,
736 OUT EFI_PHYSICAL_ADDRESS *EntryPoint
804405e7 737 )
738/*++
739
740Routine Description:
741 Loads and relocates a PE/COFF image into memory.
742
743Arguments:
744 Pe32Data - The base address of the PE/COFF file that is to be loaded and relocated
745 ImageAddress - The base address of the relocated PE/COFF image
746 ImageSize - The size of the relocated PE/COFF image
747 EntryPoint - The entry point of the relocated PE/COFF image
748
749Returns:
750 EFI_SUCCESS - The file was loaded and relocated
751 EFI_OUT_OF_RESOURCES - There was not enough memory to load and relocate the PE/COFF file
752
753--*/
754{
755 EFI_STATUS Status;
756 PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;
757
758 ZeroMem (&ImageContext, sizeof (ImageContext));
759 ImageContext.Handle = Pe32Data;
760
761 ImageContext.ImageRead = (PE_COFF_LOADER_READ_FILE) SecImageRead;
762
398b646f 763 Status = PeCoffLoaderGetImageInfo (&ImageContext);
804405e7 764 if (EFI_ERROR (Status)) {
765 return Status;
766 }
767 //
768 // Allocate space in UNIX (not emulator) memory. Extra space is for alignment
769 //
770 ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS) (UINTN) malloc ((UINTN) (ImageContext.ImageSize + (ImageContext.SectionAlignment * 2)));
771 if (ImageContext.ImageAddress == 0) {
772 return EFI_OUT_OF_RESOURCES;
773 }
774 //
775 // Align buffer on section boundry
776 //
f7bef78c 777 ImageContext.ImageAddress += ImageContext.SectionAlignment - 1;
804405e7 778 ImageContext.ImageAddress &= ~(ImageContext.SectionAlignment - 1);
779
780
398b646f 781 Status = PeCoffLoaderLoadImage (&ImageContext);
804405e7 782 if (EFI_ERROR (Status)) {
783 return Status;
784 }
7ee3b613
A
785
786 Status = PeCoffLoaderRelocateImage (&ImageContext);
787 if (EFI_ERROR (Status)) {
788 return Status;
789 }
790
804405e7 791
ccd55824 792 SecPeCoffRelocateImageExtraAction (&ImageContext);
804405e7 793
794 //
795 // BugBug: Flush Instruction Cache Here when CPU Lib is ready
796 //
797
798 *ImageAddress = ImageContext.ImageAddress;
799 *ImageSize = ImageContext.ImageSize;
800 *EntryPoint = ImageContext.EntryPoint;
801
802 return EFI_SUCCESS;
803}
804
ccd55824 805
806RETURN_STATUS
807EFIAPI
808SecPeCoffGetEntryPoint (
809 IN VOID *Pe32Data,
810 IN OUT VOID **EntryPoint
811 )
812{
813 EFI_STATUS Status;
814 EFI_PHYSICAL_ADDRESS ImageAddress;
815 UINT64 ImageSize;
816 EFI_PHYSICAL_ADDRESS PhysEntryPoint;
817
818 Status = SecUnixPeiLoadFile (Pe32Data, &ImageAddress, &ImageSize, &PhysEntryPoint);
819
820 *EntryPoint = (VOID *)(UINTN)PhysEntryPoint;
821 return Status;
822}
823
824
825
804405e7 826EFI_STATUS
827EFIAPI
ccd55824 828SecUnixFdAddress (
804405e7 829 IN UINTN Index,
830 IN OUT EFI_PHYSICAL_ADDRESS *FdBase,
7ee3b613
A
831 IN OUT UINT64 *FdSize,
832 IN OUT EFI_PHYSICAL_ADDRESS *FixUp
804405e7 833 )
834/*++
835
836Routine Description:
837 Return the FD Size and base address. Since the FD is loaded from a
838 file into host memory only the SEC will know it's address.
839
840Arguments:
841 Index - Which FD, starts at zero.
842 FdSize - Size of the FD in bytes
843 FdBase - Start address of the FD. Assume it points to an FV Header
7ee3b613 844 FixUp - Difference between actual FD address and build address
804405e7 845
846Returns:
847 EFI_SUCCESS - Return the Base address and size of the FV
848 EFI_UNSUPPORTED - Index does nto map to an FD in the system
849
850--*/
851{
852 if (Index >= gFdInfoCount) {
853 return EFI_UNSUPPORTED;
854 }
855
856 *FdBase = gFdInfo[Index].Address;
857 *FdSize = gFdInfo[Index].Size;
7ee3b613 858 *FixUp = 0;
804405e7 859
860 if (*FdBase == 0 && *FdSize == 0) {
861 return EFI_UNSUPPORTED;
862 }
863
7ee3b613
A
864 if (Index == 0) {
865 //
866 // FD 0 has XIP code and well known PCD values
867 // If the memory buffer could not be allocated at the FD build address
868 // the Fixup is the difference.
869 //
cdccd99e 870 *FixUp = *FdBase - PcdGet32 (PcdUnixFdBaseAddress);
7ee3b613
A
871 }
872
804405e7 873 return EFI_SUCCESS;
874}
875
876EFI_STATUS
877EFIAPI
878SecImageRead (
879 IN VOID *FileHandle,
880 IN UINTN FileOffset,
881 IN OUT UINTN *ReadSize,
882 OUT VOID *Buffer
883 )
884/*++
885
886Routine Description:
887 Support routine for the PE/COFF Loader that reads a buffer from a PE/COFF file
888
889Arguments:
890 FileHandle - The handle to the PE/COFF file
891 FileOffset - The offset, in bytes, into the file to read
892 ReadSize - The number of bytes to read from the file starting at FileOffset
893 Buffer - A pointer to the buffer to read the data into.
894
895Returns:
896 EFI_SUCCESS - ReadSize bytes of data were read into Buffer from the PE/COFF file starting at FileOffset
897
898--*/
899{
900 CHAR8 *Destination8;
901 CHAR8 *Source8;
902 UINTN Length;
903
904 Destination8 = Buffer;
905 Source8 = (CHAR8 *) ((UINTN) FileHandle + FileOffset);
906 Length = *ReadSize;
907 while (Length--) {
908 *(Destination8++) = *(Source8++);
909 }
910
911 return EFI_SUCCESS;
912}
913
914UINTN
915CountSeperatorsInString (
916 IN const CHAR16 *String,
917 IN CHAR16 Seperator
918 )
919/*++
920
921Routine Description:
922 Count the number of seperators in String
923
924Arguments:
925 String - String to process
926 Seperator - Item to count
927
928Returns:
929 Number of Seperator in String
930
931--*/
932{
933 UINTN Count;
934
935 for (Count = 0; *String != '\0'; String++) {
936 if (*String == Seperator) {
937 Count++;
938 }
939 }
940
941 return Count;
942}
943
944
ccd55824 945EFI_STATUS
946AddHandle (
947 IN PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext,
948 IN VOID *ModHandle
949 )
950/*++
951
952Routine Description:
953 Store the ModHandle in an array indexed by the Pdb File name.
954 The ModHandle is needed to unload the image.
955
956Arguments:
957 ImageContext - Input data returned from PE Laoder Library. Used to find the
958 .PDB file name of the PE Image.
959 ModHandle - Returned from LoadLibraryEx() and stored for call to
960 FreeLibrary().
961
962Returns:
963 EFI_SUCCESS - ModHandle was stored.
964
965--*/
966{
967 UINTN Index;
968 IMAGE_CONTEXT_TO_MOD_HANDLE *Array;
969 UINTN PreviousSize;
970
971
972 Array = mImageContextModHandleArray;
973 for (Index = 0; Index < mImageContextModHandleArraySize; Index++, Array++) {
974 if (Array->ImageContext == NULL) {
975 //
976 // Make a copy of the stirng and store the ModHandle
977 //
978 Array->ImageContext = ImageContext;
979 Array->ModHandle = ModHandle;
980 return EFI_SUCCESS;
981 }
982 }
983
984 //
985 // No free space in mImageContextModHandleArray so grow it by
986 // IMAGE_CONTEXT_TO_MOD_HANDLE entires. realloc will
987 // copy the old values to the new locaiton. But it does
988 // not zero the new memory area.
989 //
990 PreviousSize = mImageContextModHandleArraySize * sizeof (IMAGE_CONTEXT_TO_MOD_HANDLE);
991 mImageContextModHandleArraySize += MAX_IMAGE_CONTEXT_TO_MOD_HANDLE_ARRAY_SIZE;
992
993 mImageContextModHandleArray = realloc (mImageContextModHandleArray, mImageContextModHandleArraySize * sizeof (IMAGE_CONTEXT_TO_MOD_HANDLE));
994 if (mImageContextModHandleArray == NULL) {
995 ASSERT (FALSE);
996 return EFI_OUT_OF_RESOURCES;
997 }
998
999 memset (mImageContextModHandleArray + PreviousSize, 0, MAX_IMAGE_CONTEXT_TO_MOD_HANDLE_ARRAY_SIZE * sizeof (IMAGE_CONTEXT_TO_MOD_HANDLE));
1000
1001 return AddHandle (ImageContext, ModHandle);
1002}
1003
1004
1005VOID *
1006RemoveHandle (
1007 IN PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
1008 )
1009/*++
1010
1011Routine Description:
1012 Return the ModHandle and delete the entry in the array.
1013
1014Arguments:
1015 ImageContext - Input data returned from PE Laoder Library. Used to find the
1016 .PDB file name of the PE Image.
1017
1018Returns:
1019 ModHandle - ModHandle assoicated with ImageContext is returned
1020 NULL - No ModHandle associated with ImageContext
1021
1022--*/
1023{
1024 UINTN Index;
1025 IMAGE_CONTEXT_TO_MOD_HANDLE *Array;
1026
1027 if (ImageContext->PdbPointer == NULL) {
1028 //
1029 // If no PDB pointer there is no ModHandle so return NULL
1030 //
1031 return NULL;
1032 }
1033
1034 Array = mImageContextModHandleArray;
1035 for (Index = 0; Index < mImageContextModHandleArraySize; Index++, Array++) {
1036 if ((Array->ImageContext == ImageContext)) {
1037 //
1038 // If you find a match return it and delete the entry
1039 //
1040 Array->ImageContext = NULL;
1041 return Array->ModHandle;
1042 }
1043 }
1044
1045 return NULL;
1046}
1047
1048
1049
1050//
1051// Target for gdb breakpoint in a script that uses gGdbWorkingFileName to source a
1052// add-symbol-file command. Hey what can you say scripting in gdb is not that great....
1053//
1054// Put .gdbinit in the CWD where you do gdb SecMain.dll for source level debug
1055//
1056// cat .gdbinit
1057// b SecGdbScriptBreak
1058// command
1059// silent
1060// source SecMain.dll.gdb
1061// c
1062// end
1063//
1064VOID
1065SecGdbScriptBreak (
1066 VOID
1067 )
1068{
1069}
804405e7 1070
804405e7 1071VOID
1072SecUnixLoaderBreak (
1073 VOID
1074 )
1075{
1076}
1077
ccd55824 1078BOOLEAN
1079IsPdbFile (
1080 IN CHAR8 *PdbFileName
1081 )
1082{
1083 UINTN Len;
1084
1085 if (PdbFileName == NULL) {
1086 return FALSE;
1087 }
1088
1089 Len = strlen (PdbFileName);
1090 if ((Len < 5)|| (PdbFileName[Len - 4] != '.')) {
1091 return FALSE;
1092 }
1093
1094 if ((PdbFileName[Len - 3] == 'P' || PdbFileName[Len - 3] == 'p') &&
1095 (PdbFileName[Len - 2] == 'D' || PdbFileName[Len - 2] == 'd') &&
1096 (PdbFileName[Len - 1] == 'B' || PdbFileName[Len - 1] == 'b')) {
1097 return TRUE;
1098 }
1099
1100 return FALSE;
1101}
1102
1103
1104#define MAX_SPRINT_BUFFER_SIZE 0x200
1105
1106void
1107PrintLoadAddress (
1108 IN PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
1109 )
1110{
1111 fprintf (stderr,
1112 "0x%08lx Loading %s with entry point 0x%08lx\n",
1113 (unsigned long)ImageContext->ImageAddress + ImageContext->SizeOfHeaders,
1114 ImageContext->PdbPointer,
1115 (unsigned long)ImageContext->EntryPoint
1116 );
1117
1118 // Keep output synced up
1119 fflush (stderr);
1120}
1121
1122
1123VOID
804405e7 1124EFIAPI
ccd55824 1125SecPeCoffRelocateImageExtraAction (
804405e7 1126 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
1127 )
1128{
ccd55824 1129
1130#ifdef __APPLE__
1131 PrintLoadAddress (ImageContext);
1132
1133 //
1134 // In mach-o (OS X executable) dlopen() can only load files in the MH_DYLIB of MH_BUNDLE format.
1135 // To convert to PE/COFF we need to construct a mach-o with the MH_PRELOAD format. We create
1136 // .dSYM files for the PE/COFF images that can be used by gdb for source level debugging.
1137 //
1138 FILE *GdbTempFile;
1139
1140 //
1141 // In the Mach-O to PE/COFF conversion the size of the PE/COFF headers is not accounted for.
1142 // Thus we need to skip over the PE/COFF header when giving load addresses for our symbol table.
1143 //
1144 if (ImageContext->PdbPointer != NULL && !IsPdbFile (ImageContext->PdbPointer)) {
1145 //
1146 // Now we have a database of the images that are currently loaded
1147 //
1148
1149 //
1150 // 'symbol-file' will clear out currnet symbol mappings in gdb.
1151 // you can do a 'add-symbol-file filename address' for every image we loaded to get source
1152 // level debug in gdb. Note Sec, being a true application will work differently.
1153 //
1154 // We add the PE/COFF header size into the image as the mach-O does not have a header in
1155 // loaded into system memory.
1156 //
1157 // This gives us a data base of gdb commands and after something is unloaded that entry will be
1158 // removed. We don't yet have the scheme of how to comunicate with gdb, but we have the
1159 // data base of info ready to roll.
1160 //
1161 // We could use qXfer:libraries:read, but OS X GDB does not currently support it.
1162 // <library-list>
1163 // <library name="/lib/libc.so.6"> // ImageContext->PdbPointer
1164 // <segment address="0x10000000"/> // ImageContext->ImageAddress + ImageContext->SizeOfHeaders
1165 // </library>
1166 // </library-list>
1167 //
1168
1169 //
1170 // Write the file we need for the gdb script
1171 //
1172 GdbTempFile = fopen (gGdbWorkingFileName, "w");
1173 if (GdbTempFile != NULL) {
1174 fprintf (GdbTempFile, "add-symbol-file %s 0x%x\n", ImageContext->PdbPointer, (UINTN)(ImageContext->ImageAddress + ImageContext->SizeOfHeaders));
1175 fclose (GdbTempFile);
1176
1177 //
1178 // Target for gdb breakpoint in a script that uses gGdbWorkingFileName to set a breakpoint.
1179 // Hey what can you say scripting in gdb is not that great....
1180 //
1181 SecGdbScriptBreak ();
1182 }
1183
1184 AddHandle (ImageContext, ImageContext->PdbPointer);
1185
1186 }
1187
1188#else
1189
1190 void *Handle = NULL;
1191 void *Entry = NULL;
1192
804405e7 1193 fprintf (stderr,
1194 "Loading %s 0x%08lx - entry point 0x%08lx\n",
1195 ImageContext->PdbPointer,
1196 (unsigned long)ImageContext->ImageAddress,
1197 (unsigned long)ImageContext->EntryPoint);
1198
7ee3b613 1199 Handle = dlopen (ImageContext->PdbPointer, RTLD_NOW);
865c7e17 1200
1201 if (Handle) {
7ee3b613 1202 Entry = dlsym (Handle, "_ModuleEntryPoint");
865c7e17 1203 } else {
1204 printf("%s\n", dlerror());
1205 }
1206
1207 if (Entry != NULL) {
ccd55824 1208 ImageContext->EntryPoint = (UINTN)Entry;
1209 printf("Change %s Entrypoint to :0x%08lx\n", ImageContext->PdbPointer, (unsigned long)Entry);
865c7e17 1210 }
1211
804405e7 1212 SecUnixLoaderBreak ();
1213
ccd55824 1214#endif
1215
1216 return;
804405e7 1217}
1218
1219
ccd55824 1220VOID
804405e7 1221EFIAPI
ccd55824 1222SecPeCoffLoaderUnloadImageExtraAction (
804405e7 1223 IN PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
1224 )
1225{
ccd55824 1226 VOID *Handle;
1227
1228 Handle = RemoveHandle (ImageContext);
1229
1230#ifdef __APPLE__
1231 FILE *GdbTempFile;
1232
1233 if (Handle != NULL) {
1234 //
1235 // Need to skip .PDB files created from VC++
1236 //
1237 if (!IsPdbFile (ImageContext->PdbPointer)) {
1238 //
1239 // Write the file we need for the gdb script
1240 //
1241 GdbTempFile = fopen (gGdbWorkingFileName, "w");
1242 if (GdbTempFile != NULL) {
1243 fprintf (GdbTempFile, "remove-symbol-file %s\n", ImageContext->PdbPointer);
1244 fclose (GdbTempFile);
1245
1246 //
1247 // Target for gdb breakpoint in a script that uses gGdbWorkingFileName to set a breakpoint.
1248 // Hey what can you say scripting in gdb is not that great....
1249 //
1250 SecGdbScriptBreak ();
1251 }
1252 }
1253 }
1254
1255#else
1256 //
1257 // Don't want to confuse gdb with symbols for something that got unloaded
1258 //
1259 if (Handle != NULL) {
1260 dlclose (Handle);
1261 }
1262
1263#endif
1264 return;
804405e7 1265}
1266
1267VOID
1268ModuleEntryPoint (
1269 VOID
1270 )
1271{
1272}
1273
1274EFI_STATUS
1275EFIAPI
1276SecTemporaryRamSupport (
1277 IN CONST EFI_PEI_SERVICES **PeiServices,
1278 IN EFI_PHYSICAL_ADDRESS TemporaryMemoryBase,
1279 IN EFI_PHYSICAL_ADDRESS PermanentMemoryBase,
1280 IN UINTN CopySize
1281 )
1282{
1283 //
1284 // Migrate the whole temporary memory to permenent memory.
1285 //
1286 CopyMem (
1287 (VOID*)(UINTN)PermanentMemoryBase,
1288 (VOID*)(UINTN)TemporaryMemoryBase,
1289 CopySize
1290 );
1291
1292 //
1293 // SecSwitchStack function must be invoked after the memory migration
1294 // immediatly, also we need fixup the stack change caused by new call into
1295 // permenent memory.
1296 //
1297 SecSwitchStack (
1298 (UINT32) TemporaryMemoryBase,
1299 (UINT32) PermanentMemoryBase
1300 );
1301
1302 //
1303 // We need *not* fix the return address because currently,
1304 // The PeiCore is excuted in flash.
1305 //
1306
1307 //
1fd8c31a 1308 // Simulate to invalid temporary memory, terminate temporary memory
804405e7 1309 //
1310 //ZeroMem ((VOID*)(UINTN)TemporaryMemoryBase, CopySize);
1311
1312 return EFI_SUCCESS;
1313}