]> git.proxmox.com Git - mirror_edk2.git/blob - UnixPkg/Sec/SecMain.c
b232f5f54922a9fa99b5174dd0b1f77976f87c9c
[mirror_edk2.git] / UnixPkg / Sec / SecMain.c
1 /*++
2
3 Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>
4 Portions copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR>
5 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 edk2.sourceforge.net\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 | PROT_EXEC,
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 VOID
503 EFIAPI
504 PeiSwitchStacks (
505 IN SWITCH_STACK_ENTRY_POINT EntryPoint,
506 IN VOID *Context1, OPTIONAL
507 IN VOID *Context2, OPTIONAL
508 IN VOID *Context3, OPTIONAL
509 IN VOID *NewStack
510 );
511
512 VOID
513 SecLoadFromCore (
514 IN UINTN LargestRegion,
515 IN UINTN LargestRegionSize,
516 IN UINTN BootFirmwareVolumeBase,
517 IN VOID *PeiCorePe32File
518 )
519 /*++
520
521 Routine Description:
522 This is the service to load the PEI Core from the Firmware Volume
523
524 Arguments:
525 LargestRegion - Memory to use for PEI.
526 LargestRegionSize - Size of Memory to use for PEI
527 BootFirmwareVolumeBase - Start of the Boot FV
528 PeiCorePe32File - PEI Core PE32
529
530 Returns:
531 Success means control is transfered and thus we should never return
532
533 --*/
534 {
535 EFI_STATUS Status;
536 EFI_PHYSICAL_ADDRESS TopOfMemory;
537 VOID *TopOfStack;
538 UINT64 PeiCoreSize;
539 EFI_PHYSICAL_ADDRESS PeiCoreEntryPoint;
540 EFI_PHYSICAL_ADDRESS PeiImageAddress;
541 EFI_SEC_PEI_HAND_OFF *SecCoreData;
542 UINTN PeiStackSize;
543
544 //
545 // Compute Top Of Memory for Stack and PEI Core Allocations
546 //
547 TopOfMemory = LargestRegion + LargestRegionSize;
548 PeiStackSize = (UINTN)RShiftU64((UINT64)STACK_SIZE,1);
549
550 //
551 // |-----------| <---- TemporaryRamBase + TemporaryRamSize
552 // | Heap |
553 // | |
554 // |-----------| <---- StackBase / PeiTemporaryMemoryBase
555 // | |
556 // | Stack |
557 // |-----------| <---- TemporaryRamBase
558 //
559 TopOfStack = (VOID *)(LargestRegion + PeiStackSize);
560 TopOfMemory = LargestRegion + PeiStackSize;
561
562 //
563 // Reservet space for storing PeiCore's parament in stack.
564 //
565 TopOfStack = (VOID *)((UINTN)TopOfStack - sizeof (EFI_SEC_PEI_HAND_OFF) - CPU_STACK_ALIGNMENT);
566 TopOfStack = ALIGN_POINTER (TopOfStack, CPU_STACK_ALIGNMENT);
567
568
569 //
570 // Bind this information into the SEC hand-off state
571 //
572 SecCoreData = (EFI_SEC_PEI_HAND_OFF*)(UINTN) TopOfStack;
573 SecCoreData->DataSize = sizeof(EFI_SEC_PEI_HAND_OFF);
574 SecCoreData->BootFirmwareVolumeBase = (VOID*)BootFirmwareVolumeBase;
575 SecCoreData->BootFirmwareVolumeSize = PcdGet32 (PcdUnixFirmwareFdSize);
576 SecCoreData->TemporaryRamBase = (VOID*)(UINTN)LargestRegion;
577 SecCoreData->TemporaryRamSize = STACK_SIZE;
578 SecCoreData->StackBase = SecCoreData->TemporaryRamBase;
579 SecCoreData->StackSize = PeiStackSize;
580 SecCoreData->PeiTemporaryRamBase = (VOID*) ((UINTN) SecCoreData->TemporaryRamBase + PeiStackSize);
581 SecCoreData->PeiTemporaryRamSize = STACK_SIZE - PeiStackSize;
582
583 //
584 // Load the PEI Core from a Firmware Volume
585 //
586 Status = SecUnixPeiLoadFile (
587 PeiCorePe32File,
588 &PeiImageAddress,
589 &PeiCoreSize,
590 &PeiCoreEntryPoint
591 );
592 if (EFI_ERROR (Status)) {
593 return ;
594 }
595
596 //
597 // Transfer control to the PEI Core
598 //
599 PeiSwitchStacks (
600 (SWITCH_STACK_ENTRY_POINT) (UINTN) PeiCoreEntryPoint,
601 SecCoreData,
602 (VOID *) (UINTN) ((EFI_PEI_PPI_DESCRIPTOR *) &gPrivateDispatchTable),
603 NULL,
604 TopOfStack
605 );
606 //
607 // If we get here, then the PEI Core returned. This is an error
608 //
609 return ;
610 }
611
612 EFI_STATUS
613 EFIAPI
614 SecUnixPeiAutoScan (
615 IN UINTN Index,
616 OUT EFI_PHYSICAL_ADDRESS *MemoryBase,
617 OUT UINT64 *MemorySize
618 )
619 /*++
620
621 Routine Description:
622 This service is called from Index == 0 until it returns EFI_UNSUPPORTED.
623 It allows discontiguous memory regions to be supported by the emulator.
624 It uses gSystemMemory[] and gSystemMemoryCount that were created by
625 parsing the host environment variable EFI_MEMORY_SIZE.
626 The size comes from the varaible and the address comes from the call to
627 UnixOpenFile.
628
629 Arguments:
630 Index - Which memory region to use
631 MemoryBase - Return Base address of memory region
632 MemorySize - Return size in bytes of the memory region
633
634 Returns:
635 EFI_SUCCESS - If memory region was mapped
636 EFI_UNSUPPORTED - If Index is not supported
637
638 --*/
639 {
640 void *res;
641
642 if (Index >= gSystemMemoryCount) {
643 return EFI_UNSUPPORTED;
644 }
645
646 *MemoryBase = 0;
647 res = MapMemory(0, gSystemMemory[Index].Size,
648 PROT_READ | PROT_WRITE | PROT_EXEC,
649 MAP_PRIVATE | MAP_ANONYMOUS);
650 if (res == MAP_FAILED)
651 return EFI_DEVICE_ERROR;
652 *MemorySize = gSystemMemory[Index].Size;
653 *MemoryBase = (UINTN)res;
654 gSystemMemory[Index].Memory = *MemoryBase;
655
656 return EFI_SUCCESS;
657 }
658
659 VOID *
660 EFIAPI
661 SecUnixUnixThunkAddress (
662 VOID
663 )
664 /*++
665
666 Routine Description:
667 Since the SEC is the only Unix program in stack it must export
668 an interface to do POSIX calls. gUnix is initailized in UnixThunk.c.
669
670 Arguments:
671 InterfaceSize - sizeof (EFI_WIN_NT_THUNK_PROTOCOL);
672 InterfaceBase - Address of the gUnix global
673
674 Returns:
675 EFI_SUCCESS - Data returned
676
677 --*/
678 {
679 return gUnix;
680 }
681
682
683 EFI_STATUS
684 SecUnixPeiLoadFile (
685 IN VOID *Pe32Data,
686 OUT EFI_PHYSICAL_ADDRESS *ImageAddress,
687 OUT UINT64 *ImageSize,
688 OUT EFI_PHYSICAL_ADDRESS *EntryPoint
689 )
690 /*++
691
692 Routine Description:
693 Loads and relocates a PE/COFF image into memory.
694
695 Arguments:
696 Pe32Data - The base address of the PE/COFF file that is to be loaded and relocated
697 ImageAddress - The base address of the relocated PE/COFF image
698 ImageSize - The size of the relocated PE/COFF image
699 EntryPoint - The entry point of the relocated PE/COFF image
700
701 Returns:
702 EFI_SUCCESS - The file was loaded and relocated
703 EFI_OUT_OF_RESOURCES - There was not enough memory to load and relocate the PE/COFF file
704
705 --*/
706 {
707 EFI_STATUS Status;
708 PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;
709
710 ZeroMem (&ImageContext, sizeof (ImageContext));
711 ImageContext.Handle = Pe32Data;
712
713 ImageContext.ImageRead = (PE_COFF_LOADER_READ_FILE) SecImageRead;
714
715 Status = PeCoffLoaderGetImageInfo (&ImageContext);
716 if (EFI_ERROR (Status)) {
717 return Status;
718 }
719
720
721 //
722 // Allocate space in UNIX (not emulator) memory. Extra space is for alignment
723 //
724 ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS) (UINTN) MapMemory (
725 0,
726 (UINT32) (ImageContext.ImageSize + (ImageContext.SectionAlignment * 2)),
727 PROT_READ | PROT_WRITE | PROT_EXEC,
728 MAP_ANONYMOUS | MAP_PRIVATE
729 );
730 if (ImageContext.ImageAddress == 0) {
731 return EFI_OUT_OF_RESOURCES;
732 }
733
734 //
735 // Align buffer on section boundry
736 //
737 ImageContext.ImageAddress += ImageContext.SectionAlignment - 1;
738 ImageContext.ImageAddress &= ~((EFI_PHYSICAL_ADDRESS)(ImageContext.SectionAlignment - 1));
739
740
741 Status = PeCoffLoaderLoadImage (&ImageContext);
742 if (EFI_ERROR (Status)) {
743 return Status;
744 }
745
746 Status = PeCoffLoaderRelocateImage (&ImageContext);
747 if (EFI_ERROR (Status)) {
748 return Status;
749 }
750
751
752 SecPeCoffRelocateImageExtraAction (&ImageContext);
753
754 //
755 // BugBug: Flush Instruction Cache Here when CPU Lib is ready
756 //
757
758 *ImageAddress = ImageContext.ImageAddress;
759 *ImageSize = ImageContext.ImageSize;
760 *EntryPoint = ImageContext.EntryPoint;
761
762 return EFI_SUCCESS;
763 }
764
765
766 RETURN_STATUS
767 EFIAPI
768 SecPeCoffGetEntryPoint (
769 IN VOID *Pe32Data,
770 IN OUT VOID **EntryPoint
771 )
772 {
773 EFI_STATUS Status;
774 EFI_PHYSICAL_ADDRESS ImageAddress;
775 UINT64 ImageSize;
776 EFI_PHYSICAL_ADDRESS PhysEntryPoint;
777
778 Status = SecUnixPeiLoadFile (Pe32Data, &ImageAddress, &ImageSize, &PhysEntryPoint);
779
780 *EntryPoint = (VOID *)(UINTN)PhysEntryPoint;
781 return Status;
782 }
783
784
785
786 EFI_STATUS
787 EFIAPI
788 SecUnixFdAddress (
789 IN UINTN Index,
790 IN OUT EFI_PHYSICAL_ADDRESS *FdBase,
791 IN OUT UINT64 *FdSize,
792 IN OUT EFI_PHYSICAL_ADDRESS *FixUp
793 )
794 /*++
795
796 Routine Description:
797 Return the FD Size and base address. Since the FD is loaded from a
798 file into host memory only the SEC will know it's address.
799
800 Arguments:
801 Index - Which FD, starts at zero.
802 FdSize - Size of the FD in bytes
803 FdBase - Start address of the FD. Assume it points to an FV Header
804 FixUp - Difference between actual FD address and build address
805
806 Returns:
807 EFI_SUCCESS - Return the Base address and size of the FV
808 EFI_UNSUPPORTED - Index does nto map to an FD in the system
809
810 --*/
811 {
812 if (Index >= gFdInfoCount) {
813 return EFI_UNSUPPORTED;
814 }
815
816 *FdBase = gFdInfo[Index].Address;
817 *FdSize = gFdInfo[Index].Size;
818 *FixUp = 0;
819
820 if (*FdBase == 0 && *FdSize == 0) {
821 return EFI_UNSUPPORTED;
822 }
823
824 if (Index == 0) {
825 //
826 // FD 0 has XIP code and well known PCD values
827 // If the memory buffer could not be allocated at the FD build address
828 // the Fixup is the difference.
829 //
830 *FixUp = *FdBase - PcdGet32 (PcdUnixFdBaseAddress);
831 }
832
833 return EFI_SUCCESS;
834 }
835
836 EFI_STATUS
837 EFIAPI
838 SecImageRead (
839 IN VOID *FileHandle,
840 IN UINTN FileOffset,
841 IN OUT UINTN *ReadSize,
842 OUT VOID *Buffer
843 )
844 /*++
845
846 Routine Description:
847 Support routine for the PE/COFF Loader that reads a buffer from a PE/COFF file
848
849 Arguments:
850 FileHandle - The handle to the PE/COFF file
851 FileOffset - The offset, in bytes, into the file to read
852 ReadSize - The number of bytes to read from the file starting at FileOffset
853 Buffer - A pointer to the buffer to read the data into.
854
855 Returns:
856 EFI_SUCCESS - ReadSize bytes of data were read into Buffer from the PE/COFF file starting at FileOffset
857
858 --*/
859 {
860 CHAR8 *Destination8;
861 CHAR8 *Source8;
862 UINTN Length;
863
864 Destination8 = Buffer;
865 Source8 = (CHAR8 *) ((UINTN) FileHandle + FileOffset);
866 Length = *ReadSize;
867 while (Length--) {
868 *(Destination8++) = *(Source8++);
869 }
870
871 return EFI_SUCCESS;
872 }
873
874 UINTN
875 CountSeperatorsInString (
876 IN const CHAR16 *String,
877 IN CHAR16 Seperator
878 )
879 /*++
880
881 Routine Description:
882 Count the number of seperators in String
883
884 Arguments:
885 String - String to process
886 Seperator - Item to count
887
888 Returns:
889 Number of Seperator in String
890
891 --*/
892 {
893 UINTN Count;
894
895 for (Count = 0; *String != '\0'; String++) {
896 if (*String == Seperator) {
897 Count++;
898 }
899 }
900
901 return Count;
902 }
903
904
905 EFI_STATUS
906 AddHandle (
907 IN PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext,
908 IN VOID *ModHandle
909 )
910 /*++
911
912 Routine Description:
913 Store the ModHandle in an array indexed by the Pdb File name.
914 The ModHandle is needed to unload the image.
915
916 Arguments:
917 ImageContext - Input data returned from PE Laoder Library. Used to find the
918 .PDB file name of the PE Image.
919 ModHandle - Returned from LoadLibraryEx() and stored for call to
920 FreeLibrary().
921
922 Returns:
923 EFI_SUCCESS - ModHandle was stored.
924
925 --*/
926 {
927 UINTN Index;
928 IMAGE_CONTEXT_TO_MOD_HANDLE *Array;
929 UINTN PreviousSize;
930
931
932 Array = mImageContextModHandleArray;
933 for (Index = 0; Index < mImageContextModHandleArraySize; Index++, Array++) {
934 if (Array->ImageContext == NULL) {
935 //
936 // Make a copy of the stirng and store the ModHandle
937 //
938 Array->ImageContext = ImageContext;
939 Array->ModHandle = ModHandle;
940 return EFI_SUCCESS;
941 }
942 }
943
944 //
945 // No free space in mImageContextModHandleArray so grow it by
946 // IMAGE_CONTEXT_TO_MOD_HANDLE entires. realloc will
947 // copy the old values to the new locaiton. But it does
948 // not zero the new memory area.
949 //
950 PreviousSize = mImageContextModHandleArraySize * sizeof (IMAGE_CONTEXT_TO_MOD_HANDLE);
951 mImageContextModHandleArraySize += MAX_IMAGE_CONTEXT_TO_MOD_HANDLE_ARRAY_SIZE;
952
953 mImageContextModHandleArray = realloc (mImageContextModHandleArray, mImageContextModHandleArraySize * sizeof (IMAGE_CONTEXT_TO_MOD_HANDLE));
954 if (mImageContextModHandleArray == NULL) {
955 ASSERT (FALSE);
956 return EFI_OUT_OF_RESOURCES;
957 }
958
959 memset (mImageContextModHandleArray + PreviousSize, 0, MAX_IMAGE_CONTEXT_TO_MOD_HANDLE_ARRAY_SIZE * sizeof (IMAGE_CONTEXT_TO_MOD_HANDLE));
960
961 return AddHandle (ImageContext, ModHandle);
962 }
963
964
965 VOID *
966 RemoveHandle (
967 IN PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
968 )
969 /*++
970
971 Routine Description:
972 Return the ModHandle and delete the entry in the array.
973
974 Arguments:
975 ImageContext - Input data returned from PE Laoder Library. Used to find the
976 .PDB file name of the PE Image.
977
978 Returns:
979 ModHandle - ModHandle assoicated with ImageContext is returned
980 NULL - No ModHandle associated with ImageContext
981
982 --*/
983 {
984 UINTN Index;
985 IMAGE_CONTEXT_TO_MOD_HANDLE *Array;
986
987 if (ImageContext->PdbPointer == NULL) {
988 //
989 // If no PDB pointer there is no ModHandle so return NULL
990 //
991 return NULL;
992 }
993
994 Array = mImageContextModHandleArray;
995 for (Index = 0; Index < mImageContextModHandleArraySize; Index++, Array++) {
996 if ((Array->ImageContext == ImageContext)) {
997 //
998 // If you find a match return it and delete the entry
999 //
1000 Array->ImageContext = NULL;
1001 return Array->ModHandle;
1002 }
1003 }
1004
1005 return NULL;
1006 }
1007
1008
1009
1010 //
1011 // Target for gdb breakpoint in a script that uses gGdbWorkingFileName to source a
1012 // add-symbol-file command. Hey what can you say scripting in gdb is not that great....
1013 //
1014 // Put .gdbinit in the CWD where you do gdb SecMain.dll for source level debug
1015 //
1016 // cat .gdbinit
1017 // b SecGdbScriptBreak
1018 // command
1019 // silent
1020 // source SecMain.dll.gdb
1021 // c
1022 // end
1023 //
1024 VOID
1025 SecGdbScriptBreak (
1026 VOID
1027 )
1028 {
1029 }
1030
1031 VOID
1032 SecUnixLoaderBreak (
1033 VOID
1034 )
1035 {
1036 }
1037
1038 BOOLEAN
1039 IsPdbFile (
1040 IN CHAR8 *PdbFileName
1041 )
1042 {
1043 UINTN Len;
1044
1045 if (PdbFileName == NULL) {
1046 return FALSE;
1047 }
1048
1049 Len = strlen (PdbFileName);
1050 if ((Len < 5)|| (PdbFileName[Len - 4] != '.')) {
1051 return FALSE;
1052 }
1053
1054 if ((PdbFileName[Len - 3] == 'P' || PdbFileName[Len - 3] == 'p') &&
1055 (PdbFileName[Len - 2] == 'D' || PdbFileName[Len - 2] == 'd') &&
1056 (PdbFileName[Len - 1] == 'B' || PdbFileName[Len - 1] == 'b')) {
1057 return TRUE;
1058 }
1059
1060 return FALSE;
1061 }
1062
1063
1064 #define MAX_SPRINT_BUFFER_SIZE 0x200
1065
1066 void
1067 PrintLoadAddress (
1068 IN PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
1069 )
1070 {
1071 fprintf (stderr,
1072 "0x%08lx Loading %s with entry point 0x%08lx\n",
1073 (unsigned long)(ImageContext->ImageAddress + ImageContext->SizeOfHeaders),
1074 ImageContext->PdbPointer,
1075 (unsigned long)ImageContext->EntryPoint
1076 );
1077
1078 // Keep output synced up
1079 fflush (stderr);
1080 }
1081
1082
1083 VOID
1084 EFIAPI
1085 SecPeCoffRelocateImageExtraAction (
1086 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
1087 )
1088 {
1089
1090 #ifdef __APPLE__
1091 PrintLoadAddress (ImageContext);
1092
1093 //
1094 // In mach-o (OS X executable) dlopen() can only load files in the MH_DYLIB of MH_BUNDLE format.
1095 // To convert to PE/COFF we need to construct a mach-o with the MH_PRELOAD format. We create
1096 // .dSYM files for the PE/COFF images that can be used by gdb for source level debugging.
1097 //
1098 FILE *GdbTempFile;
1099
1100 //
1101 // In the Mach-O to PE/COFF conversion the size of the PE/COFF headers is not accounted for.
1102 // Thus we need to skip over the PE/COFF header when giving load addresses for our symbol table.
1103 //
1104 if (ImageContext->PdbPointer != NULL && !IsPdbFile (ImageContext->PdbPointer)) {
1105 //
1106 // Now we have a database of the images that are currently loaded
1107 //
1108
1109 //
1110 // 'symbol-file' will clear out currnet symbol mappings in gdb.
1111 // you can do a 'add-symbol-file filename address' for every image we loaded to get source
1112 // level debug in gdb. Note Sec, being a true application will work differently.
1113 //
1114 // We add the PE/COFF header size into the image as the mach-O does not have a header in
1115 // loaded into system memory.
1116 //
1117 // This gives us a data base of gdb commands and after something is unloaded that entry will be
1118 // removed. We don't yet have the scheme of how to comunicate with gdb, but we have the
1119 // data base of info ready to roll.
1120 //
1121 // We could use qXfer:libraries:read, but OS X GDB does not currently support it.
1122 // <library-list>
1123 // <library name="/lib/libc.so.6"> // ImageContext->PdbPointer
1124 // <segment address="0x10000000"/> // ImageContext->ImageAddress + ImageContext->SizeOfHeaders
1125 // </library>
1126 // </library-list>
1127 //
1128
1129 //
1130 // Write the file we need for the gdb script
1131 //
1132 GdbTempFile = fopen (gGdbWorkingFileName, "w");
1133 if (GdbTempFile != NULL) {
1134 fprintf (GdbTempFile, "add-symbol-file %s 0x%08lx\n", ImageContext->PdbPointer, (long unsigned int)(ImageContext->ImageAddress + ImageContext->SizeOfHeaders));
1135 fclose (GdbTempFile);
1136
1137 //
1138 // Target for gdb breakpoint in a script that uses gGdbWorkingFileName to set a breakpoint.
1139 // Hey what can you say scripting in gdb is not that great....
1140 //
1141 SecGdbScriptBreak ();
1142 }
1143
1144 AddHandle (ImageContext, ImageContext->PdbPointer);
1145
1146 }
1147
1148 #else
1149
1150 void *Handle = NULL;
1151 void *Entry = NULL;
1152
1153 fprintf (stderr,
1154 "Loading %s 0x%08lx - entry point 0x%08lx\n",
1155 ImageContext->PdbPointer,
1156 (unsigned long)ImageContext->ImageAddress,
1157 (unsigned long)ImageContext->EntryPoint);
1158
1159 Handle = dlopen (ImageContext->PdbPointer, RTLD_NOW);
1160
1161 if (Handle) {
1162 Entry = dlsym (Handle, "_ModuleEntryPoint");
1163 } else {
1164 printf("%s\n", dlerror());
1165 }
1166
1167 if (Entry != NULL) {
1168 ImageContext->EntryPoint = (UINTN)Entry;
1169 printf("Change %s Entrypoint to :0x%08lx\n", ImageContext->PdbPointer, (unsigned long)Entry);
1170 }
1171
1172 SecUnixLoaderBreak ();
1173
1174 #endif
1175
1176 return;
1177 }
1178
1179
1180 VOID
1181 EFIAPI
1182 SecPeCoffLoaderUnloadImageExtraAction (
1183 IN PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
1184 )
1185 {
1186 VOID *Handle;
1187
1188 Handle = RemoveHandle (ImageContext);
1189
1190 #ifdef __APPLE__
1191 FILE *GdbTempFile;
1192
1193 if (Handle != NULL) {
1194 //
1195 // Need to skip .PDB files created from VC++
1196 //
1197 if (!IsPdbFile (ImageContext->PdbPointer)) {
1198 //
1199 // Write the file we need for the gdb script
1200 //
1201 GdbTempFile = fopen (gGdbWorkingFileName, "w");
1202 if (GdbTempFile != NULL) {
1203 fprintf (GdbTempFile, "remove-symbol-file %s\n", ImageContext->PdbPointer);
1204 fclose (GdbTempFile);
1205
1206 //
1207 // Target for gdb breakpoint in a script that uses gGdbWorkingFileName to set a breakpoint.
1208 // Hey what can you say scripting in gdb is not that great....
1209 //
1210 SecGdbScriptBreak ();
1211 }
1212 }
1213 }
1214
1215 #else
1216 //
1217 // Don't want to confuse gdb with symbols for something that got unloaded
1218 //
1219 if (Handle != NULL) {
1220 dlclose (Handle);
1221 }
1222
1223 #endif
1224 return;
1225 }
1226
1227 VOID
1228 ModuleEntryPoint (
1229 VOID
1230 )
1231 {
1232 }
1233
1234 EFI_STATUS
1235 EFIAPI
1236 SecTemporaryRamSupport (
1237 IN CONST EFI_PEI_SERVICES **PeiServices,
1238 IN EFI_PHYSICAL_ADDRESS TemporaryMemoryBase,
1239 IN EFI_PHYSICAL_ADDRESS PermanentMemoryBase,
1240 IN UINTN CopySize
1241 )
1242 {
1243 //
1244 // Migrate the whole temporary memory to permenent memory.
1245 //
1246 CopyMem (
1247 (VOID*)(UINTN)PermanentMemoryBase,
1248 (VOID*)(UINTN)TemporaryMemoryBase,
1249 CopySize
1250 );
1251
1252 //
1253 // SecSwitchStack function must be invoked after the memory migration
1254 // immediatly, also we need fixup the stack change caused by new call into
1255 // permenent memory.
1256 //
1257 SecSwitchStack (
1258 (UINT32) TemporaryMemoryBase,
1259 (UINT32) PermanentMemoryBase
1260 );
1261
1262 //
1263 // We need *not* fix the return address because currently,
1264 // The PeiCore is excuted in flash.
1265 //
1266
1267 //
1268 // Simulate to invalid temporary memory, terminate temporary memory
1269 //
1270 //ZeroMem ((VOID*)(UINTN)TemporaryMemoryBase, CopySize);
1271
1272 return EFI_SUCCESS;
1273 }