summaryrefslogtreecommitdiff
path: root/UnixPkg/Sec
diff options
context:
space:
mode:
Diffstat (limited to 'UnixPkg/Sec')
-rw-r--r--UnixPkg/Sec/FwVol.c314
-rw-r--r--UnixPkg/Sec/SecMain.c1048
-rw-r--r--UnixPkg/Sec/SecMain.h548
-rw-r--r--UnixPkg/Sec/SecMain.inf76
-rw-r--r--UnixPkg/Sec/SecMain.msa113
-rw-r--r--UnixPkg/Sec/Stack.S92
-rw-r--r--UnixPkg/Sec/UgaX11.c595
-rw-r--r--UnixPkg/Sec/UnixThunk.c197
8 files changed, 2983 insertions, 0 deletions
diff --git a/UnixPkg/Sec/FwVol.c b/UnixPkg/Sec/FwVol.c
new file mode 100644
index 0000000000..7206e00fbe
--- /dev/null
+++ b/UnixPkg/Sec/FwVol.c
@@ -0,0 +1,314 @@
+/*++
+
+Copyright (c) 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+Module Name:
+ FwVol.c
+
+Abstract:
+ A simple FV stack so the SEC can extract the SEC Core from an
+ FV.
+
+--*/
+
+#include "SecMain.h"
+
+#define GET_OCCUPIED_SIZE(ActualSize, Alignment) \
+ (ActualSize) + (((Alignment) - ((ActualSize) & ((Alignment) - 1))) & ((Alignment) - 1))
+
+EFI_FFS_FILE_STATE
+GetFileState (
+ IN UINT8 ErasePolarity,
+ IN EFI_FFS_FILE_HEADER *FfsHeader
+ )
+/*++
+
+Routine Description:
+ Returns the highest bit set of the State field
+
+Arguments:
+ ErasePolarity - Erase Polarity as defined by EFI_FVB2_ERASE_POLARITY
+ in the Attributes field.
+ FfsHeader - Pointer to FFS File Header.
+
+Returns:
+ Returns the highest bit in the State field
+
+--*/
+{
+ EFI_FFS_FILE_STATE FileState;
+ EFI_FFS_FILE_STATE HighestBit;
+
+ FileState = FfsHeader->State;
+
+ if (ErasePolarity != 0) {
+ FileState = (EFI_FFS_FILE_STATE)~FileState;
+ }
+
+ HighestBit = 0x80;
+ while (HighestBit != 0 && (HighestBit & FileState) == 0) {
+ HighestBit >>= 1;
+ }
+
+ return HighestBit;
+}
+
+UINT8
+CalculateHeaderChecksum (
+ IN EFI_FFS_FILE_HEADER *FileHeader
+ )
+/*++
+
+Routine Description:
+ Calculates the checksum of the header of a file.
+
+Arguments:
+ FileHeader - Pointer to FFS File Header.
+
+Returns:
+ Checksum of the header.
+
+--*/
+{
+ UINT8 *ptr;
+ UINTN Index;
+ UINT8 Sum;
+
+ Sum = 0;
+ ptr = (UINT8 *) FileHeader;
+
+ for (Index = 0; Index < sizeof (EFI_FFS_FILE_HEADER) - 3; Index += 4) {
+ Sum = (UINT8) (Sum + ptr[Index]);
+ Sum = (UINT8) (Sum + ptr[Index + 1]);
+ Sum = (UINT8) (Sum + ptr[Index + 2]);
+ Sum = (UINT8) (Sum + ptr[Index + 3]);
+ }
+
+ for (; Index < sizeof (EFI_FFS_FILE_HEADER); Index++) {
+ Sum = (UINT8) (Sum + ptr[Index]);
+ }
+ //
+ // State field (since this indicates the different state of file).
+ //
+ Sum = (UINT8) (Sum - FileHeader->State);
+ //
+ // Checksum field of the file is not part of the header checksum.
+ //
+ Sum = (UINT8) (Sum - FileHeader->IntegrityCheck.Checksum.File);
+
+ return Sum;
+}
+
+EFI_STATUS
+SecFfsFindNextFile (
+ IN EFI_FV_FILETYPE SearchType,
+ IN EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader,
+ IN OUT EFI_FFS_FILE_HEADER **FileHeader
+ )
+/*++
+
+Routine Description:
+ Given the input file pointer, search for the next matching file in the
+ FFS volume as defined by SearchType. The search starts from FileHeader inside
+ the Firmware Volume defined by FwVolHeader.
+
+Arguments:
+ SearchType - Filter to find only files of this type.
+ Type EFI_FV_FILETYPE_ALL causes no filtering to be done.
+ FwVolHeader - Pointer to the FV header of the volume to search.
+ This parameter must point to a valid FFS volume.
+ FileHeader - Pointer to the current file from which to begin searching.
+ This pointer will be updated upon return to reflect the file
+ found.
+
+Returns:
+ EFI_NOT_FOUND - No files matching the search criteria were found
+ EFI_SUCCESS
+
+--*/
+{
+ EFI_FFS_FILE_HEADER *FfsFileHeader;
+ UINT32 FileLength;
+ UINT32 FileOccupiedSize;
+ UINT32 FileOffset;
+ UINT64 FvLength;
+ UINT8 ErasePolarity;
+ UINT8 FileState;
+
+ FvLength = FwVolHeader->FvLength;
+ if (FwVolHeader->Attributes & EFI_FVB2_ERASE_POLARITY) {
+ ErasePolarity = 1;
+ } else {
+ ErasePolarity = 0;
+ }
+ //
+ // If FileHeader is not specified (NULL) start with the first file in the
+ // firmware volume. Otherwise, start from the FileHeader.
+ //
+ if (*FileHeader == NULL) {
+ FfsFileHeader = (EFI_FFS_FILE_HEADER *) ((UINT8 *) FwVolHeader + FwVolHeader->HeaderLength);
+ } else {
+ //
+ // Length is 24 bits wide so mask upper 8 bits
+ // FileLength is adjusted to FileOccupiedSize as it is 8 byte aligned.
+ //
+ FileLength = *(UINT32 *) (*FileHeader)->Size & 0x00FFFFFF;
+ FileOccupiedSize = GET_OCCUPIED_SIZE (FileLength, 8);
+ FfsFileHeader = (EFI_FFS_FILE_HEADER *) ((UINT8 *) *FileHeader + FileOccupiedSize);
+ }
+
+ FileOffset = (UINT32) ((UINT8 *) FfsFileHeader - (UINT8 *) FwVolHeader);
+
+ while (FileOffset < (FvLength - sizeof (EFI_FFS_FILE_HEADER))) {
+ //
+ // Get FileState which is the highest bit of the State
+ //
+ FileState = GetFileState (ErasePolarity, FfsFileHeader);
+
+ switch (FileState) {
+
+ case EFI_FILE_HEADER_INVALID:
+ FileOffset += sizeof (EFI_FFS_FILE_HEADER);
+ FfsFileHeader = (EFI_FFS_FILE_HEADER *) ((UINT8 *) FfsFileHeader + sizeof (EFI_FFS_FILE_HEADER));
+ break;
+
+ case EFI_FILE_DATA_VALID:
+ case EFI_FILE_MARKED_FOR_UPDATE:
+ if (CalculateHeaderChecksum (FfsFileHeader) == 0) {
+ FileLength = *(UINT32 *) (FfsFileHeader->Size) & 0x00FFFFFF;
+ FileOccupiedSize = GET_OCCUPIED_SIZE (FileLength, 8);
+
+ if ((SearchType == FfsFileHeader->Type) || (SearchType == EFI_FV_FILETYPE_ALL)) {
+
+ *FileHeader = FfsFileHeader;
+
+ return EFI_SUCCESS;
+ }
+
+ FileOffset += FileOccupiedSize;
+ FfsFileHeader = (EFI_FFS_FILE_HEADER *) ((UINT8 *) FfsFileHeader + FileOccupiedSize);
+ } else {
+ return EFI_NOT_FOUND;
+ }
+ break;
+
+ case EFI_FILE_DELETED:
+ FileLength = *(UINT32 *) (FfsFileHeader->Size) & 0x00FFFFFF;
+ FileOccupiedSize = GET_OCCUPIED_SIZE (FileLength, 8);
+ FileOffset += FileOccupiedSize;
+ FfsFileHeader = (EFI_FFS_FILE_HEADER *) ((UINT8 *) FfsFileHeader + FileOccupiedSize);
+ break;
+
+ default:
+ return EFI_NOT_FOUND;
+
+ }
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+EFI_STATUS
+SecFfsFindSectionData (
+ IN EFI_SECTION_TYPE SectionType,
+ IN EFI_FFS_FILE_HEADER *FfsFileHeader,
+ IN OUT VOID **SectionData
+ )
+/*++
+
+Routine Description:
+ Given the input file pointer, search for the next matching section in the
+ FFS volume.
+
+Arguments:
+ SearchType - Filter to find only sections of this type.
+ FfsFileHeader - Pointer to the current file to search.
+ SectionData - Pointer to the Section matching SectionType in FfsFileHeader.
+ NULL if section not found
+
+Returns:
+ EFI_NOT_FOUND - No files matching the search criteria were found
+ EFI_SUCCESS
+
+--*/
+{
+ UINT32 FileSize;
+ EFI_COMMON_SECTION_HEADER *Section;
+ UINT32 SectionLength;
+ UINT32 ParsedLength;
+
+ //
+ // Size is 24 bits wide so mask upper 8 bits.
+ // Does not include FfsFileHeader header size
+ // FileSize is adjusted to FileOccupiedSize as it is 8 byte aligned.
+ //
+ Section = (EFI_COMMON_SECTION_HEADER *) (FfsFileHeader + 1);
+ FileSize = *(UINT32 *) (FfsFileHeader->Size) & 0x00FFFFFF;
+ FileSize -= sizeof (EFI_FFS_FILE_HEADER);
+
+ *SectionData = NULL;
+ ParsedLength = 0;
+ while (ParsedLength < FileSize) {
+ if (Section->Type == SectionType) {
+ *SectionData = (VOID *) (Section + 1);
+ return EFI_SUCCESS;
+ }
+ //
+ // Size is 24 bits wide so mask upper 8 bits.
+ // SectionLength is adjusted it is 4 byte aligned.
+ // Go to the next section
+ //
+ SectionLength = *(UINT32 *) Section->Size & 0x00FFFFFF;
+ SectionLength = GET_OCCUPIED_SIZE (SectionLength, 4);
+
+ ParsedLength += SectionLength;
+ Section = (EFI_COMMON_SECTION_HEADER *) ((UINT8 *) Section + SectionLength);
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+EFI_STATUS
+SecFfsFindPeiCore (
+ IN EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader,
+ OUT VOID **Pe32Data
+ )
+/*++
+
+Routine Description:
+ Given the pointer to the Firmware Volume Header find the SEC
+ core and return it's PE32 image.
+
+Arguments:
+ FwVolHeader - Pointer to memory mapped FV
+ Pe32Data - Pointer to SEC PE32 iamge.
+
+Returns:
+ EFI_SUCCESS - Pe32Data is valid
+ other - Failure
+
+--*/
+{
+ EFI_STATUS Status;
+ EFI_FFS_FILE_HEADER *FileHeader;
+ EFI_FV_FILETYPE SearchType;
+
+ SearchType = EFI_FV_FILETYPE_PEI_CORE;
+ FileHeader = NULL;
+ do {
+ Status = SecFfsFindNextFile (SearchType, FwVolHeader, &FileHeader);
+ if (!EFI_ERROR (Status)) {
+ Status = SecFfsFindSectionData (EFI_SECTION_PE32, FileHeader, Pe32Data);
+ return Status;
+ }
+ } while (!EFI_ERROR (Status));
+
+ return Status;
+}
diff --git a/UnixPkg/Sec/SecMain.c b/UnixPkg/Sec/SecMain.c
new file mode 100644
index 0000000000..a6da20b135
--- /dev/null
+++ b/UnixPkg/Sec/SecMain.c
@@ -0,0 +1,1048 @@
+/*++
+
+Copyright (c) 2006 - 2007 Intel Corporation.
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+Module Name:
+
+ SecMain.c
+
+Abstract:
+ WinNt emulator of SEC phase. It's really a Posix application, but this is
+ Ok since all the other modules for NT32 are NOT Posix applications.
+
+ This program processes host environment variables and figures out
+ what the memory layout will be, how may FD's will be loaded and also
+ what the boot mode is.
+
+ The SEC registers a set of services with the SEC core. gPrivateDispatchTable
+ is a list of PPI's produced by the SEC that are availble for usage in PEI.
+
+ This code produces 128 K of temporary memory for the PEI stack by opening a
+ host file and mapping it directly to memory addresses.
+
+ The system.cmd script is used to set host environment variables that drive
+ the configuration opitons of the SEC.
+
+--*/
+
+#include "SecMain.h"
+#include <sys/mman.h>
+#include <Ppi/UnixPeiLoadFile.h>
+#include <Framework/StatusCode.h>
+#include <Ppi/TemporaryRamSupport.h>
+#include <dlfcn.h>
+//
+// Globals
+//
+EFI_PEI_PE_COFF_LOADER_PROTOCOL_INSTANCE mPeiEfiPeiPeCoffLoaderInstance = {
+ {
+ SecNt32PeCoffGetImageInfo,
+ SecNt32PeCoffLoadImage,
+ SecNt32PeCoffRelocateImage,
+ SecNt32PeCoffUnloadimage
+ },
+ NULL
+};
+
+
+
+EFI_PEI_PE_COFF_LOADER_PROTOCOL *gPeiEfiPeiPeCoffLoader = &mPeiEfiPeiPeCoffLoaderInstance.PeCoff;
+
+UNIX_PEI_LOAD_FILE_PPI mSecNtLoadFilePpi = { SecWinNtPeiLoadFile };
+
+PEI_UNIX_AUTOSCAN_PPI mSecNtAutoScanPpi = { SecWinNtPeiAutoScan };
+
+PEI_UNIX_THUNK_PPI mSecWinNtThunkPpi = { SecWinNtWinNtThunkAddress };
+
+EFI_PEI_PROGRESS_CODE_PPI mSecStatusCodePpi = { SecPeiReportStatusCode };
+
+UNIX_FWH_PPI mSecFwhInformationPpi = { SecWinNtFdAddress };
+
+TEMPORARY_RAM_SUPPORT_PPI mSecTemporaryRamSupportPpi = {SecTemporaryRamSupport};
+
+EFI_PEI_PPI_DESCRIPTOR gPrivateDispatchTable[] = {
+ {
+ EFI_PEI_PPI_DESCRIPTOR_PPI,
+ &gEfiPeiPeCoffLoaderGuid,
+ NULL
+ },
+ {
+ EFI_PEI_PPI_DESCRIPTOR_PPI,
+ &gUnixPeiLoadFilePpiGuid,
+ &mSecNtLoadFilePpi
+ },
+ {
+ EFI_PEI_PPI_DESCRIPTOR_PPI,
+ &gPeiUnixAutoScanPpiGuid,
+ &mSecNtAutoScanPpi
+ },
+ {
+ EFI_PEI_PPI_DESCRIPTOR_PPI,
+ &gPeiUnixThunkPpiGuid,
+ &mSecWinNtThunkPpi
+ },
+ {
+ EFI_PEI_PPI_DESCRIPTOR_PPI,
+ &gEfiPeiStatusCodePpiGuid,
+ &mSecStatusCodePpi
+ },
+ {
+ EFI_PEI_PPI_DESCRIPTOR_PPI,
+ &gEfiTemporaryRamSupportPpiGuid,
+ &mSecTemporaryRamSupportPpi
+ },
+ {
+
+ EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST,
+ &gUnixFwhPpiGuid,
+ &mSecFwhInformationPpi
+ }
+};
+
+
+//
+// Default information about where the FD is located.
+// This array gets filled in with information from EFI_FIRMWARE_VOLUMES
+// EFI_FIRMWARE_VOLUMES is a host environment variable set by system.cmd.
+// The number of array elements is allocated base on parsing
+// EFI_FIRMWARE_VOLUMES and the memory is never freed.
+//
+UINTN gFdInfoCount = 0;
+UNIX_FD_INFO *gFdInfo;
+
+//
+// Array that supports seperate memory rantes.
+// The memory ranges are set in system.cmd via the EFI_MEMORY_SIZE variable.
+// The number of array elements is allocated base on parsing
+// EFI_MEMORY_SIZE and the memory is never freed.
+//
+UINTN gSystemMemoryCount = 0;
+UNIX_SYSTEM_MEMORY *gSystemMemory;
+
+VOID
+EFIAPI
+SecSwitchStack (
+ UINT32 TemporaryMemoryBase,
+ UINT32 PermenentMemoryBase
+ );
+
+STATIC
+EFI_PHYSICAL_ADDRESS *
+MapMemory (
+ INTN fd,
+ UINT64 length,
+ INTN prot,
+ INTN flags);
+
+STATIC
+EFI_STATUS
+MapFile (
+ IN CHAR8 *FileName,
+ IN OUT EFI_PHYSICAL_ADDRESS *BaseAddress,
+ OUT UINT64 *Length
+ );
+
+
+INTN
+EFIAPI
+main (
+ IN INTN Argc,
+ IN CHAR8 **Argv,
+ IN CHAR8 **Envp
+ )
+/*++
+
+Routine Description:
+ Main entry point to SEC for WinNt. This is a unix program
+
+Arguments:
+ Argc - Number of command line arguments
+ Argv - Array of command line argument strings
+ Envp - Array of environmemt variable strings
+
+Returns:
+ 0 - Normal exit
+ 1 - Abnormal exit
+
+--*/
+{
+ EFI_STATUS Status;
+ EFI_PHYSICAL_ADDRESS InitialStackMemory;
+ UINT64 InitialStackMemorySize;
+ UINTN Index;
+ UINTN Index1;
+ UINTN Index2;
+ UINTN PeiIndex;
+ CHAR8 *FileName;
+ BOOLEAN Done;
+ VOID *PeiCoreFile;
+ CHAR16 *MemorySizeStr;
+ CHAR16 *FirmwareVolumesStr;
+ UINTN *StackPointer;
+
+ setbuf(stdout, 0);
+ setbuf(stderr, 0);
+
+ MemorySizeStr = (CHAR16 *) FixedPcdGetPtr (PcdUnixMemorySizeForSecMain);
+ FirmwareVolumesStr = (CHAR16 *) FixedPcdGetPtr (PcdUnixFirmwareVolume);
+
+ printf ("\nEDK SEC Main UNIX Emulation Environment from www.TianoCore.org\n");
+
+ //
+ // Allocate space for gSystemMemory Array
+ //
+ gSystemMemoryCount = CountSeperatorsInString (MemorySizeStr, '!') + 1;
+ gSystemMemory = calloc (gSystemMemoryCount, sizeof (UNIX_SYSTEM_MEMORY));
+ if (gSystemMemory == NULL) {
+ printf ("ERROR : Can not allocate memory for system. Exiting.\n");
+ exit (1);
+ }
+ //
+ // Allocate space for gSystemMemory Array
+ //
+ gFdInfoCount = CountSeperatorsInString (FirmwareVolumesStr, '!') + 1;
+ gFdInfo = calloc (gFdInfoCount, sizeof (UNIX_FD_INFO));
+ if (gFdInfo == NULL) {
+ printf ("ERROR : Can not allocate memory for fd info. Exiting.\n");
+ exit (1);
+ }
+ //
+ // Setup Boot Mode. If BootModeStr == "" then BootMode = 0 (BOOT_WITH_FULL_CONFIGURATION)
+ //
+ printf (" BootMode 0x%02x\n", FixedPcdGet32 (PcdUnixBootMode));
+
+ //
+ // Open up a 128K file to emulate temp memory for PEI.
+ // on a real platform this would be SRAM, or using the cache as RAM.
+ // Set InitialStackMemory to zero so WinNtOpenFile will allocate a new mapping
+ //
+ InitialStackMemorySize = STACK_SIZE;
+ InitialStackMemory = (UINTN)MapMemory(0,
+ (UINT32) InitialStackMemorySize,
+ PROT_READ | PROT_WRITE,
+ MAP_ANONYMOUS | MAP_PRIVATE);
+ if (InitialStackMemory == 0) {
+ printf ("ERROR : Can not open SecStack Exiting\n");
+ exit (1);
+ }
+
+ printf (" SEC passing in %u KB of temp RAM at 0x%08lx to PEI\n",
+ (UINTN)(InitialStackMemorySize / 1024),
+ (unsigned long)InitialStackMemory);
+
+ for (StackPointer = (UINTN*) (UINTN) InitialStackMemory;
+ StackPointer < (UINTN*) ((UINTN) InitialStackMemory + (UINT64) InitialStackMemorySize);
+ StackPointer ++) {
+ *StackPointer = 0x5AA55AA5;
+ }
+
+ //
+ // Open All the firmware volumes and remember the info in the gFdInfo global
+ //
+ FileName = (CHAR8 *)malloc (StrLen (FirmwareVolumesStr) + 1);
+ if (FileName == NULL) {
+ printf ("ERROR : Can not allocate memory for firmware volume string\n");
+ exit (1);
+ }
+
+ Index2 = 0;
+ for (Done = FALSE, Index = 0, PeiIndex = 0, PeiCoreFile = NULL;
+ FirmwareVolumesStr[Index2] != 0;
+ Index++) {
+ for (Index1 = 0; (FirmwareVolumesStr[Index2] != '!') && (FirmwareVolumesStr[Index2] != 0); Index2++)
+ FileName[Index1++] = FirmwareVolumesStr[Index2];
+ if (FirmwareVolumesStr[Index2] == '!')
+ Index2++;
+ FileName[Index1] = '\0';
+
+ //
+ // Open the FD and remmeber where it got mapped into our processes address space
+ //
+ Status = MapFile (
+ FileName,
+ &gFdInfo[Index].Address,
+ &gFdInfo[Index].Size
+ );
+ if (EFI_ERROR (Status)) {
+ printf ("ERROR : Can not open Firmware Device File %s (%x). Exiting.\n", FileName, Status);
+ exit (1);
+ }
+
+ printf (" FD loaded from %s at 0x%08lx",
+ FileName, (unsigned long)gFdInfo[Index].Address);
+
+ if (PeiCoreFile == NULL) {
+ //
+ // Assume the beginning of the FD is an FV and look for the PEI Core.
+ // Load the first one we find.
+ //
+ Status = SecFfsFindPeiCore ((EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) gFdInfo[Index].Address, &PeiCoreFile);
+ if (!EFI_ERROR (Status)) {
+ PeiIndex = Index;
+ printf (" contains SEC Core");
+ }
+ }
+
+ printf ("\n");
+ }
+ //
+ // Calculate memory regions and store the information in the gSystemMemory
+ // global for later use. The autosizing code will use this data to
+ // map this memory into the SEC process memory space.
+ //
+ Index1 = 0;
+ Index = 0;
+ while (1) {
+ UINTN val = 0;
+ //
+ // Save the size of the memory.
+ //
+ while (MemorySizeStr[Index1] >= '0' && MemorySizeStr[Index1] <= '9') {
+ val = val * 10 + MemorySizeStr[Index1] - '0';
+ Index1++;
+ }
+ gSystemMemory[Index++].Size = val * 0x100000;
+ if (MemorySizeStr[Index1] == 0)
+ break;
+ Index1++;
+ }
+
+ printf ("\n");
+
+ //
+ // Hand off to PEI Core
+ //
+ SecLoadFromCore ((UINTN) InitialStackMemory, (UINTN) InitialStackMemorySize, (UINTN) gFdInfo[0].Address, PeiCoreFile);
+
+ //
+ // If we get here, then the PEI Core returned. This is an error as PEI should
+ // always hand off to DXE.
+ //
+ printf ("ERROR : PEI Core returned\n");
+ exit (1);
+}
+
+EFI_PHYSICAL_ADDRESS *
+MapMemory (
+ INTN fd,
+ UINT64 length,
+ INTN prot,
+ INTN flags)
+{
+ STATIC UINTN base = 0x40000000;
+ CONST UINTN align = (1 << 24);
+ VOID *res = NULL;
+ BOOLEAN isAligned = 0;
+
+ //
+ // Try to get an aligned block somewhere in the address space of this
+ // process.
+ //
+ while((!isAligned) && (base != 0)) {
+ res = mmap ((void *)base, length, prot, flags, fd, 0);
+ if (res == MAP_FAILED) {
+ return NULL;
+ }
+ if ((((UINTN)res) & ~(align-1)) == (UINTN)res) {
+ isAligned=1;
+ }
+ else {
+ munmap(res, length);
+ base += align;
+ }
+ }
+ return res;
+}
+
+EFI_STATUS
+MapFile (
+ IN CHAR8 *FileName,
+ IN OUT EFI_PHYSICAL_ADDRESS *BaseAddress,
+ OUT UINT64 *Length
+ )
+/*++
+
+Routine Description:
+ Opens and memory maps a file using WinNt services. If BaseAddress is non zero
+ the process will try and allocate the memory starting at BaseAddress.
+
+Arguments:
+ FileName - The name of the file to open and map
+ MapSize - The amount of the file to map in bytes
+ CreationDisposition - The flags to pass to CreateFile(). Use to create new files for
+ memory emulation, and exiting files for firmware volume emulation
+ BaseAddress - The base address of the mapped file in the user address space.
+ If passed in as NULL the a new memory region is used.
+ If passed in as non NULL the request memory region is used for
+ the mapping of the file into the process space.
+ Length - The size of the mapped region in bytes
+
+Returns:
+ EFI_SUCCESS - The file was opened and mapped.
+ EFI_NOT_FOUND - FileName was not found in the current directory
+ EFI_DEVICE_ERROR - An error occured attempting to map the opened file
+
+--*/
+{
+ int fd;
+ VOID *res;
+ UINTN FileSize;
+
+ fd = open (FileName, O_RDONLY);
+ if (fd < 0)
+ return EFI_NOT_FOUND;
+ FileSize = lseek (fd, 0, SEEK_END);
+
+#if 0
+ if (IsMain)
+ {
+ /* Read entry address. */
+ lseek (fd, FileSize - 0x20, SEEK_SET);
+ if (read (fd, &EntryAddress, 4) != 4)
+ {
+ close (fd);
+ return EFI_DEVICE_ERROR;
+ }
+ }
+#endif
+
+ res = MapMemory(fd, FileSize, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE);
+
+ close (fd);
+
+ if (res == MAP_FAILED)
+ return EFI_DEVICE_ERROR;
+
+ *Length = (UINT64) FileSize;
+ *BaseAddress = (EFI_PHYSICAL_ADDRESS) (UINTN) res;
+
+ return EFI_SUCCESS;
+}
+
+#define BYTES_PER_RECORD 512
+
+EFI_STATUS
+EFIAPI
+SecPeiReportStatusCode (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_STATUS_CODE_TYPE CodeType,
+ IN EFI_STATUS_CODE_VALUE Value,
+ IN UINT32 Instance,
+ IN EFI_GUID * CallerId,
+ IN EFI_STATUS_CODE_DATA * Data OPTIONAL
+ )
+/*++
+
+Routine Description:
+
+ This routine produces the ReportStatusCode PEI service. It's passed
+ up to the PEI Core via a PPI. T
+
+ This code currently uses the UNIX clib printf. This does not work the same way
+ as the EFI Print (), as %t, %g, %s as Unicode are not supported.
+
+Arguments:
+ (see EFI_PEI_REPORT_STATUS_CODE)
+
+Returns:
+ EFI_SUCCESS - Always return success
+
+--*/
+// TODO: PeiServices - add argument and description to function comment
+// TODO: CodeType - add argument and description to function comment
+// TODO: Value - add argument and description to function comment
+// TODO: Instance - add argument and description to function comment
+// TODO: CallerId - add argument and description to function comment
+// TODO: Data - add argument and description to function comment
+{
+ CHAR8 *Format;
+ VA_LIST Marker;
+ CHAR8 PrintBuffer[BYTES_PER_RECORD * 2];
+ CHAR8 *Filename;
+ CHAR8 *Description;
+ UINT32 LineNumber;
+ UINT32 ErrorLevel;
+
+
+ if (Data == NULL) {
+ } else if (ReportStatusCodeExtractAssertInfo (CodeType, Value, Data, &Filename, &Description, &LineNumber)) {
+ //
+ // Processes ASSERT ()
+ //
+ printf ("ASSERT %s(%d): %s\n", Filename, LineNumber, Description);
+
+ } else if (ReportStatusCodeExtractDebugInfo (Data, &ErrorLevel, &Marker, &Format)) {
+ //
+ // Process DEBUG () macro
+ //
+ AsciiVSPrint (PrintBuffer, BYTES_PER_RECORD, Format, Marker);
+ printf (PrintBuffer);
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Transfers control to a function starting with a new stack.
+
+ Transfers control to the function specified by EntryPoint using the new stack
+ specified by NewStack and passing in the parameters specified by Context1 and
+ Context2. Context1 and Context2 are optional and may be NULL. The function
+ EntryPoint must never return.
+
+ If EntryPoint is NULL, then ASSERT().
+ If NewStack is NULL, then ASSERT().
+
+ @param EntryPoint A pointer to function to call with the new stack.
+ @param Context1 A pointer to the context to pass into the EntryPoint
+ function.
+ @param Context2 A pointer to the context to pass into the EntryPoint
+ function.
+ @param NewStack A pointer to the new stack to use for the EntryPoint
+ function.
+ @param NewBsp A pointer to the new BSP for the EntryPoint on IPF. It's
+ Reserved on other architectures.
+
+**/
+VOID
+EFIAPI
+PeiSwitchStacks (
+ IN SWITCH_STACK_ENTRY_POINT EntryPoint,
+ IN VOID *Context1, OPTIONAL
+ IN VOID *Context2, OPTIONAL
+ IN VOID *Context3, OPTIONAL
+ IN VOID *NewStack
+ )
+{
+ BASE_LIBRARY_JUMP_BUFFER JumpBuffer;
+
+ ASSERT (EntryPoint != NULL);
+ ASSERT (NewStack != NULL);
+
+ //
+ // Stack should be aligned with CPU_STACK_ALIGNMENT
+ //
+ ASSERT (((UINTN)NewStack & (CPU_STACK_ALIGNMENT - 1)) == 0);
+
+ JumpBuffer.Eip = (UINTN)EntryPoint;
+ JumpBuffer.Esp = (UINTN)NewStack - sizeof (VOID*);
+ JumpBuffer.Esp -= sizeof (Context1) + sizeof (Context2) + sizeof(Context3);
+ ((VOID**)JumpBuffer.Esp)[1] = Context1;
+ ((VOID**)JumpBuffer.Esp)[2] = Context2;
+ ((VOID**)JumpBuffer.Esp)[3] = Context3;
+
+ LongJump (&JumpBuffer, (UINTN)-1);
+
+
+ //
+ // InternalSwitchStack () will never return
+ //
+ ASSERT (FALSE);
+}
+
+VOID
+SecLoadFromCore (
+ IN UINTN LargestRegion,
+ IN UINTN LargestRegionSize,
+ IN UINTN BootFirmwareVolumeBase,
+ IN VOID *PeiCorePe32File
+ )
+/*++
+
+Routine Description:
+ This is the service to load the PEI Core from the Firmware Volume
+
+Arguments:
+ LargestRegion - Memory to use for PEI.
+ LargestRegionSize - Size of Memory to use for PEI
+ BootFirmwareVolumeBase - Start of the Boot FV
+ PeiCorePe32File - PEI Core PE32
+
+Returns:
+ Success means control is transfered and thus we should never return
+
+--*/
+{
+ EFI_STATUS Status;
+ EFI_PHYSICAL_ADDRESS TopOfMemory;
+ VOID *TopOfStack;
+ UINT64 PeiCoreSize;
+ EFI_PHYSICAL_ADDRESS PeiCoreEntryPoint;
+ EFI_PHYSICAL_ADDRESS PeiImageAddress;
+ EFI_SEC_PEI_HAND_OFF *SecCoreData;
+ UINTN PeiStackSize;
+
+ //
+ // Compute Top Of Memory for Stack and PEI Core Allocations
+ //
+ TopOfMemory = LargestRegion + LargestRegionSize;
+ PeiStackSize = (UINTN)RShiftU64((UINT64)STACK_SIZE,1);
+
+ //
+ // |-----------| <---- TemporaryRamBase + TemporaryRamSize
+ // | Heap |
+ // | |
+ // |-----------| <---- StackBase / PeiTemporaryMemoryBase
+ // | |
+ // | Stack |
+ // |-----------| <---- TemporaryRamBase
+ //
+ TopOfStack = (VOID *)(LargestRegion + PeiStackSize);
+ TopOfMemory = LargestRegion + PeiStackSize;
+
+ //
+ // Reservet space for storing PeiCore's parament in stack.
+ //
+ TopOfStack = (VOID *)((UINTN)TopOfStack - sizeof (EFI_SEC_PEI_HAND_OFF) - CPU_STACK_ALIGNMENT);
+ TopOfStack = ALIGN_POINTER (TopOfStack, CPU_STACK_ALIGNMENT);
+
+ //
+ // Patch value in dispatch table values
+ //
+ gPrivateDispatchTable[0].Ppi = gPeiEfiPeiPeCoffLoader;
+
+ //
+ // Bind this information into the SEC hand-off state
+ //
+ SecCoreData = (EFI_SEC_PEI_HAND_OFF*)(UINTN) TopOfStack;
+ SecCoreData->DataSize = sizeof(EFI_SEC_PEI_HAND_OFF);
+ SecCoreData->BootFirmwareVolumeBase = (VOID*)BootFirmwareVolumeBase;
+ SecCoreData->BootFirmwareVolumeSize = FixedPcdGet32(PcdUnixFirmwareFdSize);
+ SecCoreData->TemporaryRamBase = (VOID*)(UINTN)LargestRegion;
+ SecCoreData->TemporaryRamSize = STACK_SIZE;
+ SecCoreData->StackBase = SecCoreData->TemporaryRamBase;
+ SecCoreData->StackSize = PeiStackSize;
+ SecCoreData->PeiTemporaryRamBase = (VOID*) ((UINTN) SecCoreData->TemporaryRamBase + PeiStackSize);
+ SecCoreData->PeiTemporaryRamSize = STACK_SIZE - PeiStackSize;
+
+ //
+ // Load the PEI Core from a Firmware Volume
+ //
+ Status = SecWinNtPeiLoadFile (
+ PeiCorePe32File,
+ &PeiImageAddress,
+ &PeiCoreSize,
+ &PeiCoreEntryPoint
+ );
+ if (EFI_ERROR (Status)) {
+ return ;
+ }
+
+ //
+ // Transfer control to the PEI Core
+ //
+ PeiSwitchStacks (
+ (SWITCH_STACK_ENTRY_POINT) (UINTN) PeiCoreEntryPoint,
+ SecCoreData,
+ (VOID *) (UINTN) ((EFI_PEI_PPI_DESCRIPTOR *) &gPrivateDispatchTable),
+ NULL,
+ TopOfStack
+ );
+ //
+ // If we get here, then the PEI Core returned. This is an error
+ //
+ return ;
+}
+
+EFI_STATUS
+EFIAPI
+SecWinNtPeiAutoScan (
+ IN UINTN Index,
+ OUT EFI_PHYSICAL_ADDRESS *MemoryBase,
+ OUT UINT64 *MemorySize
+ )
+/*++
+
+Routine Description:
+ This service is called from Index == 0 until it returns EFI_UNSUPPORTED.
+ It allows discontiguous memory regions to be supported by the emulator.
+ It uses gSystemMemory[] and gSystemMemoryCount that were created by
+ parsing the host environment variable EFI_MEMORY_SIZE.
+ The size comes from the varaible and the address comes from the call to
+ WinNtOpenFile.
+
+Arguments:
+ Index - Which memory region to use
+ MemoryBase - Return Base address of memory region
+ MemorySize - Return size in bytes of the memory region
+
+Returns:
+ EFI_SUCCESS - If memory region was mapped
+ EFI_UNSUPPORTED - If Index is not supported
+
+--*/
+{
+ void *res;
+
+ if (Index >= gSystemMemoryCount) {
+ return EFI_UNSUPPORTED;
+ }
+
+ *MemoryBase = 0;
+ res = MapMemory(0, gSystemMemory[Index].Size,
+ PROT_READ | PROT_WRITE | PROT_EXEC,
+ MAP_PRIVATE | MAP_ANONYMOUS);
+ if (res == MAP_FAILED)
+ return EFI_DEVICE_ERROR;
+ *MemorySize = gSystemMemory[Index].Size;
+ *MemoryBase = (UINTN)res;
+ gSystemMemory[Index].Memory = *MemoryBase;
+
+ return EFI_SUCCESS;
+}
+
+VOID *
+EFIAPI
+SecWinNtWinNtThunkAddress (
+ VOID
+ )
+/*++
+
+Routine Description:
+ Since the SEC is the only Unix program in stack it must export
+ an interface to do Win API calls. That's what the WinNtThunk address
+ is for. gWinNt is initailized in WinNtThunk.c.
+
+Arguments:
+ InterfaceSize - sizeof (EFI_WIN_NT_THUNK_PROTOCOL);
+ InterfaceBase - Address of the gWinNt global
+
+Returns:
+ EFI_SUCCESS - Data returned
+
+--*/
+{
+ return gUnix;
+}
+
+
+EFI_STATUS
+EFIAPI
+SecWinNtPeiLoadFile (
+ IN VOID *Pe32Data,
+ IN EFI_PHYSICAL_ADDRESS *ImageAddress,
+ IN UINT64 *ImageSize,
+ IN EFI_PHYSICAL_ADDRESS *EntryPoint
+ )
+/*++
+
+Routine Description:
+ Loads and relocates a PE/COFF image into memory.
+
+Arguments:
+ Pe32Data - The base address of the PE/COFF file that is to be loaded and relocated
+ ImageAddress - The base address of the relocated PE/COFF image
+ ImageSize - The size of the relocated PE/COFF image
+ EntryPoint - The entry point of the relocated PE/COFF image
+
+Returns:
+ EFI_SUCCESS - The file was loaded and relocated
+ EFI_OUT_OF_RESOURCES - There was not enough memory to load and relocate the PE/COFF file
+
+--*/
+{
+ EFI_STATUS Status;
+ PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;
+
+ ZeroMem (&ImageContext, sizeof (ImageContext));
+ ImageContext.Handle = Pe32Data;
+
+ ImageContext.ImageRead = (PE_COFF_LOADER_READ_FILE) SecImageRead;
+
+ Status = gPeiEfiPeiPeCoffLoader->GetImageInfo (gPeiEfiPeiPeCoffLoader, &ImageContext);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Allocate space in UNIX (not emulator) memory. Extra space is for alignment
+ //
+ ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS) (UINTN) malloc ((UINTN) (ImageContext.ImageSize + (ImageContext.SectionAlignment * 2)));
+ if (ImageContext.ImageAddress == 0) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ //
+ // Align buffer on section boundry
+ //
+ ImageContext.ImageAddress += ImageContext.SectionAlignment;
+ ImageContext.ImageAddress &= ~(ImageContext.SectionAlignment - 1);
+
+
+ Status = gPeiEfiPeiPeCoffLoader->LoadImage (gPeiEfiPeiPeCoffLoader, &ImageContext);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = gPeiEfiPeiPeCoffLoader->RelocateImage (gPeiEfiPeiPeCoffLoader, &ImageContext);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // BugBug: Flush Instruction Cache Here when CPU Lib is ready
+ //
+
+ *ImageAddress = ImageContext.ImageAddress;
+ *ImageSize = ImageContext.ImageSize;
+ *EntryPoint = ImageContext.EntryPoint;
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EFIAPI
+SecWinNtFdAddress (
+ IN UINTN Index,
+ IN OUT EFI_PHYSICAL_ADDRESS *FdBase,
+ IN OUT UINT64 *FdSize
+ )
+/*++
+
+Routine Description:
+ Return the FD Size and base address. Since the FD is loaded from a
+ file into host memory only the SEC will know it's address.
+
+Arguments:
+ Index - Which FD, starts at zero.
+ FdSize - Size of the FD in bytes
+ FdBase - Start address of the FD. Assume it points to an FV Header
+
+Returns:
+ EFI_SUCCESS - Return the Base address and size of the FV
+ EFI_UNSUPPORTED - Index does nto map to an FD in the system
+
+--*/
+{
+ if (Index >= gFdInfoCount) {
+ return EFI_UNSUPPORTED;
+ }
+
+ *FdBase = gFdInfo[Index].Address;
+ *FdSize = gFdInfo[Index].Size;
+
+ if (*FdBase == 0 && *FdSize == 0) {
+ return EFI_UNSUPPORTED;
+ }
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EFIAPI
+SecImageRead (
+ IN VOID *FileHandle,
+ IN UINTN FileOffset,
+ IN OUT UINTN *ReadSize,
+ OUT VOID *Buffer
+ )
+/*++
+
+Routine Description:
+ Support routine for the PE/COFF Loader that reads a buffer from a PE/COFF file
+
+Arguments:
+ FileHandle - The handle to the PE/COFF file
+ FileOffset - The offset, in bytes, into the file to read
+ ReadSize - The number of bytes to read from the file starting at FileOffset
+ Buffer - A pointer to the buffer to read the data into.
+
+Returns:
+ EFI_SUCCESS - ReadSize bytes of data were read into Buffer from the PE/COFF file starting at FileOffset
+
+--*/
+{
+ CHAR8 *Destination8;
+ CHAR8 *Source8;
+ UINTN Length;
+
+ Destination8 = Buffer;
+ Source8 = (CHAR8 *) ((UINTN) FileHandle + FileOffset);
+ Length = *ReadSize;
+ while (Length--) {
+ *(Destination8++) = *(Source8++);
+ }
+
+ return EFI_SUCCESS;
+}
+
+UINTN
+CountSeperatorsInString (
+ IN const CHAR16 *String,
+ IN CHAR16 Seperator
+ )
+/*++
+
+Routine Description:
+ Count the number of seperators in String
+
+Arguments:
+ String - String to process
+ Seperator - Item to count
+
+Returns:
+ Number of Seperator in String
+
+--*/
+{
+ UINTN Count;
+
+ for (Count = 0; *String != '\0'; String++) {
+ if (*String == Seperator) {
+ Count++;
+ }
+ }
+
+ return Count;
+}
+
+
+
+EFI_STATUS
+EFIAPI
+SecNt32PeCoffGetImageInfo (
+ IN EFI_PEI_PE_COFF_LOADER_PROTOCOL *This,
+ IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
+ )
+{
+ EFI_STATUS Status;
+
+ Status = PeCoffLoaderGetImageInfo (ImageContext);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ switch (ImageContext->ImageType) {
+
+ case EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION:
+ ImageContext->ImageCodeMemoryType = EfiLoaderCode;
+ ImageContext->ImageDataMemoryType = EfiLoaderData;
+ break;
+
+ case EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER:
+ ImageContext->ImageCodeMemoryType = EfiBootServicesCode;
+ ImageContext->ImageDataMemoryType = EfiBootServicesData;
+ break;
+
+ case EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER:
+ case EFI_IMAGE_SUBSYSTEM_SAL_RUNTIME_DRIVER:
+ ImageContext->ImageCodeMemoryType = EfiRuntimeServicesCode;
+ ImageContext->ImageDataMemoryType = EfiRuntimeServicesData;
+ break;
+
+ default:
+ ImageContext->ImageError = IMAGE_ERROR_INVALID_SUBSYSTEM;
+ return RETURN_UNSUPPORTED;
+ }
+
+ return Status;
+}
+
+EFI_STATUS
+EFIAPI
+SecNt32PeCoffLoadImage (
+ IN EFI_PEI_PE_COFF_LOADER_PROTOCOL *This,
+ IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
+ )
+{
+ EFI_STATUS Status;
+
+ Status = PeCoffLoaderLoadImage (ImageContext);
+ return Status;
+}
+
+VOID
+SecUnixLoaderBreak (
+ VOID
+ )
+{
+}
+
+EFI_STATUS
+EFIAPI
+SecNt32PeCoffRelocateImage (
+ IN EFI_PEI_PE_COFF_LOADER_PROTOCOL *This,
+ IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
+ )
+{
+ void * Handle;
+ void * Entry;
+ EFI_STATUS Status;
+
+ Handle = NULL;
+ Entry = NULL;
+ Status = PeCoffLoaderRelocateImage (ImageContext);
+ fprintf (stderr,
+ "Loading %s 0x%08lx - entry point 0x%08lx\n",
+ ImageContext->PdbPointer,
+ (unsigned long)ImageContext->ImageAddress,
+ (unsigned long)ImageContext->EntryPoint);
+
+ SecUnixLoaderBreak ();
+
+ return Status;
+}
+
+
+EFI_STATUS
+EFIAPI
+SecNt32PeCoffUnloadimage (
+ IN EFI_PEI_PE_COFF_LOADER_PROTOCOL *This,
+ IN PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
+ )
+{
+ return EFI_SUCCESS;
+}
+
+VOID
+ModuleEntryPoint (
+ VOID
+ )
+{
+}
+
+EFI_STATUS
+EFIAPI
+SecTemporaryRamSupport (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PHYSICAL_ADDRESS TemporaryMemoryBase,
+ IN EFI_PHYSICAL_ADDRESS PermanentMemoryBase,
+ IN UINTN CopySize
+ )
+{
+ //
+ // Migrate the whole temporary memory to permenent memory.
+ //
+ CopyMem (
+ (VOID*)(UINTN)PermanentMemoryBase,
+ (VOID*)(UINTN)TemporaryMemoryBase,
+ CopySize
+ );
+
+ //
+ // SecSwitchStack function must be invoked after the memory migration
+ // immediatly, also we need fixup the stack change caused by new call into
+ // permenent memory.
+ //
+ SecSwitchStack (
+ (UINT32) TemporaryMemoryBase,
+ (UINT32) PermanentMemoryBase
+ );
+
+ //
+ // We need *not* fix the return address because currently,
+ // The PeiCore is excuted in flash.
+ //
+
+ //
+ // Simulate to invalid CAR, terminate CAR
+ //
+ //ZeroMem ((VOID*)(UINTN)TemporaryMemoryBase, CopySize);
+
+ return EFI_SUCCESS;
+}
diff --git a/UnixPkg/Sec/SecMain.h b/UnixPkg/Sec/SecMain.h
new file mode 100644
index 0000000000..9714b5a4b9
--- /dev/null
+++ b/UnixPkg/Sec/SecMain.h
@@ -0,0 +1,548 @@
+/*++
+
+Copyright (c) 2006 - 2008, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+
+Module Name:
+ SecMain.h
+
+Abstract:
+ Include file for host API based SEC
+
+--*/
+#include "PiPei.h"
+#include "Uefi/UefiSpec.h"
+
+#include <Protocol/UnixThunk.h>
+#include <Pi/PiFirmwareVolume.h>
+#include <Guid/PeiPeCoffLoader.h>
+#include <Ppi/StatusCode.h>
+
+#include <Library/PeCoffLib.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/PrintLib.h>
+#include <Library/PcdLib.h>
+#include <Library/DebugLib.h>
+
+#define STACK_SIZE 0x20000
+
+typedef struct {
+ EFI_PHYSICAL_ADDRESS Address;
+ UINT64 Size;
+} UNIX_FD_INFO;
+
+typedef struct {
+ EFI_PHYSICAL_ADDRESS Memory;
+ UINT64 Size;
+} UNIX_SYSTEM_MEMORY;
+
+
+
+EFI_STATUS
+EFIAPI
+SecWinNtPeiLoadFile (
+ VOID *Pe32Data, // TODO: add IN/OUT modifier to Pe32Data
+ EFI_PHYSICAL_ADDRESS *ImageAddress, // TODO: add IN/OUT modifier to ImageAddress
+ UINT64 *ImageSize, // TODO: add IN/OUT modifier to ImageSize
+ EFI_PHYSICAL_ADDRESS *EntryPoint // TODO: add IN/OUT modifier to EntryPoint
+ )
+/*++
+
+Routine Description:
+
+ TODO: Add function description
+
+Arguments:
+
+ Pe32Data - TODO: add argument description
+ ImageAddress - TODO: add argument description
+ ImageSize - TODO: add argument description
+ EntryPoint - TODO: add argument description
+
+Returns:
+
+ TODO: add return values
+
+--*/
+;
+
+EFI_STATUS
+EFIAPI
+SecWinNtPeiAutoScan (
+ IN UINTN Index,
+ OUT EFI_PHYSICAL_ADDRESS *MemoryBase,
+ OUT UINT64 *MemorySize
+ )
+/*++
+
+Routine Description:
+
+ TODO: Add function description
+
+Arguments:
+
+ Index - TODO: add argument description
+ MemoryBase - TODO: add argument description
+ MemorySize - TODO: add argument description
+
+Returns:
+
+ TODO: add return values
+
+--*/
+;
+
+VOID *
+EFIAPI
+SecWinNtWinNtThunkAddress (
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ TODO: Add function description
+
+Arguments:
+
+ InterfaceSize - TODO: add argument description
+ InterfaceBase - TODO: add argument description
+
+Returns:
+
+ TODO: add return values
+
+--*/
+;
+
+EFI_STATUS
+EFIAPI
+SecWinNtWinNtFwhAddress (
+ IN OUT UINT64 *FwhSize,
+ IN OUT EFI_PHYSICAL_ADDRESS *FwhBase
+ )
+/*++
+
+Routine Description:
+
+ TODO: Add function description
+
+Arguments:
+
+ FwhSize - TODO: add argument description
+ FwhBase - TODO: add argument description
+
+Returns:
+
+ TODO: add return values
+
+--*/
+;
+
+EFI_STATUS
+EFIAPI
+SecPeiReportStatusCode (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_STATUS_CODE_TYPE CodeType,
+ IN EFI_STATUS_CODE_VALUE Value,
+ IN UINT32 Instance,
+ IN EFI_GUID * CallerId,
+ IN EFI_STATUS_CODE_DATA * Data OPTIONAL
+ )
+/*++
+
+Routine Description:
+
+ TODO: Add function description
+
+Arguments:
+
+ PeiServices - TODO: add argument description
+ CodeType - TODO: add argument description
+ Value - TODO: add argument description
+ Instance - TODO: add argument description
+ CallerId - TODO: add argument description
+ Data - TODO: add argument description
+
+Returns:
+
+ TODO: add return values
+
+--*/
+;
+
+INTN
+EFIAPI
+main (
+ IN INTN Argc,
+ IN CHAR8 **Argv,
+ IN CHAR8 **Envp
+ )
+/*++
+
+Routine Description:
+
+ TODO: Add function description
+
+Arguments:
+
+ Argc - TODO: add argument description
+ Argv - TODO: add argument description
+ Envp - TODO: add argument description
+
+Returns:
+
+ TODO: add return values
+
+--*/
+;
+
+VOID
+SecLoadFromCore (
+ IN UINTN LargestRegion,
+ IN UINTN LargestRegionSize,
+ IN UINTN BootFirmwareVolumeBase,
+ IN VOID *PeiCoreFile
+ )
+/*++
+
+Routine Description:
+
+ TODO: Add function description
+
+Arguments:
+
+ LargestRegion - TODO: add argument description
+ LargestRegionSize - TODO: add argument description
+ BootFirmwareVolumeBase - TODO: add argument description
+ PeiCoreFile - TODO: add argument description
+
+Returns:
+
+ TODO: add return values
+
+--*/
+;
+
+EFI_STATUS
+SecLoadFile (
+ IN VOID *Pe32Data,
+ IN EFI_PHYSICAL_ADDRESS *ImageAddress,
+ IN UINT64 *ImageSize,
+ IN EFI_PHYSICAL_ADDRESS *EntryPoint
+ )
+/*++
+
+Routine Description:
+
+ TODO: Add function description
+
+Arguments:
+
+ Pe32Data - TODO: add argument description
+ ImageAddress - TODO: add argument description
+ ImageSize - TODO: add argument description
+ EntryPoint - TODO: add argument description
+
+Returns:
+
+ TODO: add return values
+
+--*/
+;
+
+EFI_STATUS
+SecFfsFindPeiCore (
+ IN EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader,
+ OUT VOID **Pe32Data
+ )
+/*++
+
+Routine Description:
+
+ TODO: Add function description
+
+Arguments:
+
+ FwVolHeader - TODO: add argument description
+ Pe32Data - TODO: add argument description
+
+Returns:
+
+ TODO: add return values
+
+--*/
+;
+
+EFI_STATUS
+SecFfsFindNextFile (
+ IN EFI_FV_FILETYPE SearchType,
+ IN EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader,
+ IN OUT EFI_FFS_FILE_HEADER **FileHeader
+ )
+/*++
+
+Routine Description:
+
+ TODO: Add function description
+
+Arguments:
+
+ SearchType - TODO: add argument description
+ FwVolHeader - TODO: add argument description
+ FileHeader - TODO: add argument description
+
+Returns:
+
+ TODO: add return values
+
+--*/
+;
+
+EFI_STATUS
+SecFfsFindSectionData (
+ IN EFI_SECTION_TYPE SectionType,
+ IN EFI_FFS_FILE_HEADER *FfsFileHeader,
+ IN OUT VOID **SectionData
+ )
+/*++
+
+Routine Description:
+
+ TODO: Add function description
+
+Arguments:
+
+ SectionType - TODO: add argument description
+ FfsFileHeader - TODO: add argument description
+ SectionData - TODO: add argument description
+
+Returns:
+
+ TODO: add return values
+
+--*/
+;
+
+EFI_STATUS
+EFIAPI
+SecWinNtPeCoffLoaderLoadAsDll (
+ IN CHAR8 *PdbFileName,
+ IN VOID **ImageEntryPoint,
+ OUT VOID **ModHandle
+ )
+/*++
+
+Routine Description:
+
+ TODO: Add function description
+
+Arguments:
+
+ PdbFileName - TODO: add argument description
+ ImageEntryPoint - TODO: add argument description
+ ModHandle - TODO: add argument description
+
+Returns:
+
+ TODO: add return values
+
+--*/
+;
+
+EFI_STATUS
+EFIAPI
+SecWinNtPeCoffLoaderFreeLibrary (
+ OUT VOID *ModHandle
+ )
+/*++
+
+Routine Description:
+
+ TODO: Add function description
+
+Arguments:
+
+ ModHandle - TODO: add argument description
+
+Returns:
+
+ TODO: add return values
+
+--*/
+;
+
+EFI_STATUS
+EFIAPI
+SecWinNtFdAddress (
+ IN UINTN Index,
+ IN OUT EFI_PHYSICAL_ADDRESS *FdBase,
+ IN OUT UINT64 *FdSize
+ )
+/*++
+
+Routine Description:
+
+ TODO: Add function description
+
+Arguments:
+
+ Index - TODO: add argument description
+ FdBase - TODO: add argument description
+ FdSize - TODO: add argument description
+
+Returns:
+
+ TODO: add return values
+
+--*/
+;
+
+EFI_STATUS
+GetImageReadFunction (
+ IN PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext,
+ IN EFI_PHYSICAL_ADDRESS *TopOfMemory
+ )
+/*++
+
+Routine Description:
+
+ TODO: Add function description
+
+Arguments:
+
+ ImageContext - TODO: add argument description
+ TopOfMemory - TODO: add argument description
+
+Returns:
+
+ TODO: add return values
+
+--*/
+;
+
+EFI_STATUS
+EFIAPI
+SecImageRead (
+ IN VOID *FileHandle,
+ IN UINTN FileOffset,
+ IN OUT UINTN *ReadSize,
+ OUT VOID *Buffer
+ )
+/*++
+
+Routine Description:
+
+ TODO: Add function description
+
+Arguments:
+
+ FileHandle - TODO: add argument description
+ FileOffset - TODO: add argument description
+ ReadSize - TODO: add argument description
+ Buffer - TODO: add argument description
+
+Returns:
+
+ TODO: add return values
+
+--*/
+;
+
+CHAR16 *
+AsciiToUnicode (
+ IN CHAR8 *Ascii,
+ IN UINTN *StrLen OPTIONAL
+ )
+/*++
+
+Routine Description:
+
+ TODO: Add function description
+
+Arguments:
+
+ Ascii - TODO: add argument description
+ StrLen - TODO: add argument description
+
+Returns:
+
+ TODO: add return values
+
+--*/
+;
+
+UINTN
+CountSeperatorsInString (
+ IN const CHAR16 *String,
+ IN CHAR16 Seperator
+ )
+/*++
+
+Routine Description:
+
+ TODO: Add function description
+
+Arguments:
+
+ String - TODO: add argument description
+ Seperator - TODO: add argument description
+
+Returns:
+
+ TODO: add return values
+
+--*/
+;
+
+EFI_STATUS
+EFIAPI
+SecNt32PeCoffGetImageInfo (
+ IN EFI_PEI_PE_COFF_LOADER_PROTOCOL *This,
+ IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
+ );
+
+EFI_STATUS
+EFIAPI
+SecNt32PeCoffLoadImage (
+ IN EFI_PEI_PE_COFF_LOADER_PROTOCOL *This,
+ IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
+ );
+
+EFI_STATUS
+EFIAPI
+SecNt32PeCoffRelocateImage (
+ IN EFI_PEI_PE_COFF_LOADER_PROTOCOL *This,
+ IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
+ );
+
+EFI_STATUS
+EFIAPI
+SecNt32PeCoffUnloadimage (
+ IN EFI_PEI_PE_COFF_LOADER_PROTOCOL *This,
+ IN PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
+ );
+
+EFI_STATUS
+EFIAPI
+SecTemporaryRamSupport (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PHYSICAL_ADDRESS TemporaryMemoryBase,
+ IN EFI_PHYSICAL_ADDRESS PermanentMemoryBase,
+ IN UINTN CopySize
+ );
+
+typedef struct {
+ EFI_PEI_PE_COFF_LOADER_PROTOCOL PeCoff;
+ VOID *ModHandle;
+} EFI_PEI_PE_COFF_LOADER_PROTOCOL_INSTANCE;
+
+extern EFI_UNIX_THUNK_PROTOCOL *gUnix;
diff --git a/UnixPkg/Sec/SecMain.inf b/UnixPkg/Sec/SecMain.inf
new file mode 100644
index 0000000000..37152b08e7
--- /dev/null
+++ b/UnixPkg/Sec/SecMain.inf
@@ -0,0 +1,76 @@
+#/** @file
+# Entry Point of Unix Emulator
+#
+# Main executable file of Unix Emulator that loads PEI core after initialization finished.
+# Copyright (c) 2008, Intel Corporation
+#
+# All rights reserved. This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+#
+#**/
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = SecMain
+ FILE_GUID = f43be88c-8985-11db-8f78-0040d02b1835
+ MODULE_TYPE = SEC
+ VERSION_STRING = 1.0
+ EDK_RELEASE_VERSION = 0x00020000
+ EFI_SPECIFICATION_VERSION = 0x00020000
+ ENTRY_POINT = main
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+
+[Sources.common]
+ UgaX11.c
+ UnixThunk.c
+ FwVol.c
+ SecMain.c
+ Stack.S
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ IntelFrameworkPkg/IntelFrameworkPkg.dec
+ UnixPkg/UnixPkg.dec
+
+[LibraryClasses]
+ DebugLib
+ PcdLib
+ PrintLib
+ BaseMemoryLib
+ BaseLib
+ PeCoffLib
+ ReportStatusCodeLib
+
+
+[Guids]
+ gEfiPeiPeCoffLoaderGuid # ALWAYS_PRODUCED
+
+
+[Ppis]
+ gUnixPeiLoadFilePpiGuid # PPI ALWAYS_PRODUCED
+ gEfiPeiStatusCodePpiGuid # PPI ALWAYS_PRODUCED
+ gUnixFwhPpiGuid # PPI ALWAYS_PRODUCED
+ gPeiUnixAutoScanPpiGuid # PPI ALWAYS_PRODUCED
+ gPeiUnixThunkPpiGuid # PPI ALWAYS_PRODUCED
+ gEfiTemporaryRamSupportPpiGuid
+
+
+[Pcd.common]
+ gEfiUnixPkgTokenSpaceGuid.PcdUnixBootMode
+ gEfiUnixPkgTokenSpaceGuid.PcdUnixFirmwareVolume
+ gEfiUnixPkgTokenSpaceGuid.PcdUnixMemorySizeForSecMain
+ gEfiUnixPkgTokenSpaceGuid.PcdUnixFirmwareFdSize
+
+[BuildOptions.common]
+ GCC:*_*_IA32_DLINK_FLAGS =
diff --git a/UnixPkg/Sec/SecMain.msa b/UnixPkg/Sec/SecMain.msa
new file mode 100644
index 0000000000..2629982571
--- /dev/null
+++ b/UnixPkg/Sec/SecMain.msa
@@ -0,0 +1,113 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ModuleSurfaceArea xmlns="http://www.TianoCore.org/2006/Edk2.0">
+ <MsaHeader>
+ <ModuleName>SecMain</ModuleName>
+ <ModuleType>SEC</ModuleType>
+ <GuidValue>f43be88c-8985-11db-8f78-0040d02b1835</GuidValue>
+ <Version>1.0</Version>
+ <Abstract>Entry Point of Unix Emulator</Abstract>
+ <Description>Main executable file of Unix Emulator that loads PEI core after initialization finished.</Description>
+ <Copyright>Copyright (c) 2006, Intel Corporation</Copyright>
+ <License>All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.</License>
+ <Specification>FRAMEWORK_BUILD_PACKAGING_SPECIFICATION 0x00000052</Specification>
+ </MsaHeader>
+ <ModuleDefinitions>
+ <SupportedArchitectures>IA32 X64 IPF EBC</SupportedArchitectures>
+ <BinaryModule>false</BinaryModule>
+ <OutputFileBasename>SecMain</OutputFileBasename>
+ </ModuleDefinitions>
+ <LibraryClassDefinitions>
+ <LibraryClass Usage="ALWAYS_CONSUMED">
+ <Keyword>PeCoffLib</Keyword>
+ </LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">
+ <Keyword>BaseLib</Keyword>
+ </LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">
+ <Keyword>BaseMemoryLib</Keyword>
+ </LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">
+ <Keyword>PrintLib</Keyword>
+ </LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">
+ <Keyword>PcdLib</Keyword>
+ </LibraryClass>
+ <LibraryClass Usage="ALWAYS_CONSUMED">
+ <Keyword>DebugLib</Keyword>
+ </LibraryClass>
+ </LibraryClassDefinitions>
+ <SourceFiles>
+ <Filename ToolCode="DUMMY">SecMain_build.xml</Filename>
+ <Filename>SecMain.c</Filename>
+ <Filename>FwVol.c</Filename>
+ <Filename>UnixThunk.c</Filename>
+ <Filename>UgaX11.c</Filename>
+ <Filename>SecMain.h</Filename>
+ </SourceFiles>
+ <PackageDependencies>
+ <Package PackageGuid="5e0e9358-46b6-4ae2-8218-4ab8b9bbdcec"/>
+ <Package PackageGuid="68169ab0-d41b-4009-9060-292c253ac43d"/>
+ <Package PackageGuid="f2805c44-8985-11db-9e98-0040d02b1835"/>
+ </PackageDependencies>
+ <PPIs>
+ <Ppi Usage="ALWAYS_PRODUCED">
+ <PpiCName>gPeiUnixThunkPpiGuid</PpiCName>
+ </Ppi>
+ <Ppi Usage="ALWAYS_PRODUCED">
+ <PpiCName>gPeiUnixAutoScanPpiGuid</PpiCName>
+ </Ppi>
+ <Ppi Usage="ALWAYS_PRODUCED">
+ <PpiCName>gUnixFwhPpiGuid</PpiCName>
+ </Ppi>
+ <Ppi Usage="ALWAYS_PRODUCED">
+ <PpiCName>gEfiPeiStatusCodePpiGuid</PpiCName>
+ </Ppi>
+ <Ppi Usage="ALWAYS_PRODUCED">
+ <PpiCName>gUnixPeiLoadFilePpiGuid</PpiCName>
+ </Ppi>
+ </PPIs>
+ <Guids>
+ <GuidCNames Usage="ALWAYS_PRODUCED">
+ <GuidCName>gEfiPeiPeCoffLoaderGuid</GuidCName>
+ </GuidCNames>
+ </Guids>
+ <Externs>
+ <Specification>EFI_SPECIFICATION_VERSION 0x00020000</Specification>
+ <Specification>EDK_RELEASE_VERSION 0x00020000</Specification>
+ </Externs>
+ <PcdCoded>
+ <PcdEntry PcdItemType="DYNAMIC">
+ <C_Name>PcdUnixMemorySizeForSecMain</C_Name>
+ <TokenSpaceGuidCName>gEfiEdkUnixPkgTokenSpaceGuid</TokenSpaceGuidCName>
+ <HelpText>This PCD defines the memory size of simulated machine. Simulator will allocate
+ the size of PcdUnixMemorySizeForSecMain in host platform.</HelpText>
+ </PcdEntry>
+ <PcdEntry PcdItemType="DYNAMIC">
+ <C_Name>PcdUnixFirmwareVolume</C_Name>
+ <TokenSpaceGuidCName>gEfiEdkUnixPkgTokenSpaceGuid</TokenSpaceGuidCName>
+ <HelpText>This PCD defines the FD file windows path string. Simulator will load the FD file and execute.</HelpText>
+ </PcdEntry>
+ <PcdEntry PcdItemType="DYNAMIC">
+ <C_Name>PcdUnixBootMode</C_Name>
+ <TokenSpaceGuidCName>gEfiEdkUnixPkgTokenSpaceGuid</TokenSpaceGuidCName>
+ <HelpText>This PCD defines the boot mode for simualtor.
+ The boot mode can be set as following value:
+ 0x0: Boot with full configuration.
+ 0x1: Boot with minimal configuration.
+ 0x2: Boot assume no configuration changes.
+ 0x3: Boot with full configuration plus diagnostics.
+ 0x4: Boot with default settings.
+ 0x5: Boot on S4 resume.
+ 0x6: Boot on S5 resume.
+ 0x10: Boot on S2 resume.
+ 0x11: Boot on S3 resume.
+ 0x12: Boot on flash update.
+ 0x20: Boot in reovery mode.</HelpText>
+ </PcdEntry>
+ </PcdCoded>
+</ModuleSurfaceArea>
diff --git a/UnixPkg/Sec/Stack.S b/UnixPkg/Sec/Stack.S
new file mode 100644
index 0000000000..50f07b0894
--- /dev/null
+++ b/UnixPkg/Sec/Stack.S
@@ -0,0 +1,92 @@
+#------------------------------------------------------------------------------
+#
+# Copyright (c) 2008, Intel Corporation
+# All rights reserved. This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+# Module Name:
+#
+# Stack.asm
+#
+# Abstract:
+#
+# Switch the stack from temporary memory to permenent memory.
+#
+#------------------------------------------------------------------------------
+
+#------------------------------------------------------------------------------
+# VOID
+# EFIAPI
+# SecSwitchStack (
+# UINT32 TemporaryMemoryBase,
+# UINT32 PermenentMemoryBase
+# );
+#------------------------------------------------------------------------------
+
+#include <ProcessorBind.h>
+
+.globl ASM_PFX(SecSwitchStack)
+ASM_PFX(SecSwitchStack):
+#
+# Save three register: eax, ebx, ecx
+#
+ push %eax
+ push %ebx
+ push %ecx
+ push %edx
+
+#
+# !!CAUTION!! this function address's is pushed into stack after
+# migration of whole temporary memory, so need save it to permenent
+# memory at first!
+#
+
+ movl 20(%esp), %ebx # Save the first parameter
+ movl 24(%esp), %ecx # Save the second parameter
+
+#
+# Save this function's return address into permenent memory at first.
+# Then, Fixup the esp point to permenent memory
+#
+
+ movl %esp, %eax
+ subl %ebx, %eax
+ addl %ecx, %eax
+ movl (%esp), %edx # copy pushed register's value to permenent memory
+ movl %edx, (%eax)
+ movl 4(%esp), %edx
+ movl %edx, 4(%eax)
+ movl 8(%esp), %edx
+ movl %edx, 8(%eax)
+ movl 12(%esp), %edx
+ movl %edx, 12(%eax)
+ movl 16(%esp), %edx
+ movl %edx, 16(%eax)
+ movl %eax, %esp # From now, esp is pointed to permenent memory
+
+#
+# Fixup the ebp point to permenent memory
+#
+ movl %ebp, %eax
+ subl %ebx, %eax
+ addl %ecx, %eax
+ movl %eax, %ebp # From now, ebp is pointed to permenent memory
+
+#
+# Fixup callee's ebp point for PeiDispatch
+#
+ movl (%ebp), %eax
+ subl %ebx, %eax
+ addl %ecx, %eax
+ movl %eax, (%ebp) # From now, Temporary's PPI caller's stack is in permenent memory
+
+ pop %edx
+ pop %ecx
+ pop %ebx
+ pop %eax
+ ret
diff --git a/UnixPkg/Sec/UgaX11.c b/UnixPkg/Sec/UgaX11.c
new file mode 100644
index 0000000000..b096dc660d
--- /dev/null
+++ b/UnixPkg/Sec/UgaX11.c
@@ -0,0 +1,595 @@
+#include <sys/ipc.h>
+#include <sys/shm.h>
+#include <sys/dir.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "PiPei.h"
+#include "Protocol/UnixThunk.h"
+#include "Protocol/SimpleTextIn.h"
+#include "Protocol/UgaDraw.h"
+#include "Protocol/UnixUgaIo.h"
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/Xos.h>
+#include <X11/extensions/XShm.h>
+#include <X11/keysym.h>
+
+#include <Guid/PeiPeCoffLoader.h>
+#include <Ppi/StatusCode.h>
+
+#include <Library/PeCoffLib.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/PrintLib.h>
+#include <Library/PcdLib.h>
+#include <Library/DebugLib.h>
+
+extern void msSleep (unsigned long Milliseconds);
+
+/* XQueryPointer */
+
+struct uga_drv_shift_mask
+{
+ unsigned char shift;
+ unsigned char size;
+ unsigned char csize;
+};
+
+#define NBR_KEYS 32
+typedef struct
+{
+ EFI_UNIX_UGA_IO_PROTOCOL UgaIo;
+
+ Display *display;
+ int screen; /* values for window_size in main */
+ Window win;
+ GC gc;
+ Visual *visual;
+
+ int depth;
+ unsigned int width;
+ unsigned int height;
+ unsigned int line_bytes;
+ unsigned int pixel_shift;
+ unsigned char *image_data;
+
+ struct uga_drv_shift_mask r, g, b;
+
+ int use_shm;
+ XShmSegmentInfo xshm_info;
+ XImage *image;
+
+ unsigned int key_rd;
+ unsigned int key_wr;
+ unsigned int key_count;
+ EFI_INPUT_KEY keys[NBR_KEYS];
+} UGA_IO_PRIVATE;
+
+static void
+HandleEvents(UGA_IO_PRIVATE *drv);
+
+static void
+fill_shift_mask (struct uga_drv_shift_mask *sm, unsigned long mask)
+{
+ sm->shift = 0;
+ sm->size = 0;
+ while ((mask & 1) == 0)
+ {
+ mask >>= 1;
+ sm->shift++;
+ }
+ while (mask & 1)
+ {
+ sm->size++;
+ mask >>= 1;
+ }
+ sm->csize = 8 - sm->size;
+}
+
+static int
+TryCreateShmImage(UGA_IO_PRIVATE *drv)
+{
+ drv->image = XShmCreateImage (drv->display, drv->visual,
+ drv->depth, ZPixmap, NULL, &drv->xshm_info,
+ drv->width, drv->height);
+ if (drv->image == NULL)
+ return 0;
+
+ switch (drv->image->bitmap_unit) {
+ case 32:
+ drv->pixel_shift = 2;
+ break;
+ case 16:
+ drv->pixel_shift = 1;
+ break;
+ case 8:
+ drv->pixel_shift = 0;
+ break;
+ }
+
+ drv->xshm_info.shmid = shmget
+ (IPC_PRIVATE, drv->image->bytes_per_line * drv->image->height,
+ IPC_CREAT | 0777);
+ if (drv->xshm_info.shmid < 0)
+ {
+ XDestroyImage(drv->image);
+ return 0;
+ }
+
+ drv->image_data = shmat (drv->xshm_info.shmid, NULL, 0);
+ if(!drv->image_data)
+ {
+ shmctl (drv->xshm_info.shmid, IPC_RMID, NULL);
+ XDestroyImage(drv->image);
+ return 0;
+ }
+ /* Can this fail ? */
+ shmctl (drv->xshm_info.shmid, IPC_RMID, NULL);
+
+ drv->xshm_info.shmaddr = (char*)drv->image_data;
+ drv->image->data = (char*)drv->image_data;
+
+ if (!XShmAttach (drv->display, &drv->xshm_info))
+ {
+ shmdt (drv->image_data);
+ XDestroyImage(drv->image);
+ return 0;
+ }
+ return 1;
+}
+
+static
+EFI_STATUS
+UgaClose (EFI_UNIX_UGA_IO_PROTOCOL *UgaIo)
+{
+ UGA_IO_PRIVATE *drv = (UGA_IO_PRIVATE *)UgaIo;
+
+ if (drv == NULL)
+ return EFI_SUCCESS;
+ if (drv->image != NULL)
+ {
+ XDestroyImage(drv->image);
+
+ if (drv->use_shm)
+ shmdt (drv->image_data);
+
+ drv->image_data = NULL;
+ drv->image = NULL;
+ }
+ XDestroyWindow(drv->display, drv->win);
+ XCloseDisplay(drv->display);
+ free(drv);
+ return EFI_SUCCESS;
+}
+
+static
+EFI_STATUS
+UgaSize(EFI_UNIX_UGA_IO_PROTOCOL *UgaIo, UINT32 Width, UINT32 Height)
+{
+ UGA_IO_PRIVATE *drv = (UGA_IO_PRIVATE *)UgaIo;
+ XSizeHints size_hints;
+
+ /* Destroy current buffer if created. */
+ if (drv->image != NULL)
+ {
+ XDestroyImage(drv->image);
+
+ if (drv->use_shm)
+ shmdt (drv->image_data);
+
+ drv->image_data = NULL;
+ drv->image = NULL;
+ }
+
+ drv->width = Width;
+ drv->height = Height;
+ XResizeWindow (drv->display, drv->win, Width, Height);
+
+ /* Allocate image. */
+ if (XShmQueryExtension(drv->display) && TryCreateShmImage(drv))
+ {
+ drv->use_shm = 1;
+ }
+ else
+ {
+ drv->use_shm = 0;
+ if (drv->depth > 16)
+ drv->pixel_shift = 2;
+ else if (drv->depth > 8)
+ drv->pixel_shift = 1;
+ else
+ drv->pixel_shift = 0;
+
+ drv->image_data = malloc((drv->width * drv->height) << drv->pixel_shift);
+ drv->image = XCreateImage (drv->display, drv->visual, drv->depth,
+ ZPixmap, 0, (char *)drv->image_data,
+ drv->width, drv->height,
+ 8 << drv->pixel_shift, 0);
+ }
+ drv->line_bytes = drv->image->bytes_per_line;
+ fill_shift_mask (&drv->r, drv->image->red_mask);
+ fill_shift_mask (&drv->g, drv->image->green_mask);
+ fill_shift_mask (&drv->b, drv->image->blue_mask);
+
+ /* Set WM hints. */
+ size_hints.flags = PSize | PMinSize | PMaxSize;
+ size_hints.min_width = size_hints.max_width = size_hints.base_width = Width;
+ size_hints.min_height = size_hints.max_height = size_hints.base_height = Height;
+ XSetWMNormalHints (drv->display, drv->win, &size_hints);
+
+ XMapWindow (drv->display, drv->win);
+ HandleEvents(drv);
+ return EFI_SUCCESS;
+}
+
+static void
+handleKeyEvent(UGA_IO_PRIVATE *drv, XEvent *ev)
+{
+ KeySym keysym;
+ char str[4];
+ EFI_INPUT_KEY Key;
+ int res;
+
+ if (drv->key_count == NBR_KEYS)
+ return;
+
+ res = XLookupString(&ev->xkey, str, sizeof(str), &keysym, NULL);
+ Key.ScanCode = 0;
+ Key.UnicodeChar = 0;
+ switch (keysym) {
+ case XK_Home: Key.ScanCode = SCAN_HOME; break;
+ case XK_End: Key.ScanCode = SCAN_END; break;
+ case XK_Left: Key.ScanCode = SCAN_LEFT; break;
+ case XK_Right: Key.ScanCode = SCAN_RIGHT; break;
+ case XK_Up: Key.ScanCode = SCAN_UP; break;
+ case XK_Down: Key.ScanCode = SCAN_DOWN; break;
+ case XK_Delete: Key.ScanCode = SCAN_DELETE; break;
+ case XK_Insert: Key.ScanCode = SCAN_INSERT; break;
+ case XK_Page_Up: Key.ScanCode = SCAN_PAGE_UP; break;
+ case XK_Page_Down: Key.ScanCode = SCAN_PAGE_DOWN; break;
+ case XK_Escape: Key.ScanCode = SCAN_ESC; break;
+
+ case XK_F1: Key.ScanCode = SCAN_F1; break;
+ case XK_F2: Key.ScanCode = SCAN_F2; break;
+ case XK_F3: Key.ScanCode = SCAN_F3; break;
+ case XK_F4: Key.ScanCode = SCAN_F4; break;
+ case XK_F5: Key.ScanCode = SCAN_F5; break;
+ case XK_F6: Key.ScanCode = SCAN_F6; break;
+ case XK_F7: Key.ScanCode = SCAN_F7; break;
+ case XK_F8: Key.ScanCode = SCAN_F8; break;
+ case XK_F9: Key.ScanCode = SCAN_F9; break;
+
+ default:
+ if (res == 1) {
+ Key.UnicodeChar = str[0];
+ } else {
+ return;
+ }
+ }
+
+ drv->keys[drv->key_wr] = Key;
+ drv->key_wr = (drv->key_wr + 1) % NBR_KEYS;
+ drv->key_count++;
+}
+
+static void
+Redraw(UGA_IO_PRIVATE *drv, UINTN X, UINTN Y, UINTN Width, UINTN Height)
+{
+ if (drv->use_shm)
+ XShmPutImage (drv->display, drv->win, drv->gc, drv->image,
+ X, Y, X, Y, Width, Height, False);
+ else
+ XPutImage (drv->display, drv->win, drv->gc, drv->image,
+ X, Y, X, Y, Width, Height);
+}
+
+static void
+HandleEvent(UGA_IO_PRIVATE *drv, XEvent *ev)
+{
+ switch (ev->type)
+ {
+ case Expose:
+ Redraw(drv, ev->xexpose.x, ev->xexpose.y,
+ ev->xexpose.width, ev->xexpose.height);
+ break;
+ case GraphicsExpose:
+ Redraw(drv, ev->xgraphicsexpose.x, ev->xgraphicsexpose.y,
+ ev->xgraphicsexpose.width, ev->xgraphicsexpose.height);
+ break;
+ case KeyPress:
+ handleKeyEvent(drv, ev);
+ break;
+ case MappingNotify:
+ XRefreshKeyboardMapping(&ev->xmapping);
+ break;
+#if 0
+ case DestroyNotify:
+ XCloseDisplay (drv->display);
+ exit (1);
+ break;
+#endif
+ case NoExpose:
+ default:
+ break;
+ }
+}
+
+static void
+HandleEvents(UGA_IO_PRIVATE *drv)
+{
+ while (XPending(drv->display) != 0)
+ {
+ XEvent ev;
+
+ XNextEvent (drv->display, &ev);
+ HandleEvent(drv, &ev);
+ }
+}
+
+static
+unsigned long
+UgaPixelToColor (UGA_IO_PRIVATE *drv, EFI_UGA_PIXEL pixel)
+{
+ return ((pixel.Red >> drv->r.csize) << drv->r.shift)
+ | ((pixel.Green >> drv->g.csize) << drv->g.shift)
+ | ((pixel.Blue >> drv->b.csize) << drv->b.shift);
+}
+
+static
+EFI_UGA_PIXEL
+UgaColorToPixel (UGA_IO_PRIVATE *drv, unsigned long val)
+{
+ EFI_UGA_PIXEL res;
+
+ memset (&res, 0, sizeof (EFI_UGA_PIXEL));
+ /* FIXME: should round instead of truncate. */
+ res.Red = (val >> drv->r.shift) << drv->r.csize;
+ res.Green = (val >> drv->g.shift) << drv->g.csize;
+ res.Blue = (val >> drv->b.shift) << drv->b.csize;
+
+ return res;
+}
+
+static
+EFI_STATUS
+UgaCheckKey(EFI_UNIX_UGA_IO_PROTOCOL *UgaIo)
+{
+ UGA_IO_PRIVATE *drv = (UGA_IO_PRIVATE *)UgaIo;
+ HandleEvents(drv);
+ if (drv->key_count != 0)
+ return EFI_SUCCESS;
+ else {
+ /* EFI is certainly polling. Be CPU-friendly. */
+ msSleep (20);
+ return EFI_NOT_READY;
+ }
+}
+
+static
+EFI_STATUS
+UgaGetKey(EFI_UNIX_UGA_IO_PROTOCOL *UgaIo, EFI_INPUT_KEY *key)
+{
+ UGA_IO_PRIVATE *drv = (UGA_IO_PRIVATE *)UgaIo;
+ EFI_STATUS status;
+
+ status = UgaCheckKey(UgaIo);
+ if (status != EFI_SUCCESS)
+ return status;
+
+ *key = drv->keys[drv->key_rd];
+ drv->key_rd = (drv->key_rd + 1) % NBR_KEYS;
+ drv->key_count--;
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+UgaBlt(EFI_UNIX_UGA_IO_PROTOCOL *UgaIo,
+ IN EFI_UGA_PIXEL *BltBuffer OPTIONAL,
+ IN EFI_UGA_BLT_OPERATION BltOperation,
+ IN UINTN SourceX,
+ IN UINTN SourceY,
+ IN UINTN DestinationX,
+ IN UINTN DestinationY,
+ IN UINTN Width,
+ IN UINTN Height,
+ IN UINTN Delta OPTIONAL
+ )
+{
+ UGA_IO_PRIVATE *Private = (UGA_IO_PRIVATE *)UgaIo;
+ UINTN DstY;
+ UINTN SrcY;
+ UINTN DstX;
+ UINTN SrcX;
+ UINTN Index;
+ EFI_UGA_PIXEL *Blt;
+ UINT8 *Dst;
+ UINT8 *Src;
+ UINTN Nbr;
+ unsigned long Color;
+
+ //
+ // Check bounds
+ //
+ if (BltOperation == EfiUgaVideoToBltBuffer
+ || BltOperation == EfiUgaVideoToVideo) {
+ //
+ // Source is Video.
+ //
+ if (SourceY + Height > Private->height) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (SourceX + Width > Private->width) {
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+
+ if (BltOperation == EfiUgaBltBufferToVideo
+ || BltOperation == EfiUgaVideoToVideo
+ || BltOperation == EfiUgaVideoFill) {
+ //
+ // Destination is Video
+ //
+ if (DestinationY + Height > Private->height) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (DestinationX + Width > Private->width) {
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+
+ switch (BltOperation) {
+ case EfiUgaVideoToBltBuffer:
+ Blt = BltBuffer;
+ Delta -= Width * sizeof (EFI_UGA_PIXEL);
+ for (SrcY = SourceY; SrcY < (Height + SourceY); SrcY++) {
+ for (SrcX = SourceX; SrcX < (Width + SourceX); SrcX++) {
+ *Blt++ = UgaColorToPixel(Private,
+ XGetPixel(Private->image, SrcX, SrcY));
+ }
+ Blt = (EFI_UGA_PIXEL *) ((UINT8 *) Blt + Delta);
+ }
+ break;
+ case EfiUgaBltBufferToVideo:
+ Blt = BltBuffer;
+ Delta -= Width * sizeof (EFI_UGA_PIXEL);
+ for (DstY = DestinationY; DstY < (Height + DestinationY); DstY++) {
+ for (DstX = DestinationX; DstX < (Width + DestinationX); DstX++) {
+ XPutPixel(Private->image, DstX, DstY, UgaPixelToColor(Private, *Blt));
+ Blt++;
+ }
+ Blt = (EFI_UGA_PIXEL *) ((UINT8 *) Blt + Delta);
+ }
+ break;
+ case EfiUgaVideoToVideo:
+ Dst = Private->image_data + (DestinationX << Private->pixel_shift)
+ + DestinationY * Private->line_bytes;
+ Src = Private->image_data + (SourceX << Private->pixel_shift)
+ + SourceY * Private->line_bytes;
+ Nbr = Width << Private->pixel_shift;
+ if (DestinationY < SourceY) {
+ for (Index = 0; Index < Height; Index++) {
+ memcpy (Dst, Src, Nbr);
+ Dst += Private->line_bytes;
+ Src += Private->line_bytes;
+ }
+ }
+ else {
+ Dst += (Height - 1) * Private->line_bytes;
+ Src += (Height - 1) * Private->line_bytes;
+ for (Index = 0; Index < Height; Index++) {
+ //
+ // Source and Destination Y may be equal, therefore Dst and Src may
+ // overlap.
+ //
+ memmove (Dst, Src, Nbr);
+ Dst -= Private->line_bytes;
+ Src -= Private->line_bytes;
+ }
+ }
+ break;
+ case EfiUgaVideoFill:
+ Color = UgaPixelToColor(Private, *BltBuffer);
+ for (DstY = DestinationY; DstY < (Height + DestinationY); DstY++) {
+ for (DstX = DestinationX; DstX < (Width + DestinationX); DstX++) {
+ XPutPixel(Private->image, DstX, DstY, Color);
+ }
+ }
+ break;
+ default:
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Refresh screen.
+ //
+ switch (BltOperation) {
+ case EfiUgaVideoToVideo:
+ XCopyArea(Private->display, Private->win, Private->win, Private->gc,
+ SourceX, SourceY, Width, Height, DestinationX, DestinationY);
+ while (1) {
+ XEvent ev;
+
+ XNextEvent (Private->display, &ev);
+ HandleEvent(Private, &ev);
+ if (ev.type == NoExpose || ev.type == GraphicsExpose)
+ break;
+ }
+ break;
+ case EfiUgaVideoFill:
+ Color = UgaPixelToColor(Private, *BltBuffer);
+ XSetForeground(Private->display, Private->gc, Color);
+ XFillRectangle(Private->display, Private->win, Private->gc,
+ DestinationX, DestinationY, Width, Height);
+ break;
+ case EfiUgaBltBufferToVideo:
+ Redraw(Private, DestinationX, DestinationY, Width, Height);
+ break;
+ default:
+ break;
+ }
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+UgaCreate (EFI_UNIX_UGA_IO_PROTOCOL **Uga, CONST CHAR16 *Title)
+{
+ UGA_IO_PRIVATE *drv;
+ unsigned int border_width = 0;
+ char *display_name = NULL;
+ int title_len;
+
+ drv = (UGA_IO_PRIVATE *)
+ calloc (1, sizeof (UGA_IO_PRIVATE));
+ if (drv == NULL)
+ return EFI_OUT_OF_RESOURCES;
+
+ drv->UgaIo.UgaClose = UgaClose;
+ drv->UgaIo.UgaSize = UgaSize;
+ drv->UgaIo.UgaCheckKey = UgaCheckKey;
+ drv->UgaIo.UgaGetKey = UgaGetKey;
+ drv->UgaIo.UgaBlt = UgaBlt;
+
+ drv->key_count = 0;
+ drv->key_rd = 0;
+ drv->key_wr = 0;
+ drv->display = XOpenDisplay (display_name);
+ if (drv->display == NULL)
+ {
+ fprintf (stderr, "uga: cannot connect to X server %s\n",
+ XDisplayName (display_name));
+ free (drv);
+ return EFI_DEVICE_ERROR;
+ }
+ drv->screen = DefaultScreen (drv->display);
+ drv->visual = DefaultVisual (drv->display, drv->screen);
+ drv->win = XCreateSimpleWindow
+ (drv->display, RootWindow (drv->display, drv->screen),
+ 0, 0, 4, 4, border_width,
+ BlackPixel (drv->display, drv->screen),
+ WhitePixel (drv->display, drv->screen));
+
+ drv->depth = DefaultDepth (drv->display, drv->screen);
+
+ /* Compute title len and convert to Ascii. */
+ for (title_len = 0; Title[title_len] != 0; title_len++)
+ ;
+ {
+ char title[title_len + 1];
+ int i;
+ for (i = 0; i < title_len; i++)
+ title[i] = Title[i];
+ title[i] = 0;
+
+ XStoreName (drv->display, drv->win, title);
+ }
+
+ XSelectInput (drv->display, drv->win,
+ ExposureMask | KeyPressMask);
+ drv->gc = DefaultGC (drv->display, drv->screen);
+
+ *Uga = (EFI_UNIX_UGA_IO_PROTOCOL *)drv;
+ return EFI_SUCCESS;
+}
diff --git a/UnixPkg/Sec/UnixThunk.c b/UnixPkg/Sec/UnixThunk.c
new file mode 100644
index 0000000000..500568ad52
--- /dev/null
+++ b/UnixPkg/Sec/UnixThunk.c
@@ -0,0 +1,197 @@
+/*++
+
+Copyright (c) 2004 - 2006, Intel Corporation
+All rights reserved. This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+Module Name:
+
+ UnixThunk.c
+
+Abstract:
+
+ Since the SEC is the only program in our emulation we
+ must use a Tiano mechanism to export APIs to other modules.
+ This is the role of the EFI_UNIX_THUNK_PROTOCOL.
+
+ The mUnixThunkTable exists so that a change to EFI_UNIX_THUNK_PROTOCOL
+ will cause an error in initializing the array if all the member functions
+ are not added. It looks like adding a element to end and not initializing
+ it may cause the table to be initaliized with the members at the end being
+ set to zero. This is bad as jumping to zero will crash.
+
+
+ gUnix is a a public exported global that contains the initialized
+ data.
+
+--*/
+
+#include "SecMain.h"
+#include "Library/UnixLib.h"
+
+static int settimer_initialized;
+static struct timeval settimer_timeval;
+static void (*settimer_callback)(UINT64 delta);
+
+static void
+settimer_handler (int sig)
+{
+ struct timeval timeval;
+ UINT64 delta;
+
+ gettimeofday (&timeval, NULL);
+ delta = ((UINT64)timeval.tv_sec * 1000) + (timeval.tv_usec / 1000)
+ - ((UINT64)settimer_timeval.tv_sec * 1000)
+ - (settimer_timeval.tv_usec / 1000);
+ settimer_timeval = timeval;
+ if (settimer_callback)
+ (*settimer_callback)(delta);
+}
+
+static
+VOID
+SetTimer (UINT64 PeriodMs, VOID (*CallBack)(UINT64 DeltaMs))
+{
+ struct itimerval timerval;
+
+ if (!settimer_initialized) {
+ struct sigaction act;
+
+ settimer_initialized = 1;
+ act.sa_handler = settimer_handler;
+ act.sa_flags = 0;
+ sigemptyset (&act.sa_mask);
+ if (sigaction (SIGALRM, &act, NULL) != 0) {
+ printf ("SetTimer: sigaction error %s\n", strerror (errno));
+ }
+ if (gettimeofday (&settimer_timeval, NULL) != 0) {
+ printf ("SetTimer: gettimeofday error %s\n", strerror (errno));
+ }
+ }
+ timerval.it_value.tv_sec = PeriodMs / 1000;
+ timerval.it_value.tv_usec = (PeriodMs % 1000) * 1000;
+ timerval.it_value.tv_sec = PeriodMs / 1000;
+ timerval.it_interval = timerval.it_value;
+
+ if (setitimer (ITIMER_REAL, &timerval, NULL) != 0) {
+ printf ("SetTimer: setitimer error %s\n", strerror (errno));
+ }
+ settimer_callback = CallBack;
+}
+
+void
+msSleep (unsigned long Milliseconds)
+{
+ struct timespec ts;
+
+ ts.tv_sec = Milliseconds / 1000;
+ ts.tv_nsec = (Milliseconds % 1000) * 1000000;
+
+ while (nanosleep (&ts, &ts) != 0 && errno == EINTR)
+ ;
+}
+
+void
+GetLocalTime (EFI_TIME *Time)
+{
+ struct tm *tm;
+ time_t t;
+
+ t = time (NULL);
+ tm = localtime (&t);
+
+ Time->Year = 1900 + tm->tm_year;
+ Time->Month = tm->tm_mon;
+ Time->Day = tm->tm_mday;
+ Time->Hour = tm->tm_hour;
+ Time->Minute = tm->tm_min;
+ Time->Second = tm->tm_sec;
+ Time->Nanosecond = 0;
+ Time->TimeZone = timezone;
+ Time->Daylight = (daylight ? EFI_TIME_ADJUST_DAYLIGHT : 0)
+ | (tm->tm_isdst > 0 ? EFI_TIME_IN_DAYLIGHT : 0);
+}
+
+static void
+TzSet (void)
+{
+ static int done = 0;
+ if (!done) {
+ tzset ();
+ done = 1;
+ }
+}
+
+long
+GetTimeZone(void)
+{
+ TzSet ();
+ return timezone;
+}
+
+int
+GetDayLight(void)
+{
+ TzSet ();
+ return daylight;
+}
+
+int
+GetErrno(void)
+{
+ return errno;
+}
+
+extern EFI_STATUS
+UgaCreate(struct _EFI_UNIX_UGA_IO_PROTOCOL **UgaIo, CONST CHAR16 *Title);
+
+EFI_UNIX_THUNK_PROTOCOL mUnixThunkTable = {
+ EFI_UNIX_THUNK_PROTOCOL_SIGNATURE,
+ msSleep, /* Sleep */
+ exit, /* Exit */
+ SetTimer,
+ GetLocalTime,
+ gmtime,
+ GetTimeZone,
+ GetDayLight,
+ (UnixPoll)poll,
+ (UnixRead)read,
+ (UnixWrite)write,
+ getenv,
+ (UnixOpen)open,
+ lseek,
+ ftruncate,
+ close,
+ mkdir,
+ rmdir,
+ unlink,
+ GetErrno,
+ opendir,
+ rewinddir,
+ readdir,
+ closedir,
+ stat,
+ statfs,
+ rename,
+ mktime,
+ fsync,
+ chmod,
+ utime,
+ tcflush,
+ UgaCreate,
+ perror,
+ ioctl,
+ fcntl,
+ cfsetispeed,
+ cfsetospeed,
+ tcgetattr,
+ tcsetattr
+};
+
+
+EFI_UNIX_THUNK_PROTOCOL *gUnix = &mUnixThunkTable;