]> git.proxmox.com Git - mirror_edk2.git/blob - UnixPkg/Sec/SecMain.c
move unnecessary print statement. It may cause confused.
[mirror_edk2.git] / UnixPkg / Sec / SecMain.c
1 /*++
2
3 Copyright (c) 2006 - 2007 Intel Corporation.
4 All rights reserved. This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution. The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
8
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
11
12 Module Name:
13
14 SecMain.c
15
16 Abstract:
17 WinNt emulator of SEC phase. It's really a Posix application, but this is
18 Ok since all the other modules for NT32 are NOT Posix applications.
19
20 This program processes host environment variables and figures out
21 what the memory layout will be, how may FD's will be loaded and also
22 what the boot mode is.
23
24 The SEC registers a set of services with the SEC core. gPrivateDispatchTable
25 is a list of PPI's produced by the SEC that are availble for usage in PEI.
26
27 This code produces 128 K of temporary memory for the PEI stack by opening a
28 host file and mapping it directly to memory addresses.
29
30 The system.cmd script is used to set host environment variables that drive
31 the configuration opitons of the SEC.
32
33 --*/
34
35 #include "SecMain.h"
36 #include <sys/mman.h>
37 #include <Ppi/UnixPeiLoadFile.h>
38 #include <Framework/StatusCode.h>
39 #include <Ppi/TemporaryRamSupport.h>
40 #include <dlfcn.h>
41 //
42 // Globals
43 //
44 EFI_PEI_PE_COFF_LOADER_PROTOCOL_INSTANCE mPeiEfiPeiPeCoffLoaderInstance = {
45 {
46 SecNt32PeCoffGetImageInfo,
47 SecNt32PeCoffLoadImage,
48 SecNt32PeCoffRelocateImage,
49 SecNt32PeCoffUnloadimage
50 },
51 NULL
52 };
53
54
55
56 EFI_PEI_PE_COFF_LOADER_PROTOCOL *gPeiEfiPeiPeCoffLoader = &mPeiEfiPeiPeCoffLoaderInstance.PeCoff;
57
58 UNIX_PEI_LOAD_FILE_PPI mSecNtLoadFilePpi = { SecWinNtPeiLoadFile };
59
60 PEI_UNIX_AUTOSCAN_PPI mSecNtAutoScanPpi = { SecWinNtPeiAutoScan };
61
62 PEI_UNIX_THUNK_PPI mSecWinNtThunkPpi = { SecWinNtWinNtThunkAddress };
63
64 EFI_PEI_PROGRESS_CODE_PPI mSecStatusCodePpi = { SecPeiReportStatusCode };
65
66 UNIX_FWH_PPI mSecFwhInformationPpi = { SecWinNtFdAddress };
67
68 TEMPORARY_RAM_SUPPORT_PPI mSecTemporaryRamSupportPpi = {SecTemporaryRamSupport};
69
70 EFI_PEI_PPI_DESCRIPTOR gPrivateDispatchTable[] = {
71 {
72 EFI_PEI_PPI_DESCRIPTOR_PPI,
73 &gEfiPeiPeCoffLoaderGuid,
74 NULL
75 },
76 {
77 EFI_PEI_PPI_DESCRIPTOR_PPI,
78 &gUnixPeiLoadFilePpiGuid,
79 &mSecNtLoadFilePpi
80 },
81 {
82 EFI_PEI_PPI_DESCRIPTOR_PPI,
83 &gPeiUnixAutoScanPpiGuid,
84 &mSecNtAutoScanPpi
85 },
86 {
87 EFI_PEI_PPI_DESCRIPTOR_PPI,
88 &gPeiUnixThunkPpiGuid,
89 &mSecWinNtThunkPpi
90 },
91 {
92 EFI_PEI_PPI_DESCRIPTOR_PPI,
93 &gEfiPeiStatusCodePpiGuid,
94 &mSecStatusCodePpi
95 },
96 {
97 EFI_PEI_PPI_DESCRIPTOR_PPI,
98 &gEfiTemporaryRamSupportPpiGuid,
99 &mSecTemporaryRamSupportPpi
100 },
101 {
102
103 EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST,
104 &gUnixFwhPpiGuid,
105 &mSecFwhInformationPpi
106 }
107 };
108
109
110 //
111 // Default information about where the FD is located.
112 // This array gets filled in with information from EFI_FIRMWARE_VOLUMES
113 // EFI_FIRMWARE_VOLUMES is a host environment variable set by system.cmd.
114 // The number of array elements is allocated base on parsing
115 // EFI_FIRMWARE_VOLUMES and the memory is never freed.
116 //
117 UINTN gFdInfoCount = 0;
118 UNIX_FD_INFO *gFdInfo;
119
120 //
121 // Array that supports seperate memory rantes.
122 // The memory ranges are set in system.cmd via the EFI_MEMORY_SIZE variable.
123 // The number of array elements is allocated base on parsing
124 // EFI_MEMORY_SIZE and the memory is never freed.
125 //
126 UINTN gSystemMemoryCount = 0;
127 UNIX_SYSTEM_MEMORY *gSystemMemory;
128
129 VOID
130 EFIAPI
131 SecSwitchStack (
132 UINT32 TemporaryMemoryBase,
133 UINT32 PermenentMemoryBase
134 );
135
136 STATIC
137 EFI_PHYSICAL_ADDRESS *
138 MapMemory (
139 INTN fd,
140 UINT64 length,
141 INTN prot,
142 INTN flags);
143
144 STATIC
145 EFI_STATUS
146 MapFile (
147 IN CHAR8 *FileName,
148 IN OUT EFI_PHYSICAL_ADDRESS *BaseAddress,
149 OUT UINT64 *Length
150 );
151
152
153 INTN
154 EFIAPI
155 main (
156 IN INTN Argc,
157 IN CHAR8 **Argv,
158 IN CHAR8 **Envp
159 )
160 /*++
161
162 Routine Description:
163 Main entry point to SEC for WinNt. This is a unix program
164
165 Arguments:
166 Argc - Number of command line arguments
167 Argv - Array of command line argument strings
168 Envp - Array of environmemt variable strings
169
170 Returns:
171 0 - Normal exit
172 1 - Abnormal exit
173
174 --*/
175 {
176 EFI_STATUS Status;
177 EFI_PHYSICAL_ADDRESS InitialStackMemory;
178 UINT64 InitialStackMemorySize;
179 UINTN Index;
180 UINTN Index1;
181 UINTN Index2;
182 UINTN PeiIndex;
183 CHAR8 *FileName;
184 BOOLEAN Done;
185 VOID *PeiCoreFile;
186 CHAR16 *MemorySizeStr;
187 CHAR16 *FirmwareVolumesStr;
188 UINTN *StackPointer;
189
190 setbuf(stdout, 0);
191 setbuf(stderr, 0);
192
193 MemorySizeStr = (CHAR16 *) FixedPcdGetPtr (PcdUnixMemorySizeForSecMain);
194 FirmwareVolumesStr = (CHAR16 *) FixedPcdGetPtr (PcdUnixFirmwareVolume);
195
196 printf ("\nEDK SEC Main UNIX Emulation Environment from www.TianoCore.org\n");
197
198 //
199 // Allocate space for gSystemMemory Array
200 //
201 gSystemMemoryCount = CountSeperatorsInString (MemorySizeStr, '!') + 1;
202 gSystemMemory = calloc (gSystemMemoryCount, sizeof (UNIX_SYSTEM_MEMORY));
203 if (gSystemMemory == NULL) {
204 printf ("ERROR : Can not allocate memory for system. Exiting.\n");
205 exit (1);
206 }
207 //
208 // Allocate space for gSystemMemory Array
209 //
210 gFdInfoCount = CountSeperatorsInString (FirmwareVolumesStr, '!') + 1;
211 gFdInfo = calloc (gFdInfoCount, sizeof (UNIX_FD_INFO));
212 if (gFdInfo == NULL) {
213 printf ("ERROR : Can not allocate memory for fd info. Exiting.\n");
214 exit (1);
215 }
216 //
217 // Setup Boot Mode. If BootModeStr == "" then BootMode = 0 (BOOT_WITH_FULL_CONFIGURATION)
218 //
219 printf (" BootMode 0x%02x\n", FixedPcdGet32 (PcdUnixBootMode));
220
221 //
222 // Open up a 128K file to emulate temp memory for PEI.
223 // on a real platform this would be SRAM, or using the cache as RAM.
224 // Set InitialStackMemory to zero so WinNtOpenFile will allocate a new mapping
225 //
226 InitialStackMemorySize = STACK_SIZE;
227 InitialStackMemory = (UINTN)MapMemory(0,
228 (UINT32) InitialStackMemorySize,
229 PROT_READ | PROT_WRITE,
230 MAP_ANONYMOUS | MAP_PRIVATE);
231 if (InitialStackMemory == 0) {
232 printf ("ERROR : Can not open SecStack Exiting\n");
233 exit (1);
234 }
235
236 printf (" SEC passing in %u KB of temp RAM at 0x%08lx to PEI\n",
237 (UINTN)(InitialStackMemorySize / 1024),
238 (unsigned long)InitialStackMemory);
239
240 for (StackPointer = (UINTN*) (UINTN) InitialStackMemory;
241 StackPointer < (UINTN*) ((UINTN) InitialStackMemory + (UINT64) InitialStackMemorySize);
242 StackPointer ++) {
243 *StackPointer = 0x5AA55AA5;
244 }
245
246 //
247 // Open All the firmware volumes and remember the info in the gFdInfo global
248 //
249 FileName = (CHAR8 *)malloc (StrLen (FirmwareVolumesStr) + 1);
250 if (FileName == NULL) {
251 printf ("ERROR : Can not allocate memory for firmware volume string\n");
252 exit (1);
253 }
254
255 Index2 = 0;
256 for (Done = FALSE, Index = 0, PeiIndex = 0, PeiCoreFile = NULL;
257 FirmwareVolumesStr[Index2] != 0;
258 Index++) {
259 for (Index1 = 0; (FirmwareVolumesStr[Index2] != '!') && (FirmwareVolumesStr[Index2] != 0); Index2++)
260 FileName[Index1++] = FirmwareVolumesStr[Index2];
261 if (FirmwareVolumesStr[Index2] == '!')
262 Index2++;
263 FileName[Index1] = '\0';
264
265 //
266 // Open the FD and remmeber where it got mapped into our processes address space
267 //
268 Status = MapFile (
269 FileName,
270 &gFdInfo[Index].Address,
271 &gFdInfo[Index].Size
272 );
273 if (EFI_ERROR (Status)) {
274 printf ("ERROR : Can not open Firmware Device File %s (%x). Exiting.\n", FileName, Status);
275 exit (1);
276 }
277
278 printf (" FD loaded from %s at 0x%08lx",
279 FileName, (unsigned long)gFdInfo[Index].Address);
280
281 if (PeiCoreFile == NULL) {
282 //
283 // Assume the beginning of the FD is an FV and look for the PEI Core.
284 // Load the first one we find.
285 //
286 Status = SecFfsFindPeiCore ((EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) gFdInfo[Index].Address, &PeiCoreFile);
287 if (!EFI_ERROR (Status)) {
288 PeiIndex = Index;
289 printf (" contains SEC Core");
290 }
291 }
292
293 printf ("\n");
294 }
295 //
296 // Calculate memory regions and store the information in the gSystemMemory
297 // global for later use. The autosizing code will use this data to
298 // map this memory into the SEC process memory space.
299 //
300 Index1 = 0;
301 Index = 0;
302 while (1) {
303 UINTN val = 0;
304 //
305 // Save the size of the memory.
306 //
307 while (MemorySizeStr[Index1] >= '0' && MemorySizeStr[Index1] <= '9') {
308 val = val * 10 + MemorySizeStr[Index1] - '0';
309 Index1++;
310 }
311 gSystemMemory[Index++].Size = val * 0x100000;
312 if (MemorySizeStr[Index1] == 0)
313 break;
314 Index1++;
315 }
316
317 printf ("\n");
318
319 //
320 // Hand off to PEI Core
321 //
322 SecLoadFromCore ((UINTN) InitialStackMemory, (UINTN) InitialStackMemorySize, (UINTN) gFdInfo[0].Address, PeiCoreFile);
323
324 //
325 // If we get here, then the PEI Core returned. This is an error as PEI should
326 // always hand off to DXE.
327 //
328 printf ("ERROR : PEI Core returned\n");
329 exit (1);
330 }
331
332 EFI_PHYSICAL_ADDRESS *
333 MapMemory (
334 INTN fd,
335 UINT64 length,
336 INTN prot,
337 INTN flags)
338 {
339 STATIC UINTN base = 0x40000000;
340 CONST UINTN align = (1 << 24);
341 VOID *res = NULL;
342 BOOLEAN isAligned = 0;
343
344 //
345 // Try to get an aligned block somewhere in the address space of this
346 // process.
347 //
348 while((!isAligned) && (base != 0)) {
349 res = mmap ((void *)base, length, prot, flags, fd, 0);
350 if (res == MAP_FAILED) {
351 return NULL;
352 }
353 if ((((UINTN)res) & ~(align-1)) == (UINTN)res) {
354 isAligned=1;
355 }
356 else {
357 munmap(res, length);
358 base += align;
359 }
360 }
361 return res;
362 }
363
364 EFI_STATUS
365 MapFile (
366 IN CHAR8 *FileName,
367 IN OUT EFI_PHYSICAL_ADDRESS *BaseAddress,
368 OUT UINT64 *Length
369 )
370 /*++
371
372 Routine Description:
373 Opens and memory maps a file using WinNt services. If BaseAddress is non zero
374 the process will try and allocate the memory starting at BaseAddress.
375
376 Arguments:
377 FileName - The name of the file to open and map
378 MapSize - The amount of the file to map in bytes
379 CreationDisposition - The flags to pass to CreateFile(). Use to create new files for
380 memory emulation, and exiting files for firmware volume emulation
381 BaseAddress - The base address of the mapped file in the user address space.
382 If passed in as NULL the a new memory region is used.
383 If passed in as non NULL the request memory region is used for
384 the mapping of the file into the process space.
385 Length - The size of the mapped region in bytes
386
387 Returns:
388 EFI_SUCCESS - The file was opened and mapped.
389 EFI_NOT_FOUND - FileName was not found in the current directory
390 EFI_DEVICE_ERROR - An error occured attempting to map the opened file
391
392 --*/
393 {
394 int fd;
395 VOID *res;
396 UINTN FileSize;
397
398 fd = open (FileName, O_RDONLY);
399 if (fd < 0)
400 return EFI_NOT_FOUND;
401 FileSize = lseek (fd, 0, SEEK_END);
402
403 #if 0
404 if (IsMain)
405 {
406 /* Read entry address. */
407 lseek (fd, FileSize - 0x20, SEEK_SET);
408 if (read (fd, &EntryAddress, 4) != 4)
409 {
410 close (fd);
411 return EFI_DEVICE_ERROR;
412 }
413 }
414 #endif
415
416 res = MapMemory(fd, FileSize, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE);
417
418 close (fd);
419
420 if (res == MAP_FAILED)
421 return EFI_DEVICE_ERROR;
422
423 *Length = (UINT64) FileSize;
424 *BaseAddress = (EFI_PHYSICAL_ADDRESS) (UINTN) res;
425
426 return EFI_SUCCESS;
427 }
428
429 #define BYTES_PER_RECORD 512
430
431 EFI_STATUS
432 EFIAPI
433 SecPeiReportStatusCode (
434 IN EFI_PEI_SERVICES **PeiServices,
435 IN EFI_STATUS_CODE_TYPE CodeType,
436 IN EFI_STATUS_CODE_VALUE Value,
437 IN UINT32 Instance,
438 IN EFI_GUID * CallerId,
439 IN EFI_STATUS_CODE_DATA * Data OPTIONAL
440 )
441 /*++
442
443 Routine Description:
444
445 This routine produces the ReportStatusCode PEI service. It's passed
446 up to the PEI Core via a PPI. T
447
448 This code currently uses the UNIX clib printf. This does not work the same way
449 as the EFI Print (), as %t, %g, %s as Unicode are not supported.
450
451 Arguments:
452 (see EFI_PEI_REPORT_STATUS_CODE)
453
454 Returns:
455 EFI_SUCCESS - Always return success
456
457 --*/
458 // TODO: PeiServices - add argument and description to function comment
459 // TODO: CodeType - add argument and description to function comment
460 // TODO: Value - add argument and description to function comment
461 // TODO: Instance - add argument and description to function comment
462 // TODO: CallerId - add argument and description to function comment
463 // TODO: Data - add argument and description to function comment
464 {
465 CHAR8 *Format;
466 VA_LIST Marker;
467 CHAR8 PrintBuffer[BYTES_PER_RECORD * 2];
468 CHAR8 *Filename;
469 CHAR8 *Description;
470 UINT32 LineNumber;
471 UINT32 ErrorLevel;
472
473
474 if (Data == NULL) {
475 } else if (ReportStatusCodeExtractAssertInfo (CodeType, Value, Data, &Filename, &Description, &LineNumber)) {
476 //
477 // Processes ASSERT ()
478 //
479 printf ("ASSERT %s(%d): %s\n", Filename, LineNumber, Description);
480
481 } else if (ReportStatusCodeExtractDebugInfo (Data, &ErrorLevel, &Marker, &Format)) {
482 //
483 // Process DEBUG () macro
484 //
485 AsciiVSPrint (PrintBuffer, BYTES_PER_RECORD, Format, Marker);
486 printf (PrintBuffer);
487 }
488
489 return EFI_SUCCESS;
490 }
491
492 /**
493 Transfers control to a function starting with a new stack.
494
495 Transfers control to the function specified by EntryPoint using the new stack
496 specified by NewStack and passing in the parameters specified by Context1 and
497 Context2. Context1 and Context2 are optional and may be NULL. The function
498 EntryPoint must never return.
499
500 If EntryPoint is NULL, then ASSERT().
501 If NewStack is NULL, then ASSERT().
502
503 @param EntryPoint A pointer to function to call with the new stack.
504 @param Context1 A pointer to the context to pass into the EntryPoint
505 function.
506 @param Context2 A pointer to the context to pass into the EntryPoint
507 function.
508 @param NewStack A pointer to the new stack to use for the EntryPoint
509 function.
510 @param NewBsp A pointer to the new BSP for the EntryPoint on IPF. It's
511 Reserved on other architectures.
512
513 **/
514 VOID
515 EFIAPI
516 PeiSwitchStacks (
517 IN SWITCH_STACK_ENTRY_POINT EntryPoint,
518 IN VOID *Context1, OPTIONAL
519 IN VOID *Context2, OPTIONAL
520 IN VOID *Context3, OPTIONAL
521 IN VOID *NewStack
522 )
523 {
524 BASE_LIBRARY_JUMP_BUFFER JumpBuffer;
525
526 ASSERT (EntryPoint != NULL);
527 ASSERT (NewStack != NULL);
528
529 //
530 // Stack should be aligned with CPU_STACK_ALIGNMENT
531 //
532 ASSERT (((UINTN)NewStack & (CPU_STACK_ALIGNMENT - 1)) == 0);
533
534 JumpBuffer.Eip = (UINTN)EntryPoint;
535 JumpBuffer.Esp = (UINTN)NewStack - sizeof (VOID*);
536 JumpBuffer.Esp -= sizeof (Context1) + sizeof (Context2) + sizeof(Context3);
537 ((VOID**)JumpBuffer.Esp)[1] = Context1;
538 ((VOID**)JumpBuffer.Esp)[2] = Context2;
539 ((VOID**)JumpBuffer.Esp)[3] = Context3;
540
541 LongJump (&JumpBuffer, (UINTN)-1);
542
543
544 //
545 // InternalSwitchStack () will never return
546 //
547 ASSERT (FALSE);
548 }
549
550 VOID
551 SecLoadFromCore (
552 IN UINTN LargestRegion,
553 IN UINTN LargestRegionSize,
554 IN UINTN BootFirmwareVolumeBase,
555 IN VOID *PeiCorePe32File
556 )
557 /*++
558
559 Routine Description:
560 This is the service to load the PEI Core from the Firmware Volume
561
562 Arguments:
563 LargestRegion - Memory to use for PEI.
564 LargestRegionSize - Size of Memory to use for PEI
565 BootFirmwareVolumeBase - Start of the Boot FV
566 PeiCorePe32File - PEI Core PE32
567
568 Returns:
569 Success means control is transfered and thus we should never return
570
571 --*/
572 {
573 EFI_STATUS Status;
574 EFI_PHYSICAL_ADDRESS TopOfMemory;
575 VOID *TopOfStack;
576 UINT64 PeiCoreSize;
577 EFI_PHYSICAL_ADDRESS PeiCoreEntryPoint;
578 EFI_PHYSICAL_ADDRESS PeiImageAddress;
579 EFI_SEC_PEI_HAND_OFF *SecCoreData;
580 UINTN PeiStackSize;
581
582 //
583 // Compute Top Of Memory for Stack and PEI Core Allocations
584 //
585 TopOfMemory = LargestRegion + LargestRegionSize;
586 PeiStackSize = (UINTN)RShiftU64((UINT64)STACK_SIZE,1);
587
588 //
589 // |-----------| <---- TemporaryRamBase + TemporaryRamSize
590 // | Heap |
591 // | |
592 // |-----------| <---- StackBase / PeiTemporaryMemoryBase
593 // | |
594 // | Stack |
595 // |-----------| <---- TemporaryRamBase
596 //
597 TopOfStack = (VOID *)(LargestRegion + PeiStackSize);
598 TopOfMemory = LargestRegion + PeiStackSize;
599
600 //
601 // Reservet space for storing PeiCore's parament in stack.
602 //
603 TopOfStack = (VOID *)((UINTN)TopOfStack - sizeof (EFI_SEC_PEI_HAND_OFF) - CPU_STACK_ALIGNMENT);
604 TopOfStack = ALIGN_POINTER (TopOfStack, CPU_STACK_ALIGNMENT);
605
606 //
607 // Patch value in dispatch table values
608 //
609 gPrivateDispatchTable[0].Ppi = gPeiEfiPeiPeCoffLoader;
610
611 //
612 // Bind this information into the SEC hand-off state
613 //
614 SecCoreData = (EFI_SEC_PEI_HAND_OFF*)(UINTN) TopOfStack;
615 SecCoreData->DataSize = sizeof(EFI_SEC_PEI_HAND_OFF);
616 SecCoreData->BootFirmwareVolumeBase = (VOID*)BootFirmwareVolumeBase;
617 SecCoreData->BootFirmwareVolumeSize = FixedPcdGet32(PcdUnixFirmwareFdSize);
618 SecCoreData->TemporaryRamBase = (VOID*)(UINTN)LargestRegion;
619 SecCoreData->TemporaryRamSize = STACK_SIZE;
620 SecCoreData->StackBase = SecCoreData->TemporaryRamBase;
621 SecCoreData->StackSize = PeiStackSize;
622 SecCoreData->PeiTemporaryRamBase = (VOID*) ((UINTN) SecCoreData->TemporaryRamBase + PeiStackSize);
623 SecCoreData->PeiTemporaryRamSize = STACK_SIZE - PeiStackSize;
624
625 //
626 // Load the PEI Core from a Firmware Volume
627 //
628 Status = SecWinNtPeiLoadFile (
629 PeiCorePe32File,
630 &PeiImageAddress,
631 &PeiCoreSize,
632 &PeiCoreEntryPoint
633 );
634 if (EFI_ERROR (Status)) {
635 return ;
636 }
637
638 //
639 // Transfer control to the PEI Core
640 //
641 PeiSwitchStacks (
642 (SWITCH_STACK_ENTRY_POINT) (UINTN) PeiCoreEntryPoint,
643 SecCoreData,
644 (VOID *) (UINTN) ((EFI_PEI_PPI_DESCRIPTOR *) &gPrivateDispatchTable),
645 NULL,
646 TopOfStack
647 );
648 //
649 // If we get here, then the PEI Core returned. This is an error
650 //
651 return ;
652 }
653
654 EFI_STATUS
655 EFIAPI
656 SecWinNtPeiAutoScan (
657 IN UINTN Index,
658 OUT EFI_PHYSICAL_ADDRESS *MemoryBase,
659 OUT UINT64 *MemorySize
660 )
661 /*++
662
663 Routine Description:
664 This service is called from Index == 0 until it returns EFI_UNSUPPORTED.
665 It allows discontiguous memory regions to be supported by the emulator.
666 It uses gSystemMemory[] and gSystemMemoryCount that were created by
667 parsing the host environment variable EFI_MEMORY_SIZE.
668 The size comes from the varaible and the address comes from the call to
669 WinNtOpenFile.
670
671 Arguments:
672 Index - Which memory region to use
673 MemoryBase - Return Base address of memory region
674 MemorySize - Return size in bytes of the memory region
675
676 Returns:
677 EFI_SUCCESS - If memory region was mapped
678 EFI_UNSUPPORTED - If Index is not supported
679
680 --*/
681 {
682 void *res;
683
684 if (Index >= gSystemMemoryCount) {
685 return EFI_UNSUPPORTED;
686 }
687
688 *MemoryBase = 0;
689 res = MapMemory(0, gSystemMemory[Index].Size,
690 PROT_READ | PROT_WRITE | PROT_EXEC,
691 MAP_PRIVATE | MAP_ANONYMOUS);
692 if (res == MAP_FAILED)
693 return EFI_DEVICE_ERROR;
694 *MemorySize = gSystemMemory[Index].Size;
695 *MemoryBase = (UINTN)res;
696 gSystemMemory[Index].Memory = *MemoryBase;
697
698 return EFI_SUCCESS;
699 }
700
701 VOID *
702 EFIAPI
703 SecWinNtWinNtThunkAddress (
704 VOID
705 )
706 /*++
707
708 Routine Description:
709 Since the SEC is the only Unix program in stack it must export
710 an interface to do Win API calls. That's what the WinNtThunk address
711 is for. gWinNt is initailized in WinNtThunk.c.
712
713 Arguments:
714 InterfaceSize - sizeof (EFI_WIN_NT_THUNK_PROTOCOL);
715 InterfaceBase - Address of the gWinNt global
716
717 Returns:
718 EFI_SUCCESS - Data returned
719
720 --*/
721 {
722 return gUnix;
723 }
724
725
726 EFI_STATUS
727 EFIAPI
728 SecWinNtPeiLoadFile (
729 IN VOID *Pe32Data,
730 IN EFI_PHYSICAL_ADDRESS *ImageAddress,
731 IN UINT64 *ImageSize,
732 IN EFI_PHYSICAL_ADDRESS *EntryPoint
733 )
734 /*++
735
736 Routine Description:
737 Loads and relocates a PE/COFF image into memory.
738
739 Arguments:
740 Pe32Data - The base address of the PE/COFF file that is to be loaded and relocated
741 ImageAddress - The base address of the relocated PE/COFF image
742 ImageSize - The size of the relocated PE/COFF image
743 EntryPoint - The entry point of the relocated PE/COFF image
744
745 Returns:
746 EFI_SUCCESS - The file was loaded and relocated
747 EFI_OUT_OF_RESOURCES - There was not enough memory to load and relocate the PE/COFF file
748
749 --*/
750 {
751 EFI_STATUS Status;
752 PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;
753
754 ZeroMem (&ImageContext, sizeof (ImageContext));
755 ImageContext.Handle = Pe32Data;
756
757 ImageContext.ImageRead = (PE_COFF_LOADER_READ_FILE) SecImageRead;
758
759 Status = gPeiEfiPeiPeCoffLoader->GetImageInfo (gPeiEfiPeiPeCoffLoader, &ImageContext);
760 if (EFI_ERROR (Status)) {
761 return Status;
762 }
763 //
764 // Allocate space in UNIX (not emulator) memory. Extra space is for alignment
765 //
766 ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS) (UINTN) malloc ((UINTN) (ImageContext.ImageSize + (ImageContext.SectionAlignment * 2)));
767 if (ImageContext.ImageAddress == 0) {
768 return EFI_OUT_OF_RESOURCES;
769 }
770 //
771 // Align buffer on section boundry
772 //
773 ImageContext.ImageAddress += ImageContext.SectionAlignment;
774 ImageContext.ImageAddress &= ~(ImageContext.SectionAlignment - 1);
775
776
777 Status = gPeiEfiPeiPeCoffLoader->LoadImage (gPeiEfiPeiPeCoffLoader, &ImageContext);
778 if (EFI_ERROR (Status)) {
779 return Status;
780 }
781
782 Status = gPeiEfiPeiPeCoffLoader->RelocateImage (gPeiEfiPeiPeCoffLoader, &ImageContext);
783 if (EFI_ERROR (Status)) {
784 return Status;
785 }
786
787 //
788 // BugBug: Flush Instruction Cache Here when CPU Lib is ready
789 //
790
791 *ImageAddress = ImageContext.ImageAddress;
792 *ImageSize = ImageContext.ImageSize;
793 *EntryPoint = ImageContext.EntryPoint;
794
795 return EFI_SUCCESS;
796 }
797
798 EFI_STATUS
799 EFIAPI
800 SecWinNtFdAddress (
801 IN UINTN Index,
802 IN OUT EFI_PHYSICAL_ADDRESS *FdBase,
803 IN OUT UINT64 *FdSize
804 )
805 /*++
806
807 Routine Description:
808 Return the FD Size and base address. Since the FD is loaded from a
809 file into host memory only the SEC will know it's address.
810
811 Arguments:
812 Index - Which FD, starts at zero.
813 FdSize - Size of the FD in bytes
814 FdBase - Start address of the FD. Assume it points to an FV Header
815
816 Returns:
817 EFI_SUCCESS - Return the Base address and size of the FV
818 EFI_UNSUPPORTED - Index does nto map to an FD in the system
819
820 --*/
821 {
822 if (Index >= gFdInfoCount) {
823 return EFI_UNSUPPORTED;
824 }
825
826 *FdBase = gFdInfo[Index].Address;
827 *FdSize = gFdInfo[Index].Size;
828
829 if (*FdBase == 0 && *FdSize == 0) {
830 return EFI_UNSUPPORTED;
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
906 EFI_STATUS
907 EFIAPI
908 SecNt32PeCoffGetImageInfo (
909 IN EFI_PEI_PE_COFF_LOADER_PROTOCOL *This,
910 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
911 )
912 {
913 EFI_STATUS Status;
914
915 Status = PeCoffLoaderGetImageInfo (ImageContext);
916 if (EFI_ERROR (Status)) {
917 return Status;
918 }
919
920 switch (ImageContext->ImageType) {
921
922 case EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION:
923 ImageContext->ImageCodeMemoryType = EfiLoaderCode;
924 ImageContext->ImageDataMemoryType = EfiLoaderData;
925 break;
926
927 case EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER:
928 ImageContext->ImageCodeMemoryType = EfiBootServicesCode;
929 ImageContext->ImageDataMemoryType = EfiBootServicesData;
930 break;
931
932 case EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER:
933 case EFI_IMAGE_SUBSYSTEM_SAL_RUNTIME_DRIVER:
934 ImageContext->ImageCodeMemoryType = EfiRuntimeServicesCode;
935 ImageContext->ImageDataMemoryType = EfiRuntimeServicesData;
936 break;
937
938 default:
939 ImageContext->ImageError = IMAGE_ERROR_INVALID_SUBSYSTEM;
940 return RETURN_UNSUPPORTED;
941 }
942
943 return Status;
944 }
945
946 EFI_STATUS
947 EFIAPI
948 SecNt32PeCoffLoadImage (
949 IN EFI_PEI_PE_COFF_LOADER_PROTOCOL *This,
950 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
951 )
952 {
953 EFI_STATUS Status;
954
955 Status = PeCoffLoaderLoadImage (ImageContext);
956 return Status;
957 }
958
959 VOID
960 SecUnixLoaderBreak (
961 VOID
962 )
963 {
964 }
965
966 EFI_STATUS
967 EFIAPI
968 SecNt32PeCoffRelocateImage (
969 IN EFI_PEI_PE_COFF_LOADER_PROTOCOL *This,
970 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
971 )
972 {
973 void * Handle;
974 void * Entry;
975 EFI_STATUS Status;
976
977 Handle = NULL;
978 Entry = NULL;
979 Status = PeCoffLoaderRelocateImage (ImageContext);
980 fprintf (stderr,
981 "Loading %s 0x%08lx - entry point 0x%08lx\n",
982 ImageContext->PdbPointer,
983 (unsigned long)ImageContext->ImageAddress,
984 (unsigned long)ImageContext->EntryPoint);
985
986 Handle = dlopen(ImageContext->PdbPointer, RTLD_NOW);
987
988 if (Handle) {
989 Entry = dlsym(Handle, "_ModuleEntryPoint");
990 } else {
991 printf("%s\n", dlerror());
992 }
993
994 if (Entry != NULL) {
995 ImageContext->EntryPoint = Entry;
996 printf("Change %s Entrypoint to :0x%08lx\n", ImageContext->PdbPointer, Entry);
997 }
998
999 SecUnixLoaderBreak ();
1000
1001 return Status;
1002 }
1003
1004
1005 EFI_STATUS
1006 EFIAPI
1007 SecNt32PeCoffUnloadimage (
1008 IN EFI_PEI_PE_COFF_LOADER_PROTOCOL *This,
1009 IN PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
1010 )
1011 {
1012 return EFI_SUCCESS;
1013 }
1014
1015 VOID
1016 ModuleEntryPoint (
1017 VOID
1018 )
1019 {
1020 }
1021
1022 EFI_STATUS
1023 EFIAPI
1024 SecTemporaryRamSupport (
1025 IN CONST EFI_PEI_SERVICES **PeiServices,
1026 IN EFI_PHYSICAL_ADDRESS TemporaryMemoryBase,
1027 IN EFI_PHYSICAL_ADDRESS PermanentMemoryBase,
1028 IN UINTN CopySize
1029 )
1030 {
1031 //
1032 // Migrate the whole temporary memory to permenent memory.
1033 //
1034 CopyMem (
1035 (VOID*)(UINTN)PermanentMemoryBase,
1036 (VOID*)(UINTN)TemporaryMemoryBase,
1037 CopySize
1038 );
1039
1040 //
1041 // SecSwitchStack function must be invoked after the memory migration
1042 // immediatly, also we need fixup the stack change caused by new call into
1043 // permenent memory.
1044 //
1045 SecSwitchStack (
1046 (UINT32) TemporaryMemoryBase,
1047 (UINT32) PermanentMemoryBase
1048 );
1049
1050 //
1051 // We need *not* fix the return address because currently,
1052 // The PeiCore is excuted in flash.
1053 //
1054
1055 //
1056 // Simulate to invalid CAR, terminate CAR
1057 //
1058 //ZeroMem ((VOID*)(UINTN)TemporaryMemoryBase, CopySize);
1059
1060 return EFI_SUCCESS;
1061 }