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