]> git.proxmox.com Git - mirror_edk2.git/blob - UnixPkg/Sec/SecMain.c
Remove over-specified dependencies on IntelFrameworkPkg and IntelFrameworkModulePkg.
[mirror_edk2.git] / UnixPkg / Sec / SecMain.c
1 /*++
2
3 Copyright (c) 2006 - 2010, Intel Corporation.
4 Portions copyright (c) 2008-2009 Apple Inc.
5 All rights reserved. This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
9
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12
13 Module Name:
14
15 SecMain.c
16
17 Abstract:
18 Unix emulator of SEC phase. It's really a Posix application, but this is
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>
39 #include <Ppi/TemporaryRamSupport.h>
40 #include <dlfcn.h>
41
42 #ifdef __APPLE__
43 #define MAP_ANONYMOUS MAP_ANON
44 char *gGdbWorkingFileName = NULL;
45 #endif
46
47
48 //
49 // Globals
50 //
51
52 UNIX_PEI_LOAD_FILE_PPI mSecUnixLoadFilePpi = { SecUnixPeiLoadFile };
53
54 PEI_UNIX_AUTOSCAN_PPI mSecUnixAutoScanPpi = { SecUnixPeiAutoScan };
55
56 PEI_UNIX_THUNK_PPI mSecUnixThunkPpi = { SecUnixUnixThunkAddress };
57
58 EFI_PEI_PROGRESS_CODE_PPI mSecStatusCodePpi = { SecPeiReportStatusCode };
59
60 UNIX_FWH_PPI mSecFwhInformationPpi = { SecUnixFdAddress };
61
62 TEMPORARY_RAM_SUPPORT_PPI mSecTemporaryRamSupportPpi = {SecTemporaryRamSupport};
63
64 EFI_PEI_PPI_DESCRIPTOR gPrivateDispatchTable[] = {
65 {
66 EFI_PEI_PPI_DESCRIPTOR_PPI,
67 &gUnixPeiLoadFilePpiGuid,
68 &mSecUnixLoadFilePpi
69 },
70 {
71 EFI_PEI_PPI_DESCRIPTOR_PPI,
72 &gPeiUnixAutoScanPpiGuid,
73 &mSecUnixAutoScanPpi
74 },
75 {
76 EFI_PEI_PPI_DESCRIPTOR_PPI,
77 &gPeiUnixThunkPpiGuid,
78 &mSecUnixThunkPpi
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 {
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 //
105 UINTN gFdInfoCount = 0;
106 UNIX_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 //
114 UINTN gSystemMemoryCount = 0;
115 UNIX_SYSTEM_MEMORY *gSystemMemory;
116
117
118
119 UINTN mImageContextModHandleArraySize = 0;
120 IMAGE_CONTEXT_TO_MOD_HANDLE *mImageContextModHandleArray = NULL;
121
122
123 VOID
124 EFIAPI
125 SecSwitchStack (
126 UINT32 TemporaryMemoryBase,
127 UINT32 PermenentMemoryBase
128 );
129
130 EFI_PHYSICAL_ADDRESS *
131 MapMemory (
132 INTN fd,
133 UINT64 length,
134 INTN prot,
135 INTN flags);
136
137 EFI_STATUS
138 MapFile (
139 IN CHAR8 *FileName,
140 IN OUT EFI_PHYSICAL_ADDRESS *BaseAddress,
141 OUT UINT64 *Length
142 );
143
144 EFI_STATUS
145 EFIAPI
146 SecNt32PeCoffRelocateImage (
147 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
148 );
149
150
151 int
152 main (
153 IN int Argc,
154 IN char **Argv,
155 IN char **Envp
156 )
157 /*++
158
159 Routine Description:
160 Main entry point to SEC for Unix. This is a unix program
161
162 Arguments:
163 Argc - Number of command line arguments
164 Argv - Array of command line argument strings
165 Envp - Array of environmemt variable strings
166
167 Returns:
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
190 MemorySizeStr = (CHAR16 *) PcdGetPtr (PcdUnixMemorySizeForSecMain);
191 FirmwareVolumesStr = (CHAR16 *) PcdGetPtr (PcdUnixFirmwareVolume);
192
193 printf ("\nEDK SEC Main UNIX Emulation Environment from www.TianoCore.org\n");
194
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);
202 gGdbWorkingFileName = malloc (Index + strlen(".gdb") + 1);
203 strcpy (gGdbWorkingFileName, *Argv);
204 strcat (gGdbWorkingFileName, ".gdb");
205 #endif
206
207
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 //
229 printf (" BootMode 0x%02x\n", (unsigned int)PcdGet32 (PcdUnixBootMode));
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.
234 // Set InitialStackMemory to zero so UnixOpenFile will allocate a new mapping
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",
247 (unsigned int)(InitialStackMemorySize / 1024),
248 (unsigned long)InitialStackMemory);
249
250 for (StackPointer = (UINTN*) (UINTN) InitialStackMemory;
251 StackPointer < (UINTN*)(UINTN)((UINTN) InitialStackMemory + (UINT64) InitialStackMemorySize);
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)) {
284 printf ("ERROR : Can not open Firmware Device File %s (%x). Exiting.\n", FileName, (unsigned int)Status);
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
342 EFI_PHYSICAL_ADDRESS *
343 MapMemory (
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
374 EFI_STATUS
375 MapFile (
376 IN CHAR8 *FileName,
377 IN OUT EFI_PHYSICAL_ADDRESS *BaseAddress,
378 OUT UINT64 *Length
379 )
380 /*++
381
382 Routine Description:
383 Opens and memory maps a file using Unix services. If BaseAddress is non zero
384 the process will try and allocate the memory starting at BaseAddress.
385
386 Arguments:
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
397 Returns:
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
441 EFI_STATUS
442 EFIAPI
443 SecPeiReportStatusCode (
444 IN CONST EFI_PEI_SERVICES **PeiServices,
445 IN EFI_STATUS_CODE_TYPE CodeType,
446 IN EFI_STATUS_CODE_VALUE Value,
447 IN UINT32 Instance,
448 IN CONST EFI_GUID *CallerId,
449 IN CONST EFI_STATUS_CODE_DATA *Data OPTIONAL
450 )
451 /*++
452
453 Routine 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
461 Arguments:
462 (see EFI_PEI_REPORT_STATUS_CODE)
463
464 Returns:
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;
476 BASE_LIST Marker;
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 //
489 printf ("ASSERT %s(%d): %s\n", Filename, (int)LineNumber, Description);
490
491 } else if (ReportStatusCodeExtractDebugInfo (Data, &ErrorLevel, &Marker, &Format)) {
492 //
493 // Process DEBUG () macro
494 //
495 AsciiBSPrint (PrintBuffer, BYTES_PER_RECORD, Format, Marker);
496 printf ("%s", PrintBuffer);
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 **/
524 VOID
525 EFIAPI
526 PeiSwitchStacks (
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
560 VOID
561 SecLoadFromCore (
562 IN UINTN LargestRegion,
563 IN UINTN LargestRegionSize,
564 IN UINTN BootFirmwareVolumeBase,
565 IN VOID *PeiCorePe32File
566 )
567 /*++
568
569 Routine Description:
570 This is the service to load the PEI Core from the Firmware Volume
571
572 Arguments:
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
578 Returns:
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
616
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;
623 SecCoreData->BootFirmwareVolumeSize = PcdGet32 (PcdUnixFirmwareFdSize);
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 //
634 Status = SecUnixPeiLoadFile (
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
660 EFI_STATUS
661 EFIAPI
662 SecUnixPeiAutoScan (
663 IN UINTN Index,
664 OUT EFI_PHYSICAL_ADDRESS *MemoryBase,
665 OUT UINT64 *MemorySize
666 )
667 /*++
668
669 Routine 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
675 UnixOpenFile.
676
677 Arguments:
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
682 Returns:
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
707 VOID *
708 EFIAPI
709 SecUnixUnixThunkAddress (
710 VOID
711 )
712 /*++
713
714 Routine Description:
715 Since the SEC is the only Unix program in stack it must export
716 an interface to do POSIX calls. gUnix is initailized in UnixThunk.c.
717
718 Arguments:
719 InterfaceSize - sizeof (EFI_WIN_NT_THUNK_PROTOCOL);
720 InterfaceBase - Address of the gUnix global
721
722 Returns:
723 EFI_SUCCESS - Data returned
724
725 --*/
726 {
727 return gUnix;
728 }
729
730
731 EFI_STATUS
732 SecUnixPeiLoadFile (
733 IN VOID *Pe32Data,
734 OUT EFI_PHYSICAL_ADDRESS *ImageAddress,
735 OUT UINT64 *ImageSize,
736 OUT EFI_PHYSICAL_ADDRESS *EntryPoint
737 )
738 /*++
739
740 Routine Description:
741 Loads and relocates a PE/COFF image into memory.
742
743 Arguments:
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
749 Returns:
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
763 Status = PeCoffLoaderGetImageInfo (&ImageContext);
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 //
777 ImageContext.ImageAddress += ImageContext.SectionAlignment - 1;
778 ImageContext.ImageAddress &= ~(ImageContext.SectionAlignment - 1);
779
780
781 Status = PeCoffLoaderLoadImage (&ImageContext);
782 if (EFI_ERROR (Status)) {
783 return Status;
784 }
785
786 Status = PeCoffLoaderRelocateImage (&ImageContext);
787 if (EFI_ERROR (Status)) {
788 return Status;
789 }
790
791
792 SecPeCoffRelocateImageExtraAction (&ImageContext);
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
805
806 RETURN_STATUS
807 EFIAPI
808 SecPeCoffGetEntryPoint (
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
826 EFI_STATUS
827 EFIAPI
828 SecUnixFdAddress (
829 IN UINTN Index,
830 IN OUT EFI_PHYSICAL_ADDRESS *FdBase,
831 IN OUT UINT64 *FdSize,
832 IN OUT EFI_PHYSICAL_ADDRESS *FixUp
833 )
834 /*++
835
836 Routine 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
840 Arguments:
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
844 FixUp - Difference between actual FD address and build address
845
846 Returns:
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;
858 *FixUp = 0;
859
860 if (*FdBase == 0 && *FdSize == 0) {
861 return EFI_UNSUPPORTED;
862 }
863
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 //
870 *FixUp = *FdBase - PcdGet32 (PcdUnixFdBaseAddress);
871 }
872
873 return EFI_SUCCESS;
874 }
875
876 EFI_STATUS
877 EFIAPI
878 SecImageRead (
879 IN VOID *FileHandle,
880 IN UINTN FileOffset,
881 IN OUT UINTN *ReadSize,
882 OUT VOID *Buffer
883 )
884 /*++
885
886 Routine Description:
887 Support routine for the PE/COFF Loader that reads a buffer from a PE/COFF file
888
889 Arguments:
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
895 Returns:
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
914 UINTN
915 CountSeperatorsInString (
916 IN const CHAR16 *String,
917 IN CHAR16 Seperator
918 )
919 /*++
920
921 Routine Description:
922 Count the number of seperators in String
923
924 Arguments:
925 String - String to process
926 Seperator - Item to count
927
928 Returns:
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
945 EFI_STATUS
946 AddHandle (
947 IN PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext,
948 IN VOID *ModHandle
949 )
950 /*++
951
952 Routine Description:
953 Store the ModHandle in an array indexed by the Pdb File name.
954 The ModHandle is needed to unload the image.
955
956 Arguments:
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
962 Returns:
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
1005 VOID *
1006 RemoveHandle (
1007 IN PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
1008 )
1009 /*++
1010
1011 Routine Description:
1012 Return the ModHandle and delete the entry in the array.
1013
1014 Arguments:
1015 ImageContext - Input data returned from PE Laoder Library. Used to find the
1016 .PDB file name of the PE Image.
1017
1018 Returns:
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 //
1064 VOID
1065 SecGdbScriptBreak (
1066 VOID
1067 )
1068 {
1069 }
1070
1071 VOID
1072 SecUnixLoaderBreak (
1073 VOID
1074 )
1075 {
1076 }
1077
1078 BOOLEAN
1079 IsPdbFile (
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
1106 void
1107 PrintLoadAddress (
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
1123 VOID
1124 EFIAPI
1125 SecPeCoffRelocateImageExtraAction (
1126 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
1127 )
1128 {
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
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
1199 Handle = dlopen (ImageContext->PdbPointer, RTLD_NOW);
1200
1201 if (Handle) {
1202 Entry = dlsym (Handle, "_ModuleEntryPoint");
1203 } else {
1204 printf("%s\n", dlerror());
1205 }
1206
1207 if (Entry != NULL) {
1208 ImageContext->EntryPoint = (UINTN)Entry;
1209 printf("Change %s Entrypoint to :0x%08lx\n", ImageContext->PdbPointer, (unsigned long)Entry);
1210 }
1211
1212 SecUnixLoaderBreak ();
1213
1214 #endif
1215
1216 return;
1217 }
1218
1219
1220 VOID
1221 EFIAPI
1222 SecPeCoffLoaderUnloadImageExtraAction (
1223 IN PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
1224 )
1225 {
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;
1265 }
1266
1267 VOID
1268 ModuleEntryPoint (
1269 VOID
1270 )
1271 {
1272 }
1273
1274 EFI_STATUS
1275 EFIAPI
1276 SecTemporaryRamSupport (
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 //
1308 // Simulate to invalid temporary memory, terminate temporary memory
1309 //
1310 //ZeroMem ((VOID*)(UINTN)TemporaryMemoryBase, CopySize);
1311
1312 return EFI_SUCCESS;
1313 }