]> git.proxmox.com Git - mirror_edk2.git/blob - UnixPkg/Sec/SecMain.c
Started trying to get the UnixPkg to compile for X64 with UnixABI. So far only have...
[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 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 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 // Allocate space in UNIX (not emulator) memory. Extra space is for alignment
721 //
722 ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS) (UINTN) malloc ((UINTN) (ImageContext.ImageSize + (ImageContext.SectionAlignment * 2)));
723 if (ImageContext.ImageAddress == 0) {
724 return EFI_OUT_OF_RESOURCES;
725 }
726 //
727 // Align buffer on section boundry
728 //
729 ImageContext.ImageAddress += ImageContext.SectionAlignment - 1;
730 ImageContext.ImageAddress &= ~(ImageContext.SectionAlignment - 1);
731
732
733 Status = PeCoffLoaderLoadImage (&ImageContext);
734 if (EFI_ERROR (Status)) {
735 return Status;
736 }
737
738 Status = PeCoffLoaderRelocateImage (&ImageContext);
739 if (EFI_ERROR (Status)) {
740 return Status;
741 }
742
743
744 SecPeCoffRelocateImageExtraAction (&ImageContext);
745
746 //
747 // BugBug: Flush Instruction Cache Here when CPU Lib is ready
748 //
749
750 *ImageAddress = ImageContext.ImageAddress;
751 *ImageSize = ImageContext.ImageSize;
752 *EntryPoint = ImageContext.EntryPoint;
753
754 return EFI_SUCCESS;
755 }
756
757
758 RETURN_STATUS
759 EFIAPI
760 SecPeCoffGetEntryPoint (
761 IN VOID *Pe32Data,
762 IN OUT VOID **EntryPoint
763 )
764 {
765 EFI_STATUS Status;
766 EFI_PHYSICAL_ADDRESS ImageAddress;
767 UINT64 ImageSize;
768 EFI_PHYSICAL_ADDRESS PhysEntryPoint;
769
770 Status = SecUnixPeiLoadFile (Pe32Data, &ImageAddress, &ImageSize, &PhysEntryPoint);
771
772 *EntryPoint = (VOID *)(UINTN)PhysEntryPoint;
773 return Status;
774 }
775
776
777
778 EFI_STATUS
779 EFIAPI
780 SecUnixFdAddress (
781 IN UINTN Index,
782 IN OUT EFI_PHYSICAL_ADDRESS *FdBase,
783 IN OUT UINT64 *FdSize,
784 IN OUT EFI_PHYSICAL_ADDRESS *FixUp
785 )
786 /*++
787
788 Routine Description:
789 Return the FD Size and base address. Since the FD is loaded from a
790 file into host memory only the SEC will know it's address.
791
792 Arguments:
793 Index - Which FD, starts at zero.
794 FdSize - Size of the FD in bytes
795 FdBase - Start address of the FD. Assume it points to an FV Header
796 FixUp - Difference between actual FD address and build address
797
798 Returns:
799 EFI_SUCCESS - Return the Base address and size of the FV
800 EFI_UNSUPPORTED - Index does nto map to an FD in the system
801
802 --*/
803 {
804 if (Index >= gFdInfoCount) {
805 return EFI_UNSUPPORTED;
806 }
807
808 *FdBase = gFdInfo[Index].Address;
809 *FdSize = gFdInfo[Index].Size;
810 *FixUp = 0;
811
812 if (*FdBase == 0 && *FdSize == 0) {
813 return EFI_UNSUPPORTED;
814 }
815
816 if (Index == 0) {
817 //
818 // FD 0 has XIP code and well known PCD values
819 // If the memory buffer could not be allocated at the FD build address
820 // the Fixup is the difference.
821 //
822 *FixUp = *FdBase - PcdGet32 (PcdUnixFdBaseAddress);
823 }
824
825 return EFI_SUCCESS;
826 }
827
828 EFI_STATUS
829 EFIAPI
830 SecImageRead (
831 IN VOID *FileHandle,
832 IN UINTN FileOffset,
833 IN OUT UINTN *ReadSize,
834 OUT VOID *Buffer
835 )
836 /*++
837
838 Routine Description:
839 Support routine for the PE/COFF Loader that reads a buffer from a PE/COFF file
840
841 Arguments:
842 FileHandle - The handle to the PE/COFF file
843 FileOffset - The offset, in bytes, into the file to read
844 ReadSize - The number of bytes to read from the file starting at FileOffset
845 Buffer - A pointer to the buffer to read the data into.
846
847 Returns:
848 EFI_SUCCESS - ReadSize bytes of data were read into Buffer from the PE/COFF file starting at FileOffset
849
850 --*/
851 {
852 CHAR8 *Destination8;
853 CHAR8 *Source8;
854 UINTN Length;
855
856 Destination8 = Buffer;
857 Source8 = (CHAR8 *) ((UINTN) FileHandle + FileOffset);
858 Length = *ReadSize;
859 while (Length--) {
860 *(Destination8++) = *(Source8++);
861 }
862
863 return EFI_SUCCESS;
864 }
865
866 UINTN
867 CountSeperatorsInString (
868 IN const CHAR16 *String,
869 IN CHAR16 Seperator
870 )
871 /*++
872
873 Routine Description:
874 Count the number of seperators in String
875
876 Arguments:
877 String - String to process
878 Seperator - Item to count
879
880 Returns:
881 Number of Seperator in String
882
883 --*/
884 {
885 UINTN Count;
886
887 for (Count = 0; *String != '\0'; String++) {
888 if (*String == Seperator) {
889 Count++;
890 }
891 }
892
893 return Count;
894 }
895
896
897 EFI_STATUS
898 AddHandle (
899 IN PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext,
900 IN VOID *ModHandle
901 )
902 /*++
903
904 Routine Description:
905 Store the ModHandle in an array indexed by the Pdb File name.
906 The ModHandle is needed to unload the image.
907
908 Arguments:
909 ImageContext - Input data returned from PE Laoder Library. Used to find the
910 .PDB file name of the PE Image.
911 ModHandle - Returned from LoadLibraryEx() and stored for call to
912 FreeLibrary().
913
914 Returns:
915 EFI_SUCCESS - ModHandle was stored.
916
917 --*/
918 {
919 UINTN Index;
920 IMAGE_CONTEXT_TO_MOD_HANDLE *Array;
921 UINTN PreviousSize;
922
923
924 Array = mImageContextModHandleArray;
925 for (Index = 0; Index < mImageContextModHandleArraySize; Index++, Array++) {
926 if (Array->ImageContext == NULL) {
927 //
928 // Make a copy of the stirng and store the ModHandle
929 //
930 Array->ImageContext = ImageContext;
931 Array->ModHandle = ModHandle;
932 return EFI_SUCCESS;
933 }
934 }
935
936 //
937 // No free space in mImageContextModHandleArray so grow it by
938 // IMAGE_CONTEXT_TO_MOD_HANDLE entires. realloc will
939 // copy the old values to the new locaiton. But it does
940 // not zero the new memory area.
941 //
942 PreviousSize = mImageContextModHandleArraySize * sizeof (IMAGE_CONTEXT_TO_MOD_HANDLE);
943 mImageContextModHandleArraySize += MAX_IMAGE_CONTEXT_TO_MOD_HANDLE_ARRAY_SIZE;
944
945 mImageContextModHandleArray = realloc (mImageContextModHandleArray, mImageContextModHandleArraySize * sizeof (IMAGE_CONTEXT_TO_MOD_HANDLE));
946 if (mImageContextModHandleArray == NULL) {
947 ASSERT (FALSE);
948 return EFI_OUT_OF_RESOURCES;
949 }
950
951 memset (mImageContextModHandleArray + PreviousSize, 0, MAX_IMAGE_CONTEXT_TO_MOD_HANDLE_ARRAY_SIZE * sizeof (IMAGE_CONTEXT_TO_MOD_HANDLE));
952
953 return AddHandle (ImageContext, ModHandle);
954 }
955
956
957 VOID *
958 RemoveHandle (
959 IN PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
960 )
961 /*++
962
963 Routine Description:
964 Return the ModHandle and delete the entry in the array.
965
966 Arguments:
967 ImageContext - Input data returned from PE Laoder Library. Used to find the
968 .PDB file name of the PE Image.
969
970 Returns:
971 ModHandle - ModHandle assoicated with ImageContext is returned
972 NULL - No ModHandle associated with ImageContext
973
974 --*/
975 {
976 UINTN Index;
977 IMAGE_CONTEXT_TO_MOD_HANDLE *Array;
978
979 if (ImageContext->PdbPointer == NULL) {
980 //
981 // If no PDB pointer there is no ModHandle so return NULL
982 //
983 return NULL;
984 }
985
986 Array = mImageContextModHandleArray;
987 for (Index = 0; Index < mImageContextModHandleArraySize; Index++, Array++) {
988 if ((Array->ImageContext == ImageContext)) {
989 //
990 // If you find a match return it and delete the entry
991 //
992 Array->ImageContext = NULL;
993 return Array->ModHandle;
994 }
995 }
996
997 return NULL;
998 }
999
1000
1001
1002 //
1003 // Target for gdb breakpoint in a script that uses gGdbWorkingFileName to source a
1004 // add-symbol-file command. Hey what can you say scripting in gdb is not that great....
1005 //
1006 // Put .gdbinit in the CWD where you do gdb SecMain.dll for source level debug
1007 //
1008 // cat .gdbinit
1009 // b SecGdbScriptBreak
1010 // command
1011 // silent
1012 // source SecMain.dll.gdb
1013 // c
1014 // end
1015 //
1016 VOID
1017 SecGdbScriptBreak (
1018 VOID
1019 )
1020 {
1021 }
1022
1023 VOID
1024 SecUnixLoaderBreak (
1025 VOID
1026 )
1027 {
1028 }
1029
1030 BOOLEAN
1031 IsPdbFile (
1032 IN CHAR8 *PdbFileName
1033 )
1034 {
1035 UINTN Len;
1036
1037 if (PdbFileName == NULL) {
1038 return FALSE;
1039 }
1040
1041 Len = strlen (PdbFileName);
1042 if ((Len < 5)|| (PdbFileName[Len - 4] != '.')) {
1043 return FALSE;
1044 }
1045
1046 if ((PdbFileName[Len - 3] == 'P' || PdbFileName[Len - 3] == 'p') &&
1047 (PdbFileName[Len - 2] == 'D' || PdbFileName[Len - 2] == 'd') &&
1048 (PdbFileName[Len - 1] == 'B' || PdbFileName[Len - 1] == 'b')) {
1049 return TRUE;
1050 }
1051
1052 return FALSE;
1053 }
1054
1055
1056 #define MAX_SPRINT_BUFFER_SIZE 0x200
1057
1058 void
1059 PrintLoadAddress (
1060 IN PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
1061 )
1062 {
1063 fprintf (stderr,
1064 "0x%08lx Loading %s with entry point 0x%08lx\n",
1065 (unsigned long)(ImageContext->ImageAddress + ImageContext->SizeOfHeaders),
1066 ImageContext->PdbPointer,
1067 (unsigned long)ImageContext->EntryPoint
1068 );
1069
1070 // Keep output synced up
1071 fflush (stderr);
1072 }
1073
1074
1075 VOID
1076 EFIAPI
1077 SecPeCoffRelocateImageExtraAction (
1078 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
1079 )
1080 {
1081
1082 #ifdef __APPLE__
1083 PrintLoadAddress (ImageContext);
1084
1085 //
1086 // In mach-o (OS X executable) dlopen() can only load files in the MH_DYLIB of MH_BUNDLE format.
1087 // To convert to PE/COFF we need to construct a mach-o with the MH_PRELOAD format. We create
1088 // .dSYM files for the PE/COFF images that can be used by gdb for source level debugging.
1089 //
1090 FILE *GdbTempFile;
1091
1092 //
1093 // In the Mach-O to PE/COFF conversion the size of the PE/COFF headers is not accounted for.
1094 // Thus we need to skip over the PE/COFF header when giving load addresses for our symbol table.
1095 //
1096 if (ImageContext->PdbPointer != NULL && !IsPdbFile (ImageContext->PdbPointer)) {
1097 //
1098 // Now we have a database of the images that are currently loaded
1099 //
1100
1101 //
1102 // 'symbol-file' will clear out currnet symbol mappings in gdb.
1103 // you can do a 'add-symbol-file filename address' for every image we loaded to get source
1104 // level debug in gdb. Note Sec, being a true application will work differently.
1105 //
1106 // We add the PE/COFF header size into the image as the mach-O does not have a header in
1107 // loaded into system memory.
1108 //
1109 // This gives us a data base of gdb commands and after something is unloaded that entry will be
1110 // removed. We don't yet have the scheme of how to comunicate with gdb, but we have the
1111 // data base of info ready to roll.
1112 //
1113 // We could use qXfer:libraries:read, but OS X GDB does not currently support it.
1114 // <library-list>
1115 // <library name="/lib/libc.so.6"> // ImageContext->PdbPointer
1116 // <segment address="0x10000000"/> // ImageContext->ImageAddress + ImageContext->SizeOfHeaders
1117 // </library>
1118 // </library-list>
1119 //
1120
1121 //
1122 // Write the file we need for the gdb script
1123 //
1124 GdbTempFile = fopen (gGdbWorkingFileName, "w");
1125 if (GdbTempFile != NULL) {
1126 fprintf (GdbTempFile, "add-symbol-file %s 0x%x\n", ImageContext->PdbPointer, (unsigned int)(ImageContext->ImageAddress + ImageContext->SizeOfHeaders));
1127 fclose (GdbTempFile);
1128
1129 //
1130 // Target for gdb breakpoint in a script that uses gGdbWorkingFileName to set a breakpoint.
1131 // Hey what can you say scripting in gdb is not that great....
1132 //
1133 SecGdbScriptBreak ();
1134 }
1135
1136 AddHandle (ImageContext, ImageContext->PdbPointer);
1137
1138 }
1139
1140 #else
1141
1142 void *Handle = NULL;
1143 void *Entry = NULL;
1144
1145 fprintf (stderr,
1146 "Loading %s 0x%08lx - entry point 0x%08lx\n",
1147 ImageContext->PdbPointer,
1148 (unsigned long)ImageContext->ImageAddress,
1149 (unsigned long)ImageContext->EntryPoint);
1150
1151 Handle = dlopen (ImageContext->PdbPointer, RTLD_NOW);
1152
1153 if (Handle) {
1154 Entry = dlsym (Handle, "_ModuleEntryPoint");
1155 } else {
1156 printf("%s\n", dlerror());
1157 }
1158
1159 if (Entry != NULL) {
1160 ImageContext->EntryPoint = (UINTN)Entry;
1161 printf("Change %s Entrypoint to :0x%08lx\n", ImageContext->PdbPointer, (unsigned long)Entry);
1162 }
1163
1164 SecUnixLoaderBreak ();
1165
1166 #endif
1167
1168 return;
1169 }
1170
1171
1172 VOID
1173 EFIAPI
1174 SecPeCoffLoaderUnloadImageExtraAction (
1175 IN PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
1176 )
1177 {
1178 VOID *Handle;
1179
1180 Handle = RemoveHandle (ImageContext);
1181
1182 #ifdef __APPLE__
1183 FILE *GdbTempFile;
1184
1185 if (Handle != NULL) {
1186 //
1187 // Need to skip .PDB files created from VC++
1188 //
1189 if (!IsPdbFile (ImageContext->PdbPointer)) {
1190 //
1191 // Write the file we need for the gdb script
1192 //
1193 GdbTempFile = fopen (gGdbWorkingFileName, "w");
1194 if (GdbTempFile != NULL) {
1195 fprintf (GdbTempFile, "remove-symbol-file %s\n", ImageContext->PdbPointer);
1196 fclose (GdbTempFile);
1197
1198 //
1199 // Target for gdb breakpoint in a script that uses gGdbWorkingFileName to set a breakpoint.
1200 // Hey what can you say scripting in gdb is not that great....
1201 //
1202 SecGdbScriptBreak ();
1203 }
1204 }
1205 }
1206
1207 #else
1208 //
1209 // Don't want to confuse gdb with symbols for something that got unloaded
1210 //
1211 if (Handle != NULL) {
1212 dlclose (Handle);
1213 }
1214
1215 #endif
1216 return;
1217 }
1218
1219 VOID
1220 ModuleEntryPoint (
1221 VOID
1222 )
1223 {
1224 }
1225
1226 EFI_STATUS
1227 EFIAPI
1228 SecTemporaryRamSupport (
1229 IN CONST EFI_PEI_SERVICES **PeiServices,
1230 IN EFI_PHYSICAL_ADDRESS TemporaryMemoryBase,
1231 IN EFI_PHYSICAL_ADDRESS PermanentMemoryBase,
1232 IN UINTN CopySize
1233 )
1234 {
1235 //
1236 // Migrate the whole temporary memory to permenent memory.
1237 //
1238 CopyMem (
1239 (VOID*)(UINTN)PermanentMemoryBase,
1240 (VOID*)(UINTN)TemporaryMemoryBase,
1241 CopySize
1242 );
1243
1244 //
1245 // SecSwitchStack function must be invoked after the memory migration
1246 // immediatly, also we need fixup the stack change caused by new call into
1247 // permenent memory.
1248 //
1249 SecSwitchStack (
1250 (UINT32) TemporaryMemoryBase,
1251 (UINT32) PermanentMemoryBase
1252 );
1253
1254 //
1255 // We need *not* fix the return address because currently,
1256 // The PeiCore is excuted in flash.
1257 //
1258
1259 //
1260 // Simulate to invalid temporary memory, terminate temporary memory
1261 //
1262 //ZeroMem ((VOID*)(UINTN)TemporaryMemoryBase, CopySize);
1263
1264 return EFI_SUCCESS;
1265 }