]> git.proxmox.com Git - mirror_edk2.git/blame - 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
CommitLineData
804405e7 1/*++
2
f9b8ab56
HT
3Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>
4Portions copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR>
5This program and the accompanying materials
804405e7 6are licensed and made available under the terms and conditions of the BSD License
7which accompanies this distribution. The full text of the license may be found at
8http://opensource.org/licenses/bsd-license.php
9
10THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12
13Module Name:
14
15 SecMain.c
16
17Abstract:
ccd55824 18 Unix emulator of SEC phase. It's really a Posix application, but this is
804405e7 19 Ok since all the other modules for NT32 are NOT Posix applications.
20
21 This program processes host environment variables and figures out
22 what the memory layout will be, how may FD's will be loaded and also
23 what the boot mode is.
24
25 The SEC registers a set of services with the SEC core. gPrivateDispatchTable
26 is a list of PPI's produced by the SEC that are availble for usage in PEI.
27
28 This code produces 128 K of temporary memory for the PEI stack by opening a
29 host file and mapping it directly to memory addresses.
30
31 The system.cmd script is used to set host environment variables that drive
32 the configuration opitons of the SEC.
33
34--*/
35
36#include "SecMain.h"
37#include <sys/mman.h>
38#include <Ppi/UnixPeiLoadFile.h>
804405e7 39#include <Ppi/TemporaryRamSupport.h>
40#include <dlfcn.h>
ccd55824 41
42#ifdef __APPLE__
43#define MAP_ANONYMOUS MAP_ANON
44char *gGdbWorkingFileName = NULL;
45#endif
46
47
804405e7 48//
49// Globals
50//
804405e7 51
ccd55824 52UNIX_PEI_LOAD_FILE_PPI mSecUnixLoadFilePpi = { SecUnixPeiLoadFile };
804405e7 53
ccd55824 54PEI_UNIX_AUTOSCAN_PPI mSecUnixAutoScanPpi = { SecUnixPeiAutoScan };
804405e7 55
ccd55824 56PEI_UNIX_THUNK_PPI mSecUnixThunkPpi = { SecUnixUnixThunkAddress };
804405e7 57
73aa7f04 58EFI_PEI_PROGRESS_CODE_PPI mSecStatusCodePpi = { SecPeiReportStatusCode };
804405e7 59
ccd55824 60UNIX_FWH_PPI mSecFwhInformationPpi = { SecUnixFdAddress };
804405e7 61
62TEMPORARY_RAM_SUPPORT_PPI mSecTemporaryRamSupportPpi = {SecTemporaryRamSupport};
63
64EFI_PEI_PPI_DESCRIPTOR gPrivateDispatchTable[] = {
804405e7 65 {
66 EFI_PEI_PPI_DESCRIPTOR_PPI,
67 &gUnixPeiLoadFilePpiGuid,
ccd55824 68 &mSecUnixLoadFilePpi
804405e7 69 },
70 {
71 EFI_PEI_PPI_DESCRIPTOR_PPI,
72 &gPeiUnixAutoScanPpiGuid,
ccd55824 73 &mSecUnixAutoScanPpi
804405e7 74 },
75 {
76 EFI_PEI_PPI_DESCRIPTOR_PPI,
77 &gPeiUnixThunkPpiGuid,
ccd55824 78 &mSecUnixThunkPpi
804405e7 79 },
80 {
81 EFI_PEI_PPI_DESCRIPTOR_PPI,
82 &gEfiPeiStatusCodePpiGuid,
83 &mSecStatusCodePpi
84 },
85 {
86 EFI_PEI_PPI_DESCRIPTOR_PPI,
87 &gEfiTemporaryRamSupportPpiGuid,
88 &mSecTemporaryRamSupportPpi
89 },
90 {
804405e7 91 EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST,
92 &gUnixFwhPpiGuid,
93 &mSecFwhInformationPpi
94 }
95};
96
97
98//
99// Default information about where the FD is located.
100// This array gets filled in with information from EFI_FIRMWARE_VOLUMES
101// EFI_FIRMWARE_VOLUMES is a host environment variable set by system.cmd.
102// The number of array elements is allocated base on parsing
103// EFI_FIRMWARE_VOLUMES and the memory is never freed.
104//
105UINTN gFdInfoCount = 0;
106UNIX_FD_INFO *gFdInfo;
107
108//
109// Array that supports seperate memory rantes.
110// The memory ranges are set in system.cmd via the EFI_MEMORY_SIZE variable.
111// The number of array elements is allocated base on parsing
112// EFI_MEMORY_SIZE and the memory is never freed.
113//
114UINTN gSystemMemoryCount = 0;
115UNIX_SYSTEM_MEMORY *gSystemMemory;
116
ccd55824 117
118
119UINTN mImageContextModHandleArraySize = 0;
120IMAGE_CONTEXT_TO_MOD_HANDLE *mImageContextModHandleArray = NULL;
121
122
804405e7 123VOID
124EFIAPI
125SecSwitchStack (
126 UINT32 TemporaryMemoryBase,
127 UINT32 PermenentMemoryBase
128 );
129
804405e7 130EFI_PHYSICAL_ADDRESS *
131MapMemory (
132 INTN fd,
133 UINT64 length,
134 INTN prot,
135 INTN flags);
136
804405e7 137EFI_STATUS
138MapFile (
139 IN CHAR8 *FileName,
140 IN OUT EFI_PHYSICAL_ADDRESS *BaseAddress,
141 OUT UINT64 *Length
142 );
7ee3b613 143
398b646f 144EFI_STATUS
145EFIAPI
146SecNt32PeCoffRelocateImage (
147 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
148 );
804405e7 149
150
ccd55824 151int
804405e7 152main (
ccd55824 153 IN int Argc,
154 IN char **Argv,
155 IN char **Envp
804405e7 156 )
157/*++
158
159Routine Description:
ccd55824 160 Main entry point to SEC for Unix. This is a unix program
804405e7 161
162Arguments:
163 Argc - Number of command line arguments
164 Argv - Array of command line argument strings
165 Envp - Array of environmemt variable strings
166
167Returns:
168 0 - Normal exit
169 1 - Abnormal exit
170
171--*/
172{
173 EFI_STATUS Status;
174 EFI_PHYSICAL_ADDRESS InitialStackMemory;
175 UINT64 InitialStackMemorySize;
176 UINTN Index;
177 UINTN Index1;
178 UINTN Index2;
179 UINTN PeiIndex;
180 CHAR8 *FileName;
181 BOOLEAN Done;
182 VOID *PeiCoreFile;
183 CHAR16 *MemorySizeStr;
184 CHAR16 *FirmwareVolumesStr;
185 UINTN *StackPointer;
186
187 setbuf(stdout, 0);
188 setbuf(stderr, 0);
189
cdccd99e 190 MemorySizeStr = (CHAR16 *) PcdGetPtr (PcdUnixMemorySizeForSecMain);
191 FirmwareVolumesStr = (CHAR16 *) PcdGetPtr (PcdUnixFirmwareVolume);
804405e7 192
193 printf ("\nEDK SEC Main UNIX Emulation Environment from www.TianoCore.org\n");
194
ccd55824 195#ifdef __APPLE__
196 //
197 // We can't use dlopen on OS X, so we need a scheme to get symboles into gdb
198 // We need to create a temp file that contains gdb commands so we can load
199 // symbols when we load every PE/COFF image.
200 //
201 Index = strlen (*Argv);
7ee3b613 202 gGdbWorkingFileName = malloc (Index + strlen(".gdb") + 1);
ccd55824 203 strcpy (gGdbWorkingFileName, *Argv);
204 strcat (gGdbWorkingFileName, ".gdb");
205#endif
206
207
804405e7 208 //
209 // Allocate space for gSystemMemory Array
210 //
211 gSystemMemoryCount = CountSeperatorsInString (MemorySizeStr, '!') + 1;
212 gSystemMemory = calloc (gSystemMemoryCount, sizeof (UNIX_SYSTEM_MEMORY));
213 if (gSystemMemory == NULL) {
214 printf ("ERROR : Can not allocate memory for system. Exiting.\n");
215 exit (1);
216 }
217 //
218 // Allocate space for gSystemMemory Array
219 //
220 gFdInfoCount = CountSeperatorsInString (FirmwareVolumesStr, '!') + 1;
221 gFdInfo = calloc (gFdInfoCount, sizeof (UNIX_FD_INFO));
222 if (gFdInfo == NULL) {
223 printf ("ERROR : Can not allocate memory for fd info. Exiting.\n");
224 exit (1);
225 }
226 //
227 // Setup Boot Mode. If BootModeStr == "" then BootMode = 0 (BOOT_WITH_FULL_CONFIGURATION)
228 //
cdccd99e 229 printf (" BootMode 0x%02x\n", (unsigned int)PcdGet32 (PcdUnixBootMode));
804405e7 230
231 //
232 // Open up a 128K file to emulate temp memory for PEI.
233 // on a real platform this would be SRAM, or using the cache as RAM.
ccd55824 234 // Set InitialStackMemory to zero so UnixOpenFile will allocate a new mapping
804405e7 235 //
236 InitialStackMemorySize = STACK_SIZE;
237 InitialStackMemory = (UINTN)MapMemory(0,
238 (UINT32) InitialStackMemorySize,
239 PROT_READ | PROT_WRITE,
240 MAP_ANONYMOUS | MAP_PRIVATE);
241 if (InitialStackMemory == 0) {
242 printf ("ERROR : Can not open SecStack Exiting\n");
243 exit (1);
244 }
245
246 printf (" SEC passing in %u KB of temp RAM at 0x%08lx to PEI\n",
ccd55824 247 (unsigned int)(InitialStackMemorySize / 1024),
804405e7 248 (unsigned long)InitialStackMemory);
249
250 for (StackPointer = (UINTN*) (UINTN) InitialStackMemory;
ccd55824 251 StackPointer < (UINTN*)(UINTN)((UINTN) InitialStackMemory + (UINT64) InitialStackMemorySize);
804405e7 252 StackPointer ++) {
253 *StackPointer = 0x5AA55AA5;
254 }
255
256 //
257 // Open All the firmware volumes and remember the info in the gFdInfo global
258 //
259 FileName = (CHAR8 *)malloc (StrLen (FirmwareVolumesStr) + 1);
260 if (FileName == NULL) {
261 printf ("ERROR : Can not allocate memory for firmware volume string\n");
262 exit (1);
263 }
264
265 Index2 = 0;
266 for (Done = FALSE, Index = 0, PeiIndex = 0, PeiCoreFile = NULL;
267 FirmwareVolumesStr[Index2] != 0;
268 Index++) {
269 for (Index1 = 0; (FirmwareVolumesStr[Index2] != '!') && (FirmwareVolumesStr[Index2] != 0); Index2++)
270 FileName[Index1++] = FirmwareVolumesStr[Index2];
271 if (FirmwareVolumesStr[Index2] == '!')
272 Index2++;
273 FileName[Index1] = '\0';
274
275 //
276 // Open the FD and remmeber where it got mapped into our processes address space
277 //
278 Status = MapFile (
279 FileName,
280 &gFdInfo[Index].Address,
281 &gFdInfo[Index].Size
282 );
283 if (EFI_ERROR (Status)) {
ccd55824 284 printf ("ERROR : Can not open Firmware Device File %s (%x). Exiting.\n", FileName, (unsigned int)Status);
804405e7 285 exit (1);
286 }
287
288 printf (" FD loaded from %s at 0x%08lx",
289 FileName, (unsigned long)gFdInfo[Index].Address);
290
291 if (PeiCoreFile == NULL) {
292 //
293 // Assume the beginning of the FD is an FV and look for the PEI Core.
294 // Load the first one we find.
295 //
296 Status = SecFfsFindPeiCore ((EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) gFdInfo[Index].Address, &PeiCoreFile);
297 if (!EFI_ERROR (Status)) {
298 PeiIndex = Index;
299 printf (" contains SEC Core");
300 }
301 }
302
303 printf ("\n");
304 }
305 //
306 // Calculate memory regions and store the information in the gSystemMemory
307 // global for later use. The autosizing code will use this data to
308 // map this memory into the SEC process memory space.
309 //
310 Index1 = 0;
311 Index = 0;
312 while (1) {
313 UINTN val = 0;
314 //
315 // Save the size of the memory.
316 //
317 while (MemorySizeStr[Index1] >= '0' && MemorySizeStr[Index1] <= '9') {
318 val = val * 10 + MemorySizeStr[Index1] - '0';
319 Index1++;
320 }
321 gSystemMemory[Index++].Size = val * 0x100000;
322 if (MemorySizeStr[Index1] == 0)
323 break;
324 Index1++;
325 }
326
327 printf ("\n");
328
329 //
330 // Hand off to PEI Core
331 //
332 SecLoadFromCore ((UINTN) InitialStackMemory, (UINTN) InitialStackMemorySize, (UINTN) gFdInfo[0].Address, PeiCoreFile);
333
334 //
335 // If we get here, then the PEI Core returned. This is an error as PEI should
336 // always hand off to DXE.
337 //
338 printf ("ERROR : PEI Core returned\n");
339 exit (1);
340}
341
342EFI_PHYSICAL_ADDRESS *
343MapMemory (
344 INTN fd,
345 UINT64 length,
346 INTN prot,
347 INTN flags)
348{
349 STATIC UINTN base = 0x40000000;
350 CONST UINTN align = (1 << 24);
351 VOID *res = NULL;
352 BOOLEAN isAligned = 0;
353
354 //
355 // Try to get an aligned block somewhere in the address space of this
356 // process.
357 //
358 while((!isAligned) && (base != 0)) {
359 res = mmap ((void *)base, length, prot, flags, fd, 0);
360 if (res == MAP_FAILED) {
361 return NULL;
362 }
363 if ((((UINTN)res) & ~(align-1)) == (UINTN)res) {
364 isAligned=1;
365 }
366 else {
367 munmap(res, length);
368 base += align;
369 }
370 }
371 return res;
372}
373
374EFI_STATUS
375MapFile (
376 IN CHAR8 *FileName,
377 IN OUT EFI_PHYSICAL_ADDRESS *BaseAddress,
378 OUT UINT64 *Length
379 )
380/*++
381
382Routine Description:
ccd55824 383 Opens and memory maps a file using Unix services. If BaseAddress is non zero
804405e7 384 the process will try and allocate the memory starting at BaseAddress.
385
386Arguments:
387 FileName - The name of the file to open and map
388 MapSize - The amount of the file to map in bytes
389 CreationDisposition - The flags to pass to CreateFile(). Use to create new files for
390 memory emulation, and exiting files for firmware volume emulation
391 BaseAddress - The base address of the mapped file in the user address space.
392 If passed in as NULL the a new memory region is used.
393 If passed in as non NULL the request memory region is used for
394 the mapping of the file into the process space.
395 Length - The size of the mapped region in bytes
396
397Returns:
398 EFI_SUCCESS - The file was opened and mapped.
399 EFI_NOT_FOUND - FileName was not found in the current directory
400 EFI_DEVICE_ERROR - An error occured attempting to map the opened file
401
402--*/
403{
404 int fd;
405 VOID *res;
406 UINTN FileSize;
407
408 fd = open (FileName, O_RDONLY);
409 if (fd < 0)
410 return EFI_NOT_FOUND;
411 FileSize = lseek (fd, 0, SEEK_END);
412
413#if 0
414 if (IsMain)
415 {
416 /* Read entry address. */
417 lseek (fd, FileSize - 0x20, SEEK_SET);
418 if (read (fd, &EntryAddress, 4) != 4)
419 {
420 close (fd);
421 return EFI_DEVICE_ERROR;
422 }
423 }
424#endif
425
426 res = MapMemory(fd, FileSize, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE);
427
428 close (fd);
429
430 if (res == MAP_FAILED)
431 return EFI_DEVICE_ERROR;
432
433 *Length = (UINT64) FileSize;
434 *BaseAddress = (EFI_PHYSICAL_ADDRESS) (UINTN) res;
435
436 return EFI_SUCCESS;
437}
438
439#define BYTES_PER_RECORD 512
440
441EFI_STATUS
442EFIAPI
443SecPeiReportStatusCode (
ccd55824 444 IN CONST EFI_PEI_SERVICES **PeiServices,
804405e7 445 IN EFI_STATUS_CODE_TYPE CodeType,
446 IN EFI_STATUS_CODE_VALUE Value,
447 IN UINT32 Instance,
ccd55824 448 IN CONST EFI_GUID *CallerId,
449 IN CONST EFI_STATUS_CODE_DATA *Data OPTIONAL
804405e7 450 )
451/*++
452
453Routine Description:
454
455 This routine produces the ReportStatusCode PEI service. It's passed
456 up to the PEI Core via a PPI. T
457
458 This code currently uses the UNIX clib printf. This does not work the same way
459 as the EFI Print (), as %t, %g, %s as Unicode are not supported.
460
461Arguments:
462 (see EFI_PEI_REPORT_STATUS_CODE)
463
464Returns:
465 EFI_SUCCESS - Always return success
466
467--*/
468// TODO: PeiServices - add argument and description to function comment
469// TODO: CodeType - add argument and description to function comment
470// TODO: Value - add argument and description to function comment
471// TODO: Instance - add argument and description to function comment
472// TODO: CallerId - add argument and description to function comment
473// TODO: Data - add argument and description to function comment
474{
475 CHAR8 *Format;
9c98c8e1 476 BASE_LIST Marker;
804405e7 477 CHAR8 PrintBuffer[BYTES_PER_RECORD * 2];
478 CHAR8 *Filename;
479 CHAR8 *Description;
480 UINT32 LineNumber;
481 UINT32 ErrorLevel;
482
483
484 if (Data == NULL) {
485 } else if (ReportStatusCodeExtractAssertInfo (CodeType, Value, Data, &Filename, &Description, &LineNumber)) {
486 //
487 // Processes ASSERT ()
488 //
ccd55824 489 printf ("ASSERT %s(%d): %s\n", Filename, (int)LineNumber, Description);
804405e7 490
491 } else if (ReportStatusCodeExtractDebugInfo (Data, &ErrorLevel, &Marker, &Format)) {
492 //
493 // Process DEBUG () macro
494 //
9c98c8e1 495 AsciiBSPrint (PrintBuffer, BYTES_PER_RECORD, Format, Marker);
b7f76514 496 printf ("%s", PrintBuffer);
804405e7 497 }
498
499 return EFI_SUCCESS;
500}
501
804405e7 502VOID
503EFIAPI
504PeiSwitchStacks (
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
67f86803 510 );
804405e7 511
512VOID
513SecLoadFromCore (
514 IN UINTN LargestRegion,
515 IN UINTN LargestRegionSize,
516 IN UINTN BootFirmwareVolumeBase,
517 IN VOID *PeiCorePe32File
518 )
519/*++
520
521Routine Description:
522 This is the service to load the PEI Core from the Firmware Volume
523
524Arguments:
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
530Returns:
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
398b646f 568
804405e7 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;
cdccd99e 575 SecCoreData->BootFirmwareVolumeSize = PcdGet32 (PcdUnixFirmwareFdSize);
804405e7 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 //
ccd55824 586 Status = SecUnixPeiLoadFile (
804405e7 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
612EFI_STATUS
613EFIAPI
ccd55824 614SecUnixPeiAutoScan (
804405e7 615 IN UINTN Index,
616 OUT EFI_PHYSICAL_ADDRESS *MemoryBase,
617 OUT UINT64 *MemorySize
618 )
619/*++
620
621Routine 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
ccd55824 627 UnixOpenFile.
804405e7 628
629Arguments:
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
634Returns:
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
659VOID *
660EFIAPI
ccd55824 661SecUnixUnixThunkAddress (
804405e7 662 VOID
663 )
664/*++
665
666Routine Description:
667 Since the SEC is the only Unix program in stack it must export
ccd55824 668 an interface to do POSIX calls. gUnix is initailized in UnixThunk.c.
804405e7 669
670Arguments:
671 InterfaceSize - sizeof (EFI_WIN_NT_THUNK_PROTOCOL);
ccd55824 672 InterfaceBase - Address of the gUnix global
804405e7 673
674Returns:
675 EFI_SUCCESS - Data returned
676
677--*/
678{
679 return gUnix;
680}
681
682
683EFI_STATUS
ccd55824 684SecUnixPeiLoadFile (
804405e7 685 IN VOID *Pe32Data,
ccd55824 686 OUT EFI_PHYSICAL_ADDRESS *ImageAddress,
687 OUT UINT64 *ImageSize,
688 OUT EFI_PHYSICAL_ADDRESS *EntryPoint
804405e7 689 )
690/*++
691
692Routine Description:
693 Loads and relocates a PE/COFF image into memory.
694
695Arguments:
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
701Returns:
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
398b646f 715 Status = PeCoffLoaderGetImageInfo (&ImageContext);
804405e7 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 //
f7bef78c 729 ImageContext.ImageAddress += ImageContext.SectionAlignment - 1;
804405e7 730 ImageContext.ImageAddress &= ~(ImageContext.SectionAlignment - 1);
731
732
398b646f 733 Status = PeCoffLoaderLoadImage (&ImageContext);
804405e7 734 if (EFI_ERROR (Status)) {
735 return Status;
736 }
7ee3b613
A
737
738 Status = PeCoffLoaderRelocateImage (&ImageContext);
739 if (EFI_ERROR (Status)) {
740 return Status;
741 }
742
804405e7 743
ccd55824 744 SecPeCoffRelocateImageExtraAction (&ImageContext);
804405e7 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
ccd55824 757
758RETURN_STATUS
759EFIAPI
760SecPeCoffGetEntryPoint (
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
804405e7 778EFI_STATUS
779EFIAPI
ccd55824 780SecUnixFdAddress (
804405e7 781 IN UINTN Index,
782 IN OUT EFI_PHYSICAL_ADDRESS *FdBase,
7ee3b613
A
783 IN OUT UINT64 *FdSize,
784 IN OUT EFI_PHYSICAL_ADDRESS *FixUp
804405e7 785 )
786/*++
787
788Routine 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
792Arguments:
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
7ee3b613 796 FixUp - Difference between actual FD address and build address
804405e7 797
798Returns:
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;
7ee3b613 810 *FixUp = 0;
804405e7 811
812 if (*FdBase == 0 && *FdSize == 0) {
813 return EFI_UNSUPPORTED;
814 }
815
7ee3b613
A
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 //
cdccd99e 822 *FixUp = *FdBase - PcdGet32 (PcdUnixFdBaseAddress);
7ee3b613
A
823 }
824
804405e7 825 return EFI_SUCCESS;
826}
827
828EFI_STATUS
829EFIAPI
830SecImageRead (
831 IN VOID *FileHandle,
832 IN UINTN FileOffset,
833 IN OUT UINTN *ReadSize,
834 OUT VOID *Buffer
835 )
836/*++
837
838Routine Description:
839 Support routine for the PE/COFF Loader that reads a buffer from a PE/COFF file
840
841Arguments:
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
847Returns:
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
866UINTN
867CountSeperatorsInString (
868 IN const CHAR16 *String,
869 IN CHAR16 Seperator
870 )
871/*++
872
873Routine Description:
874 Count the number of seperators in String
875
876Arguments:
877 String - String to process
878 Seperator - Item to count
879
880Returns:
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
ccd55824 897EFI_STATUS
898AddHandle (
899 IN PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext,
900 IN VOID *ModHandle
901 )
902/*++
903
904Routine Description:
905 Store the ModHandle in an array indexed by the Pdb File name.
906 The ModHandle is needed to unload the image.
907
908Arguments:
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
914Returns:
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
957VOID *
958RemoveHandle (
959 IN PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
960 )
961/*++
962
963Routine Description:
964 Return the ModHandle and delete the entry in the array.
965
966Arguments:
967 ImageContext - Input data returned from PE Laoder Library. Used to find the
968 .PDB file name of the PE Image.
969
970Returns:
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//
1016VOID
1017SecGdbScriptBreak (
1018 VOID
1019 )
1020{
1021}
804405e7 1022
804405e7 1023VOID
1024SecUnixLoaderBreak (
1025 VOID
1026 )
1027{
1028}
1029
ccd55824 1030BOOLEAN
1031IsPdbFile (
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
1058void
1059PrintLoadAddress (
1060 IN PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
1061 )
1062{
1063 fprintf (stderr,
1064 "0x%08lx Loading %s with entry point 0x%08lx\n",
67f86803 1065 (unsigned long)(ImageContext->ImageAddress + ImageContext->SizeOfHeaders),
ccd55824 1066 ImageContext->PdbPointer,
1067 (unsigned long)ImageContext->EntryPoint
1068 );
1069
1070 // Keep output synced up
1071 fflush (stderr);
1072}
1073
1074
1075VOID
804405e7 1076EFIAPI
ccd55824 1077SecPeCoffRelocateImageExtraAction (
804405e7 1078 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
1079 )
1080{
ccd55824 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) {
67f86803 1126 fprintf (GdbTempFile, "add-symbol-file %s 0x%x\n", ImageContext->PdbPointer, (unsigned int)(ImageContext->ImageAddress + ImageContext->SizeOfHeaders));
ccd55824 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
804405e7 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
7ee3b613 1151 Handle = dlopen (ImageContext->PdbPointer, RTLD_NOW);
865c7e17 1152
1153 if (Handle) {
7ee3b613 1154 Entry = dlsym (Handle, "_ModuleEntryPoint");
865c7e17 1155 } else {
1156 printf("%s\n", dlerror());
1157 }
1158
1159 if (Entry != NULL) {
ccd55824 1160 ImageContext->EntryPoint = (UINTN)Entry;
1161 printf("Change %s Entrypoint to :0x%08lx\n", ImageContext->PdbPointer, (unsigned long)Entry);
865c7e17 1162 }
1163
804405e7 1164 SecUnixLoaderBreak ();
1165
ccd55824 1166#endif
1167
1168 return;
804405e7 1169}
1170
1171
ccd55824 1172VOID
804405e7 1173EFIAPI
ccd55824 1174SecPeCoffLoaderUnloadImageExtraAction (
804405e7 1175 IN PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
1176 )
1177{
ccd55824 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;
804405e7 1217}
1218
1219VOID
1220ModuleEntryPoint (
1221 VOID
1222 )
1223{
1224}
1225
1226EFI_STATUS
1227EFIAPI
1228SecTemporaryRamSupport (
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 //
1fd8c31a 1260 // Simulate to invalid temporary memory, terminate temporary memory
804405e7 1261 //
1262 //ZeroMem ((VOID*)(UINTN)TemporaryMemoryBase, CopySize);
1263
1264 return EFI_SUCCESS;
1265}