diff options
author | andrewfish <andrewfish@6f19259b-4bc3-4df7-8a09-765794883524> | 2011-05-11 18:31:20 +0000 |
---|---|---|
committer | andrewfish <andrewfish@6f19259b-4bc3-4df7-8a09-765794883524> | 2011-05-11 18:31:20 +0000 |
commit | 949f388f5fa361e3be374f59edc09b92296abe03 (patch) | |
tree | 1fdc4fe9c2c4aa61b8bfbb527134b19918448d29 /InOsEmuPkg/Unix/Sec | |
parent | da92f27632d2c89fa8726948ac9b02461ca8b61e (diff) | |
download | edk2-949f388f5fa361e3be374f59edc09b92296abe03.zip edk2-949f388f5fa361e3be374f59edc09b92296abe03.tar.gz edk2-949f388f5fa361e3be374f59edc09b92296abe03.tar.bz2 |
Add InOsEmuPkg. Like UnixPkg and Nt32Pkg, but EFI code can be common and does not require including system include files. Currently only Unix 64-bit is supported and it has only been tested on Mac OS X. Not all features are ported over, but GOP, via X11, and access to local file systems are supported and you can boot to the shell.
git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@11641 6f19259b-4bc3-4df7-8a09-765794883524
Diffstat (limited to 'InOsEmuPkg/Unix/Sec')
-rw-r--r-- | InOsEmuPkg/Unix/Sec/EmuThunk.c | 314 | ||||
-rw-r--r-- | InOsEmuPkg/Unix/Sec/FwVol.c | 309 | ||||
-rw-r--r-- | InOsEmuPkg/Unix/Sec/Gasket.h | 420 | ||||
-rw-r--r-- | InOsEmuPkg/Unix/Sec/PosixFileSystem.c | 1556 | ||||
-rw-r--r-- | InOsEmuPkg/Unix/Sec/Pthreads.c | 233 | ||||
-rw-r--r-- | InOsEmuPkg/Unix/Sec/SecMain.c | 1148 | ||||
-rw-r--r-- | InOsEmuPkg/Unix/Sec/SecMain.h | 306 | ||||
-rw-r--r-- | InOsEmuPkg/Unix/Sec/SecMain.inf | 118 | ||||
-rw-r--r-- | InOsEmuPkg/Unix/Sec/X11GraphicsWindow.c | 976 | ||||
-rw-r--r-- | InOsEmuPkg/Unix/Sec/X64/Gasket.S | 1054 | ||||
-rw-r--r-- | InOsEmuPkg/Unix/Sec/X64/SwitchStack.S | 112 |
11 files changed, 6546 insertions, 0 deletions
diff --git a/InOsEmuPkg/Unix/Sec/EmuThunk.c b/InOsEmuPkg/Unix/Sec/EmuThunk.c new file mode 100644 index 0000000..abae70b --- /dev/null +++ b/InOsEmuPkg/Unix/Sec/EmuThunk.c @@ -0,0 +1,314 @@ +/*++ @file + Since the SEC is the only program in our emulation we + must use a UEFI/PI mechanism to export APIs to other modules. + This is the role of the EFI_EMU_THUNK_PROTOCOL. + + The mUnixThunkTable exists so that a change to EFI_EMU_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. + +Copyright (c) 2004 - 2009, Intel Corporation. All rights reserved.<BR> +Portions copyright (c) 2008 - 2011, Apple Inc. All rights reserved.<BR> +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. + +**/ + +#include "SecMain.h" + +#ifdef __APPLE__ +#define DebugAssert _Mangle__DebugAssert + +#include <assert.h> +#include <CoreServices/CoreServices.h> +#include <mach/mach.h> +#include <mach/mach_time.h> + +#undef DebugAssert +#endif + +int settimer_initialized; +struct timeval settimer_timeval; +void (*settimer_callback)(UINT64 delta); + +BOOLEAN gEmulatorInterruptEnabled = FALSE; + + +UINTN +SecWriteStdErr ( + IN UINT8 *Buffer, + IN UINTN NumberOfBytes + ) +{ + ssize_t Return; + + Return = write (1, (const void *)Buffer, (size_t)NumberOfBytes); + + return (Return == -1) ? 0 : Return; +} + + + +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) { + ReverseGasketUint64 (settimer_callback, delta); + } +} + +VOID +SecSetTimer ( + IN UINT64 PeriodMs, + IN EMU_SET_TIMER_CALLBACK CallBack + ) +{ + struct itimerval timerval; + UINT32 remainder; + + if (!settimer_initialized) { + struct sigaction act; + + settimer_initialized = 1; + act.sa_handler = settimer_handler; + act.sa_flags = 0; + sigemptyset (&act.sa_mask); + gEmulatorInterruptEnabled = TRUE; + 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 = DivU64x32(PeriodMs, 1000); + DivU64x32Remainder(PeriodMs, 1000, &remainder); + timerval.it_value.tv_usec = remainder * 1000; + timerval.it_value.tv_sec = DivU64x32(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 +SecEnableInterrupt ( + VOID + ) +{ + sigset_t sigset; + + gEmulatorInterruptEnabled = TRUE; + // Since SetTimer() uses SIGALRM we emulate turning on and off interrupts + // by enabling/disabling SIGALRM. + sigemptyset (&sigset); + sigaddset (&sigset, SIGALRM); + pthread_sigmask (SIG_UNBLOCK, &sigset, NULL); +} + + +VOID +SecDisableInterrupt ( + VOID + ) +{ + sigset_t sigset; + + // Since SetTimer() uses SIGALRM we emulate turning on and off interrupts + // by enabling/disabling SIGALRM. + sigemptyset (&sigset); + sigaddset (&sigset, SIGALRM); + pthread_sigmask (SIG_BLOCK, &sigset, NULL); + gEmulatorInterruptEnabled = FALSE; +} + + +BOOLEAN +SecInterruptEanbled (void) +{ + return gEmulatorInterruptEnabled; +} + + +UINT64 +QueryPerformanceFrequency ( + VOID + ) +{ + // Hard code to nanoseconds + return 1000000000ULL; +} + +UINT64 +QueryPerformanceCounter ( + VOID + ) +{ +#if __APPLE__ + UINT64 Start; + Nanoseconds elapsedNano; + + Start = mach_absolute_time (); + + // Convert to nanoseconds. + + // Have to do some pointer fun because AbsoluteToNanoseconds + // works in terms of UnsignedWide, which is a structure rather + // than a proper 64-bit integer. + elapsedNano = AbsoluteToNanoseconds (*(AbsoluteTime *) &Start); + + return *(uint64_t *) &elapsedNano; +#else + // Need to figure out what to do for Linux? + return 0; +#endif +} + + + +VOID +SecSleep ( + IN UINT64 Milliseconds + ) +{ + struct timespec rq, rm; + struct timeval start, end; + unsigned long MicroSec; + + rq.tv_sec = Milliseconds / 1000; + rq.tv_nsec = (Milliseconds % 1000) * 1000000; + + // + // nanosleep gets interrupted by our timer tic. + // we need to track wall clock time or we will stall for way too long + // + gettimeofday (&start, NULL); + end.tv_sec = start.tv_sec + rq.tv_sec; + MicroSec = (start.tv_usec + rq.tv_nsec/1000); + end.tv_usec = MicroSec % 1000000; + if (MicroSec > 1000000) { + end.tv_sec++; + } + + while (nanosleep (&rq, &rm) == -1) { + if (errno != EINTR) { + break; + } + gettimeofday (&start, NULL); + if (start.tv_sec > end.tv_sec) { + break; + } if ((start.tv_sec == end.tv_sec) && (start.tv_usec > end.tv_usec)) { + break; + } + rq = rm; + } +} + +VOID +SecExit ( + UINTN Status + ) +{ + exit (Status); +} + + +VOID +SecGetTime ( + OUT EFI_TIME *Time, + OUT EFI_TIME_CAPABILITIES *Capabilities OPTIONAL + ) +{ + struct tm *tm; + time_t t; + + t = time (NULL); + tm = localtime (&t); + + Time->Year = 1900 + tm->tm_year; + Time->Month = tm->tm_mon + 1; + 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); + + if (Capabilities != NULL) { + Capabilities->Resolution = 1; + Capabilities->Accuracy = 50000000; + Capabilities->SetsToZero = FALSE; + } +} + + + +VOID +SecSetTime ( + IN EFI_TIME *Time + ) +{ + // Don't change the time on the system + // We could save delta to localtime() and have SecGetTime adjust return values? + return; +} + + +EFI_STATUS +SecGetNextProtocol ( + IN BOOLEAN EmuBusDriver, + OUT EMU_IO_THUNK_PROTOCOL **Instance OPTIONAL + ) +{ + return GetNextThunkProtocol (EmuBusDriver, Instance); +} + + +EMU_THUNK_PROTOCOL gEmuThunkProtocol = { + GasketSecWriteStdErr, + GasketSecPeCoffGetEntryPoint, + GasketSecPeCoffRelocateImageExtraAction, + GasketSecPeCoffUnloadImageExtraAction, + GasketSecEnableInterrupt, + GasketSecDisableInterrupt, + GasketQueryPerformanceFrequency, + GasketQueryPerformanceCounter, + GasketSecSleep, + GasketSecExit, + GasketSecGetTime, + GasketSecSetTime, + GasketSecSetTimer, + GasketSecGetNextProtocol +}; + + +VOID +SecInitThunkProtocol ( + VOID + ) +{ + // timezone and daylight lib globals depend on tzset be called 1st. + tzset (); +} + diff --git a/InOsEmuPkg/Unix/Sec/FwVol.c b/InOsEmuPkg/Unix/Sec/FwVol.c new file mode 100644 index 0000000..a9a09a4 --- /dev/null +++ b/InOsEmuPkg/Unix/Sec/FwVol.c @@ -0,0 +1,309 @@ +/*++ @file
+ A simple FV stack so the SEC can extract the SEC Core from an
+ FV.
+
+Copyright (c) 2006, Intel Corporation. All rights reserved.<BR>
+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.
+
+**/
+
+#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/InOsEmuPkg/Unix/Sec/Gasket.h b/InOsEmuPkg/Unix/Sec/Gasket.h new file mode 100644 index 0000000..665a075 --- /dev/null +++ b/InOsEmuPkg/Unix/Sec/Gasket.h @@ -0,0 +1,420 @@ +/** @file
+
+ Copyright (c) 2008 - 2011, Apple Inc. All rights reserved.<BR>
+
+ 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.
+
+**/
+
+#ifndef _GASKET_H_
+#define _GASKET_H_
+
+//
+// EMU_THUNK_PROTOCOL gaskets (EFIAPI to UNIX ABI)
+//
+
+UINTN
+GasketSecWriteStdErr (
+ IN UINT8 *Buffer,
+ IN UINTN NumberOfBytes
+ );
+
+RETURN_STATUS
+EFIAPI
+GasketSecPeCoffGetEntryPoint (
+ IN VOID *Pe32Data,
+ IN OUT VOID **EntryPoint
+ );
+
+VOID
+EFIAPI
+GasketSecPeCoffRelocateImageExtraAction (
+ IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
+ );
+
+VOID
+EFIAPI
+GasketSecPeCoffUnloadImageExtraAction (
+ IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
+ );
+
+VOID
+EFIAPI
+GasketSecSetTimer (
+ IN UINT64 PeriodMs,
+ IN EMU_SET_TIMER_CALLBACK CallBack
+ );
+
+VOID
+EFIAPI
+GasketSecEnableInterrupt (
+ VOID
+ );
+
+VOID
+EFIAPI
+GasketSecDisableInterrupt (
+ VOID
+ );
+
+UINT64
+GasketQueryPerformanceFrequency (
+ VOID
+ );
+
+UINT64
+GasketQueryPerformanceCounter (
+ VOID
+ );
+
+
+VOID
+EFIAPI
+GasketSecSleep (
+ IN UINT64 Milliseconds
+ );
+
+VOID
+EFIAPI
+GasketSecExit (
+ UINTN Status
+ );
+
+VOID
+EFIAPI
+GasketSecGetTime (
+ OUT EFI_TIME *Time,
+ OUT EFI_TIME_CAPABILITIES *Capabilities OPTIONAL
+ );
+
+VOID
+EFIAPI
+GasketSecSetTime (
+ IN EFI_TIME *Time
+ );
+
+EFI_STATUS
+EFIAPI
+GasketSecGetNextProtocol (
+ IN BOOLEAN EmuBusDriver,
+ OUT EMU_IO_THUNK_PROTOCOL **Instance OPTIONAL
+ );
+
+
+// PPIs produced by SEC
+
+
+EFI_STATUS
+EFIAPI
+GasketSecUnixPeiLoadFile (
+ IN VOID *Pe32Data,
+ IN EFI_PHYSICAL_ADDRESS *ImageAddress,
+ IN UINT64 *ImageSize,
+ OUT EFI_PHYSICAL_ADDRESS *EntryPoint
+ );
+
+EFI_STATUS
+EFIAPI
+GasketSecUnixPeiAutoScan (
+ IN UINTN Index,
+ OUT EFI_PHYSICAL_ADDRESS *MemoryBase,
+ OUT UINT64 *MemorySize
+ );
+
+VOID *
+EFIAPI
+GasketSecEmuThunkAddress (
+ VOID
+ );
+
+
+EFI_STATUS
+EFIAPI
+GasketSecUnixUnixFwhAddress (
+ IN OUT UINT64 *FwhSize,
+ IN OUT EFI_PHYSICAL_ADDRESS *FwhBase
+ );
+
+
+
+//
+// Reverse (UNIX to EFIAPI) gaskets
+//
+
+typedef
+void
+(*CALL_BACK) (
+ UINT64 Delta
+ );
+
+UINTN
+ReverseGasketUint64 (
+ CALL_BACK CallBack,
+ UINT64 a
+ );
+
+UINTN
+ReverseGasketUint64Uint64 (
+ VOID *CallBack,
+ VOID *Context,
+ VOID *Key
+ );
+
+//
+// Gasket functions for EFI_EMU_UGA_IO_PROTOCOL
+//
+
+
+EFI_STATUS
+EFIAPI
+GasketX11Size (
+ EMU_GRAPHICS_WINDOW_PROTOCOL *GraphicsWindowsIo,
+ UINT32 Width,
+ UINT32 Height
+ );
+
+EFI_STATUS
+EFIAPI
+GasketX11CheckKey (
+ EMU_GRAPHICS_WINDOW_PROTOCOL *GraphicsWindowsIo
+ );
+
+EFI_STATUS
+EFIAPI
+GasketX11GetKey (
+ EMU_GRAPHICS_WINDOW_PROTOCOL *GraphicsWindowsIo,
+ EFI_KEY_DATA *key
+ );
+
+EFI_STATUS
+EFIAPI
+GasketX11KeySetState (
+ EMU_GRAPHICS_WINDOW_PROTOCOL *GraphicsWindowsIo,
+ EFI_KEY_TOGGLE_STATE *KeyToggleState
+ );
+
+EFI_STATUS
+EFIAPI
+GasketX11RegisterKeyNotify (
+ IN EMU_GRAPHICS_WINDOW_PROTOCOL *GraphicsWindowsIo,
+ IN EMU_GRAPHICS_WINDOW_REGISTER_KEY_NOTIFY_CALLBACK MakeCallBack,
+ IN EMU_GRAPHICS_WINDOW_REGISTER_KEY_NOTIFY_CALLBACK BreakCallBack,
+ IN VOID *Context
+ );
+
+
+EFI_STATUS
+EFIAPI
+GasketX11Blt (
+ IN EMU_GRAPHICS_WINDOW_PROTOCOL *GraphicsWindows,
+ IN EFI_UGA_PIXEL *BltBuffer OPTIONAL,
+ IN EFI_UGA_BLT_OPERATION BltOperation,
+ IN EMU_GRAPHICS_WINDOWS__BLT_ARGS *Args
+ );
+
+EFI_STATUS
+EFIAPI
+GasketX11CheckPointer (
+ EMU_GRAPHICS_WINDOW_PROTOCOL *GraphicsWindowsIo
+ );
+
+EFI_STATUS
+EFIAPI
+GasketX11GetPointerState (
+ EMU_GRAPHICS_WINDOW_PROTOCOL *GraphicsWindowsIo,
+ EFI_SIMPLE_POINTER_STATE *state
+ );
+
+EFI_STATUS
+EFIAPI
+GasketX11GraphicsWindowOpen (
+ IN EMU_IO_THUNK_PROTOCOL *This
+ );
+
+EFI_STATUS
+EFIAPI
+GasketX11GraphicsWindowClose (
+ IN EMU_IO_THUNK_PROTOCOL *This
+ );
+
+// Pthreads
+
+UINTN
+EFIAPI
+GasketPthreadMutexLock (
+ IN VOID *Mutex
+ );
+
+
+
+UINTN
+EFIAPI
+GasketPthreadMutexUnLock (
+ IN VOID *Mutex
+ );
+
+
+UINTN
+EFIAPI
+GasketPthreadMutexTryLock (
+ IN VOID *Mutex
+ );
+
+
+VOID *
+EFIAPI
+GasketPthreadMutexInit (
+ IN VOID
+ );
+
+
+UINTN
+EFIAPI
+GasketPthreadMutexDestroy (
+ IN VOID *Mutex
+ );
+
+
+UINTN
+EFIAPI
+GasketPthreadCreate (
+ IN VOID *Thread,
+ IN VOID *Attribute,
+ IN PTREAD_THUNK_THEAD_ENTRY Start,
+ IN VOID *Context
+ );
+
+VOID
+EFIAPI
+GasketPthreadExit (
+ IN VOID *ValuePtr
+ );
+
+
+UINTN
+EFIAPI
+GasketPthreadSelf (
+ VOID
+ );
+
+EFI_STATUS
+EFIAPI
+GasketPthreadOpen (
+ IN EMU_IO_THUNK_PROTOCOL *This
+ );
+
+EFI_STATUS
+EFIAPI
+GasketPthreadClose (
+ IN EMU_IO_THUNK_PROTOCOL *This
+ );
+
+
+// PosixFileSystem
+
+EFI_STATUS
+EFIAPI
+GasketPosixOpenVolume (
+ IN EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *This,
+ OUT EFI_FILE_PROTOCOL **Root
+ );
+
+EFI_STATUS
+EFIAPI
+GasketPosixFileOpen (
+ IN EFI_FILE_PROTOCOL *This,
+ OUT EFI_FILE_PROTOCOL **NewHandle,
+ IN CHAR16 *FileName,
+ IN UINT64 OpenMode,
+ IN UINT64 Attributes
+ );
+
+EFI_STATUS
+EFIAPI
+GasketPosixFileCLose (
+ IN EFI_FILE_PROTOCOL *This
+ );
+
+EFI_STATUS
+EFIAPI
+GasketPosixFileDelete (
+ IN EFI_FILE_PROTOCOL *This
+ );
+
+EFI_STATUS
+EFIAPI
+GasketPosixFileRead (
+ IN EFI_FILE_PROTOCOL *This,
+ IN OUT UINTN *BufferSize,
+ OUT VOID *Buffer
+ );
+
+EFI_STATUS
+EFIAPI
+GasketPosixFileWrite (
+ IN EFI_FILE_PROTOCOL *This,
+ IN OUT UINTN *BufferSize,
+ IN VOID *Buffer
+ );
+
+EFI_STATUS
+EFIAPI
+GasketPosixFileSetPossition (
+ IN EFI_FILE_PROTOCOL *This,
+ IN UINT64 Position
+ );
+
+EFI_STATUS
+EFIAPI
+GasketPosixFileGetPossition (
+ IN EFI_FILE_PROTOCOL *This,
+ OUT UINT64 *Position
+ );
+
+EFI_STATUS
+EFIAPI
+GasketPosixFileGetInfo (
+ IN EFI_FILE_PROTOCOL *This,
+ IN EFI_GUID *InformationType,
+ IN OUT UINTN *BufferSize,
+ OUT VOID *Buffer
+ );
+
+EFI_STATUS
+EFIAPI
+GasketPosixFileSetInfo (
+ IN EFI_FILE_PROTOCOL *This,
+ IN EFI_GUID *InformationType,
+ IN UINTN BufferSize,
+ IN VOID *Buffer
+ );
+
+EFI_STATUS
+EFIAPI
+GasketPosixFileFlush (
+ IN EFI_FILE_PROTOCOL *This
+ );
+
+EFI_STATUS
+EFIAPI
+GasketPosixFileSystmeThunkOpen (
+ IN EMU_IO_THUNK_PROTOCOL *This
+ );
+
+EFI_STATUS
+EFIAPI
+GasketPosixFileSystmeThunkClose (
+ IN EMU_IO_THUNK_PROTOCOL *This
+ );
+
+
+
+#endif
+
+
diff --git a/InOsEmuPkg/Unix/Sec/PosixFileSystem.c b/InOsEmuPkg/Unix/Sec/PosixFileSystem.c new file mode 100644 index 0000000..d2d3e6d --- /dev/null +++ b/InOsEmuPkg/Unix/Sec/PosixFileSystem.c @@ -0,0 +1,1556 @@ +/*++ @file + POSIX Pthreads to emulate APs and implement threads + +Copyright (c) 2011, Apple Inc. 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. + + +**/ + +#include "SecMain.h" + + +#define EMU_SIMPLE_FILE_SYSTEM_PRIVATE_SIGNATURE SIGNATURE_32 ('E', 'P', 'f', 's') + +typedef struct { + UINTN Signature; + EMU_IO_THUNK_PROTOCOL *Thunk; + EFI_SIMPLE_FILE_SYSTEM_PROTOCOL SimpleFileSystem; + CHAR8 *FilePath; + CHAR16 *VolumeLabel; + BOOLEAN FileHandlesOpen; +} EMU_SIMPLE_FILE_SYSTEM_PRIVATE; + +#define EMU_SIMPLE_FILE_SYSTEM_PRIVATE_DATA_FROM_THIS(a) \ + CR (a, \ + EMU_SIMPLE_FILE_SYSTEM_PRIVATE, \ + SimpleFileSystem, \ + EMU_SIMPLE_FILE_SYSTEM_PRIVATE_SIGNATURE \ + ) + + +#define EMU_EFI_FILE_PRIVATE_SIGNATURE SIGNATURE_32 ('E', 'P', 'f', 'i') + +typedef struct { + UINTN Signature; + EMU_IO_THUNK_PROTOCOL *Thunk; + EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *SimpleFileSystem; + EFI_FILE_PROTOCOL EfiFile; + int fd; + DIR *Dir; + BOOLEAN IsRootDirectory; + BOOLEAN IsDirectoryPath; + BOOLEAN IsOpenedByRead; + char *FileName; + struct dirent *Dirent; +} EMU_EFI_FILE_PRIVATE; + +#define EMU_EFI_FILE_PRIVATE_DATA_FROM_THIS(a) \ + CR (a, \ + EMU_EFI_FILE_PRIVATE, \ + EfiFile, \ + EMU_EFI_FILE_PRIVATE_SIGNATURE \ + ) + +EFI_STATUS +PosixFileGetInfo ( + IN EFI_FILE_PROTOCOL *This, + IN EFI_GUID *InformationType, + IN OUT UINTN *BufferSize, + OUT VOID *Buffer + ); + +EFI_STATUS +PosixFileSetInfo ( + IN EFI_FILE_PROTOCOL *This, + IN EFI_GUID *InformationType, + IN UINTN BufferSize, + IN VOID *Buffer + ); + + +EFI_FILE_PROTOCOL gPosixFileProtocol = { + EFI_FILE_REVISION, + GasketPosixFileOpen, + GasketPosixFileCLose, + GasketPosixFileDelete, + GasketPosixFileRead, + GasketPosixFileWrite, + GasketPosixFileGetPossition, + GasketPosixFileSetPossition, + GasketPosixFileGetInfo, + GasketPosixFileSetInfo, + GasketPosixFileFlush +}; + +EFI_SIMPLE_FILE_SYSTEM_PROTOCOL gPosixFileSystemProtocol = { + EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_REVISION, + GasketPosixOpenVolume, +}; + + +/** + Open the root directory on a volume. + + @param This Protocol instance pointer. + @param Root Returns an Open file handle for the root directory + + @retval EFI_SUCCESS The device was opened. + @retval EFI_UNSUPPORTED This volume does not support the file system. + @retval EFI_NO_MEDIA The device has no media. + @retval EFI_DEVICE_ERROR The device reported an error. + @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. + @retval EFI_ACCESS_DENIED The service denied access to the file. + @retval EFI_OUT_OF_RESOURCES The volume was not opened due to lack of resources. + +**/ +EFI_STATUS +PosixOpenVolume ( + IN EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *This, + OUT EFI_FILE_PROTOCOL **Root + ) +{ + EFI_STATUS Status; + EMU_SIMPLE_FILE_SYSTEM_PRIVATE *Private; + EMU_EFI_FILE_PRIVATE *PrivateFile; + + Private = EMU_SIMPLE_FILE_SYSTEM_PRIVATE_DATA_FROM_THIS (This); + + Status = EFI_OUT_OF_RESOURCES; + PrivateFile = malloc (sizeof (EMU_EFI_FILE_PRIVATE)); + if (PrivateFile == NULL) { + goto Done; + } + + PrivateFile->FileName = malloc (AsciiStrSize (Private->FilePath)); + if (PrivateFile->FileName == NULL) { + goto Done; + } + AsciiStrCpy (PrivateFile->FileName, Private->FilePath); + + PrivateFile->Signature = EMU_EFI_FILE_PRIVATE_SIGNATURE; + PrivateFile->Thunk = Private->Thunk; + PrivateFile->SimpleFileSystem = This; + PrivateFile->IsRootDirectory = TRUE; + PrivateFile->IsDirectoryPath = TRUE; + PrivateFile->IsOpenedByRead = TRUE; + + CopyMem (&PrivateFile->EfiFile, &gPosixFileProtocol, sizeof (EFI_FILE_PROTOCOL)); + + PrivateFile->fd = -1; + PrivateFile->Dir = NULL; + PrivateFile->Dirent = NULL; + + *Root = &PrivateFile->EfiFile; + + PrivateFile->Dir = opendir (PrivateFile->FileName); + if (PrivateFile->Dir == NULL) { + Status = EFI_ACCESS_DENIED; + } else { + Status = EFI_SUCCESS; + } + +Done: + if (EFI_ERROR (Status)) { + if (PrivateFile != NULL) { + if (PrivateFile->FileName != NULL) { + free (PrivateFile->FileName); + } + + free (PrivateFile); + } + + *Root = NULL; + } + + return Status; +} + + +EFI_STATUS +ErrnoToEfiStatus () +{ + switch (errno) { + case EACCES: + return EFI_ACCESS_DENIED; + + case EDQUOT: + case ENOSPC: + return EFI_VOLUME_FULL; + + default: + return EFI_DEVICE_ERROR; + } +} + +VOID +CutPrefix ( + IN CHAR8 *Str, + IN UINTN Count + ) +{ + CHAR8 *Pointer; + + if (AsciiStrLen (Str) < Count) { + ASSERT (0); + } + + for (Pointer = Str; *(Pointer + Count); Pointer++) { + *Pointer = *(Pointer + Count); + } + + *Pointer = *(Pointer + Count); +} + + +VOID +PosixSystemTimeToEfiTime ( + IN time_t SystemTime, + OUT EFI_TIME *Time + ) +{ + struct tm *tm; + + tm = gmtime (&SystemTime); + Time->Year = tm->tm_year; + Time->Month = tm->tm_mon + 1; + 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); +} + + +EFI_STATUS +UnixSimpleFileSystemFileInfo ( + EMU_EFI_FILE_PRIVATE *PrivateFile, + IN CHAR8 *FileName, + IN OUT UINTN *BufferSize, + OUT VOID *Buffer + ) +{ + EFI_STATUS Status; + UINTN Size; + UINTN NameSize; + UINTN ResultSize; + EFI_FILE_INFO *Info; + CHAR8 *RealFileName; + CHAR8 *TempPointer; + CHAR16 *BufferFileName; + struct stat buf; + + if (FileName != NULL) { + RealFileName = FileName; + } + else if (PrivateFile->IsRootDirectory) { + RealFileName = ""; + } else { + RealFileName = PrivateFile->FileName; + } + + TempPointer = RealFileName; + while (*TempPointer) { + if (*TempPointer == '/') { + RealFileName = TempPointer + 1; + } + + TempPointer++; + } + + Size = SIZE_OF_EFI_FILE_INFO; + NameSize = AsciiStrSize (RealFileName) * 2; + ResultSize = Size + NameSize; + + if (*BufferSize < ResultSize) { + *BufferSize = ResultSize; + return EFI_BUFFER_TOO_SMALL; + } + if (stat (FileName == NULL ? PrivateFile->FileName : FileName, &buf) < 0) { + return EFI_DEVICE_ERROR; + } + + Status = EFI_SUCCESS; + + Info = Buffer; + ZeroMem (Info, ResultSize); + + Info->Size = ResultSize; + Info->FileSize = buf.st_size; + Info->PhysicalSize = MultU64x32 (buf.st_blocks, buf.st_blksize); + + PosixSystemTimeToEfiTime (buf.st_ctime, &Info->CreateTime); + PosixSystemTimeToEfiTime (buf.st_atime, &Info->LastAccessTime); + PosixSystemTimeToEfiTime (buf.st_mtime, &Info->ModificationTime); + + if (!(buf.st_mode & S_IWUSR)) { + Info->Attribute |= EFI_FILE_READ_ONLY; + } + + if (S_ISDIR(buf.st_mode)) { + Info->Attribute |= EFI_FILE_DIRECTORY; + } + + + BufferFileName = (CHAR16 *)((CHAR8 *) Buffer + Size); + while (*RealFileName) { + *BufferFileName++ = *RealFileName++; + } + *BufferFileName = 0; + + *BufferSize = ResultSize; + return Status; +} + +BOOLEAN +IsZero ( + IN VOID *Buffer, + IN UINTN Length + ) +{ + if (Buffer == NULL || Length == 0) { + return FALSE; + } + + if (*(UINT8 *) Buffer != 0) { + return FALSE; + } + + if (Length > 1) { + if (!CompareMem (Buffer, (UINT8 *) Buffer + 1, Length - 1)) { + return FALSE; + } + } + + return TRUE; +} + + + +/** + Opens a new file relative to the source file's location. + + @param This The protocol instance pointer. + @param NewHandle Returns File Handle for FileName. + @param FileName Null terminated string. "\", ".", and ".." are supported. + @param OpenMode Open mode for file. + @param Attributes Only used for EFI_FILE_MODE_CREATE. + + @retval EFI_SUCCESS The device was opened. + @retval EFI_NOT_FOUND The specified file could not be found on the device. + @retval EFI_NO_MEDIA The device has no media. + @retval EFI_MEDIA_CHANGED The media has changed. + @retval EFI_DEVICE_ERROR The device reported an error. + @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. + @retval EFI_ACCESS_DENIED The service denied access to the file. + @retval EFI_OUT_OF_RESOURCES The volume was not opened due to lack of resources. + @retval EFI_VOLUME_FULL The volume is full. + +**/ +EFI_STATUS +PosixFileOpen ( + IN EFI_FILE_PROTOCOL *This, + OUT EFI_FILE_PROTOCOL **NewHandle, + IN CHAR16 *FileName, + IN UINT64 OpenMode, + IN UINT64 Attributes + ) +{ + EFI_FILE_PROTOCOL *Root; + EMU_EFI_FILE_PRIVATE *PrivateFile; + EMU_EFI_FILE_PRIVATE *NewPrivateFile; + EMU_SIMPLE_FILE_SYSTEM_PRIVATE *PrivateRoot; + EFI_STATUS Status; + CHAR16 *Src; + char *Dst; + CHAR8 *RealFileName; + char *ParseFileName; + char *GuardPointer; + CHAR8 TempChar; + UINTN Count; + BOOLEAN TrailingDash; + BOOLEAN LoopFinish; + UINTN InfoSize; + EFI_FILE_INFO *Info; + struct stat finfo; + int res; + + + PrivateFile = EMU_EFI_FILE_PRIVATE_DATA_FROM_THIS (This); + PrivateRoot = EMU_SIMPLE_FILE_SYSTEM_PRIVATE_DATA_FROM_THIS (PrivateFile->SimpleFileSystem); + NewPrivateFile = NULL; + Status = EFI_OUT_OF_RESOURCES; + + // + // BUGBUG: assume an open of root + // if current location, return current data + // + if ((StrCmp (FileName, L"\\") == 0) || + (StrCmp (FileName, L".") == 0 && PrivateFile->IsRootDirectory)) { +OpenRoot: + Status = PosixOpenVolume (PrivateFile->SimpleFileSystem, &Root); + NewPrivateFile = EMU_EFI_FILE_PRIVATE_DATA_FROM_THIS (Root); + goto Done; + } + + TrailingDash = FALSE; + if (FileName[StrLen (FileName) - 1] == L'\\') { + TrailingDash = TRUE; + FileName[StrLen (FileName) - 1] = 0; + } + + // + // Attempt to open the file + // + NewPrivateFile = malloc (sizeof (EMU_EFI_FILE_PRIVATE)); + if (NewPrivateFile == NULL) { + goto Done; + } + + CopyMem (NewPrivateFile, PrivateFile, sizeof (EMU_EFI_FILE_PRIVATE)); + + NewPrivateFile->FileName = malloc (AsciiStrSize (PrivateFile->FileName) + 1 + StrLen (FileName) + 1); + if (NewPrivateFile->FileName == NULL) { + goto Done; + } + + if (*FileName == L'\\') { + AsciiStrCpy (NewPrivateFile->FileName, PrivateRoot->FilePath); + // Skip first '\'. + Src = FileName + 1; + } else { + AsciiStrCpy (NewPrivateFile->FileName, PrivateFile->FileName); + Src = FileName; + } + Dst = NewPrivateFile->FileName + AsciiStrLen (NewPrivateFile->FileName); + GuardPointer = NewPrivateFile->FileName + AsciiStrLen (PrivateRoot->FilePath); + *Dst++ = '/'; + // Convert unicode to ascii and '\' to '/' + while (*Src) { + if (*Src == '\\') { + *Dst++ = '/'; + } else { + *Dst++ = *Src; + } + Src++; + } + *Dst = 0; + + + // + // Get rid of . and .., except leading . or .. + // + + // + // GuardPointer protect simplefilesystem root path not be destroyed + // + + LoopFinish = FALSE; + while (!LoopFinish) { + LoopFinish = TRUE; + + for (ParseFileName = GuardPointer; *ParseFileName; ParseFileName++) { + if (*ParseFileName == '.' && + (*(ParseFileName + 1) == 0 || *(ParseFileName + 1) == '/') && + *(ParseFileName - 1) == '/' + ) { + + // + // cut /. + // + CutPrefix (ParseFileName - 1, 2); + LoopFinish = FALSE; + break; + } + + if (*ParseFileName == '.' && + *(ParseFileName + 1) == '.' && + (*(ParseFileName + 2) == 0 || *(ParseFileName + 2) == '/') && + *(ParseFileName - 1) == '/' + ) { + + ParseFileName--; + Count = 3; + + while (ParseFileName != GuardPointer) { + ParseFileName--; + Count++; + if (*ParseFileName == '/') { + break; + } + } + + // + // cut /.. and its left directory + // + CutPrefix (ParseFileName, Count); + LoopFinish = FALSE; + break; + } + } + } + + if (AsciiStrCmp (NewPrivateFile->FileName, PrivateRoot->FilePath) == 0) { + NewPrivateFile->IsRootDirectory = TRUE; + free (NewPrivateFile->FileName); + free (NewPrivateFile); + goto OpenRoot; + } + + RealFileName = NewPrivateFile->FileName + AsciiStrLen(NewPrivateFile->FileName) - 1; + while (RealFileName > NewPrivateFile->FileName && *RealFileName != '/') { + RealFileName--; + } + + TempChar = *(RealFileName - 1); + *(RealFileName - 1) = 0; + *(RealFileName - 1) = TempChar; + + + // + // Test whether file or directory + // + NewPrivateFile->IsRootDirectory = FALSE; + NewPrivateFile->fd = -1; + NewPrivateFile->Dir = NULL; + if (OpenMode & EFI_FILE_MODE_CREATE) { + if (Attributes & EFI_FILE_DIRECTORY) { + NewPrivateFile->IsDirectoryPath = TRUE; + } else { + NewPrivateFile->IsDirectoryPath = FALSE; + } + } else { + res = stat (NewPrivateFile->FileName, &finfo); + if (res == 0 && S_ISDIR(finfo.st_mode)) { + NewPrivateFile->IsDirectoryPath = TRUE; + } else { + NewPrivateFile->IsDirectoryPath = FALSE; + } + } + + if (OpenMode & EFI_FILE_MODE_WRITE) { + NewPrivateFile->IsOpenedByRead = FALSE; + } else { + NewPrivateFile->IsOpenedByRead = TRUE; + } + + Status = EFI_SUCCESS; + + // + // deal with directory + // + if (NewPrivateFile->IsDirectoryPath) { + if ((OpenMode & EFI_FILE_MODE_CREATE)) { + // + // Create a directory + // + if (mkdir (NewPrivateFile->FileName, 0777) != 0) { + if (errno != EEXIST) { + //free (TempFileName); + Status = EFI_ACCESS_DENIED; + goto Done; + } + } + } + + NewPrivateFile->Dir = opendir (NewPrivateFile->FileName); + if (NewPrivateFile->Dir == NULL) { + if (errno == EACCES) { + Status = EFI_ACCESS_DENIED; + } else { + Status = EFI_NOT_FOUND; + } + + goto Done; + } + + } else { + // + // deal with file + // + NewPrivateFile->fd = open ( + NewPrivateFile->FileName, + ((OpenMode & EFI_FILE_MODE_CREATE) ? O_CREAT : 0) | (NewPrivateFile->IsOpenedByRead ? O_RDONLY : O_RDWR), + 0666 + ); + if (NewPrivateFile->fd < 0) { + if (errno == ENOENT) { + Status = EFI_NOT_FOUND; + } else { + Status = EFI_ACCESS_DENIED; + } + } + } + + if ((OpenMode & EFI_FILE_MODE_CREATE) && Status == EFI_SUCCESS) { + // + // Set the attribute + // + InfoSize = 0; + Info = NULL; + Status = PosixFileGetInfo (&NewPrivateFile->EfiFile, &gEfiFileInfoGuid, &InfoSize, Info); + if (Status != EFI_BUFFER_TOO_SMALL) { + Status = EFI_DEVICE_ERROR; + goto Done; + } + + Info = malloc (InfoSize); + if (Info == NULL) { + goto Done; + } + + Status = PosixFileGetInfo (&NewPrivateFile->EfiFile, &gEfiFileInfoGuid, &InfoSize, Info); + if (EFI_ERROR (Status)) { + goto Done; + } + + Info->Attribute = Attributes; + PosixFileSetInfo (&NewPrivateFile->EfiFile, &gEfiFileInfoGuid, InfoSize, Info); + + free (Info); + } + +Done: ; + if (TrailingDash) { + FileName[StrLen (FileName) + 1] = 0; + FileName[StrLen (FileName)] = L'\\'; + } + + if (EFI_ERROR (Status)) { + if (NewPrivateFile) { + if (NewPrivateFile->FileName) { + free (NewPrivateFile->FileName); + } + + free (NewPrivateFile); + } + } else { + *NewHandle = &NewPrivateFile->EfiFile; + } + + return Status; +} + + + +/** + Close the file handle + + @param This Protocol instance pointer. + + @retval EFI_SUCCESS The device was opened. + +**/ +EFI_STATUS +PosixFileCLose ( + IN EFI_FILE_PROTOCOL *This + ) +{ + EMU_EFI_FILE_PRIVATE *PrivateFile; + + PrivateFile = EMU_EFI_FILE_PRIVATE_DATA_FROM_THIS (This); + + if (PrivateFile->fd >= 0) { + close (PrivateFile->fd); + } + if (PrivateFile->Dir != NULL) { + closedir (PrivateFile->Dir); + } + + PrivateFile->fd = -1; + PrivateFile->Dir = NULL; + + if (PrivateFile->FileName) { + free (PrivateFile->FileName); + } + + free (PrivateFile); + + return EFI_SUCCESS; +} + + +/** + Close and delete the file handle. + + @param This Protocol instance pointer. + + @retval EFI_SUCCESS The device was opened. + @retval EFI_WARN_DELETE_FAILURE The handle was closed but the file was not deleted. + +**/ +EFI_STATUS +PosixFileDelete ( + IN EFI_FILE_PROTOCOL *This + ) +{ + EFI_STATUS Status; + EMU_EFI_FILE_PRIVATE *PrivateFile; + + PrivateFile = EMU_EFI_FILE_PRIVATE_DATA_FROM_THIS (This); + Status = EFI_WARN_DELETE_FAILURE; + + if (PrivateFile->IsDirectoryPath) { + if (PrivateFile->Dir != NULL) { + closedir (PrivateFile->Dir); + PrivateFile->Dir = NULL; + } + + if (rmdir (PrivateFile->FileName) == 0) { + Status = EFI_SUCCESS; + } + } else { + close (PrivateFile->fd); + PrivateFile->fd = -1; + + if (!PrivateFile->IsOpenedByRead) { + if (!unlink (PrivateFile->FileName)) { + Status = EFI_SUCCESS; + } + } + } + + free (PrivateFile->FileName); + free (PrivateFile); + + return Status; +} + + +/** + Read data from the file. + + @param This Protocol instance pointer. + @param BufferSize On input size of buffer, on output amount of data in buffer. + @param Buffer The buffer in which data is read. + + @retval EFI_SUCCESS Data was read. + @retval EFI_NO_MEDIA The device has no media. + @retval EFI_DEVICE_ERROR The device reported an error. + @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. + @retval EFI_BUFFER_TO_SMALL BufferSize is too small. BufferSize contains required size. + +**/ +EFI_STATUS +PosixFileRead ( + IN EFI_FILE_PROTOCOL *This, + IN OUT UINTN *BufferSize, + OUT VOID *Buffer + ) +{ + EMU_EFI_FILE_PRIVATE *PrivateFile; + EFI_STATUS Status; + int Res; + UINTN Size; + UINTN NameSize; + UINTN ResultSize; + CHAR8 *FullFileName; + + + PrivateFile = EMU_EFI_FILE_PRIVATE_DATA_FROM_THIS (This); + + if (!PrivateFile->IsDirectoryPath) { + if (PrivateFile->fd < 0) { + Status = EFI_DEVICE_ERROR; + goto Done; + } + + Res = read (PrivateFile->fd, Buffer, *BufferSize); + if (Res < 0) { + Status = EFI_DEVICE_ERROR; + goto Done; + } + *BufferSize = Res; + Status = EFI_SUCCESS; + goto Done; + } + + // + // Read on a directory. + // + if (PrivateFile->Dir == NULL) { + Status = EFI_DEVICE_ERROR; + goto Done; + } + + if (PrivateFile->Dirent == NULL) { + PrivateFile->Dirent = readdir (PrivateFile->Dir); + if (PrivateFile->Dirent == NULL) { + *BufferSize = 0; + Status = EFI_SUCCESS; + goto Done; + } + } + + Size = SIZE_OF_EFI_FILE_INFO; + NameSize = AsciiStrLen (PrivateFile->Dirent->d_name) + 1; + ResultSize = Size + 2 * NameSize; + + if (*BufferSize < ResultSize) { + *BufferSize = ResultSize; + Status = EFI_BUFFER_TOO_SMALL; + goto Done; + } + Status = EFI_SUCCESS; + + *BufferSize = ResultSize; + + FullFileName = malloc (AsciiStrLen(PrivateFile->FileName) + 1 + NameSize); + if (FullFileName == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto Done; + } + + AsciiStrCpy (FullFileName, PrivateFile->FileName); + AsciiStrCat (FullFileName, "/"); + AsciiStrCat (FullFileName, PrivateFile->Dirent->d_name); + Status = UnixSimpleFileSystemFileInfo ( + PrivateFile, + FullFileName, + BufferSize, + Buffer + ); + free (FullFileName); + + PrivateFile->Dirent = NULL; + +Done: + return Status; +} + + + +/** + Write data to a file. + + @param This Protocol instance pointer. + @param BufferSize On input size of buffer, on output amount of data in buffer. + @param Buffer The buffer in which data to write. + + @retval EFI_SUCCESS Data was written. + @retval EFI_UNSUPPORTED Writes to Open directory are not supported. + @retval EFI_NO_MEDIA The device has no media. + @retval EFI_DEVICE_ERROR The device reported an error. + @retval EFI_DEVICE_ERROR An attempt was made to write to a deleted file. + @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. + @retval EFI_WRITE_PROTECTED The device is write protected. + @retval EFI_ACCESS_DENIED The file was open for read only. + @retval EFI_VOLUME_FULL The volume is full. + +**/ +EFI_STATUS +PosixFileWrite ( + IN EFI_FILE_PROTOCOL *This, + IN OUT UINTN *BufferSize, + IN VOID *Buffer + ) +{ + EMU_EFI_FILE_PRIVATE *PrivateFile; + int Res; + + + PrivateFile = EMU_EFI_FILE_PRIVATE_DATA_FROM_THIS (This); + + if (PrivateFile->fd < 0) { + return EFI_DEVICE_ERROR; + } + + if (PrivateFile->IsDirectoryPath) { + return EFI_UNSUPPORTED; + } + + if (PrivateFile->IsOpenedByRead) { + return EFI_ACCESS_DENIED; + } + + Res = write (PrivateFile->fd, Buffer, *BufferSize); + if (Res == (UINTN)-1) { + return ErrnoToEfiStatus (); + } + + *BufferSize = Res; + return EFI_SUCCESS; +} + + + +/** + Set a files current position + + @param This Protocol instance pointer. + @param Position Byte position from the start of the file. + + @retval EFI_SUCCESS Data was written. + @retval EFI_UNSUPPORTED Seek request for non-zero is not valid on open. + +**/ +EFI_STATUS +PosixFileSetPossition ( + IN EFI_FILE_PROTOCOL *This, + IN UINT64 Position + ) +{ + EMU_EFI_FILE_PRIVATE *PrivateFile; + off_t Pos; + + PrivateFile = EMU_EFI_FILE_PRIVATE_DATA_FROM_THIS (This); + + if (PrivateFile->IsDirectoryPath) { + if (Position != 0) { + return EFI_UNSUPPORTED; + } + + if (PrivateFile->Dir == NULL) { + return EFI_DEVICE_ERROR; + } + rewinddir (PrivateFile->Dir); + return EFI_SUCCESS; + } else { + if (Position == (UINT64) -1) { + Pos = lseek (PrivateFile->fd, 0, SEEK_END); + } else { + Pos = lseek (PrivateFile->fd, Position, SEEK_SET); + } + if (Pos == (off_t)-1) { + return ErrnoToEfiStatus (); + } + return EFI_SUCCESS; + } +} + + + +/** + Get a file's current position + + @param This Protocol instance pointer. + @param Position Byte position from the start of the file. + + @retval EFI_SUCCESS Data was written. + @retval EFI_UNSUPPORTED Seek request for non-zero is not valid on open.. + +**/ +EFI_STATUS +PosixFileGetPossition ( + IN EFI_FILE_PROTOCOL *This, + OUT UINT64 *Position + ) +{ + EFI_STATUS Status; + EMU_EFI_FILE_PRIVATE *PrivateFile; + + PrivateFile = EMU_EFI_FILE_PRIVATE_DATA_FROM_THIS (This); + + if (PrivateFile->IsDirectoryPath) { + Status = EFI_UNSUPPORTED; + } else { + *Position = (UINT64)lseek (PrivateFile->fd, 0, SEEK_CUR); + Status = (*Position == (UINT64) -1) ? ErrnoToEfiStatus () : EFI_SUCCESS; + } + + return Status; +} + + +/** + Get information about a file. + + @param This Protocol instance pointer. + @param InformationType Type of information to return in Buffer. + @param BufferSize On input size of buffer, on output amount of data in buffer. + @param Buffer The buffer to return data. + + @retval EFI_SUCCESS Data was returned. + @retval EFI_UNSUPPORTED InformationType is not supported. + @retval EFI_NO_MEDIA The device has no media. + @retval EFI_DEVICE_ERROR The device reported an error. + @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. + @retval EFI_WRITE_PROTECTED The device is write protected. + @retval EFI_ACCESS_DENIED The file was open for read only. + @retval EFI_BUFFER_TOO_SMALL Buffer was too small; required size returned in BufferSize. + +**/ +EFI_STATUS +PosixFileGetInfo ( + IN EFI_FILE_PROTOCOL *This, + IN EFI_GUID *InformationType, + IN OUT UINTN *BufferSize, + OUT VOID *Buffer + ) +{ + EFI_STATUS Status; + EMU_EFI_FILE_PRIVATE *PrivateFile; + EFI_FILE_SYSTEM_INFO *FileSystemInfoBuffer; + int UnixStatus; + EMU_SIMPLE_FILE_SYSTEM_PRIVATE *PrivateRoot; + struct statfs buf; + + PrivateFile = EMU_EFI_FILE_PRIVATE_DATA_FROM_THIS (This); + PrivateRoot = EMU_SIMPLE_FILE_SYSTEM_PRIVATE_DATA_FROM_THIS (PrivateFile->SimpleFileSystem); + + Status = EFI_SUCCESS; + if (CompareGuid (InformationType, &gEfiFileInfoGuid)) { + Status = UnixSimpleFileSystemFileInfo (PrivateFile, NULL, BufferSize, Buffer); + } else if (CompareGuid (InformationType, &gEfiFileSystemInfoGuid)) { + if (*BufferSize < SIZE_OF_EFI_FILE_SYSTEM_INFO + StrSize (PrivateRoot->VolumeLabel)) { + *BufferSize = SIZE_OF_EFI_FILE_SYSTEM_INFO + StrSize (PrivateRoot->VolumeLabel); + return EFI_BUFFER_TOO_SMALL; + } + + UnixStatus = statfs (PrivateFile->FileName, &buf); + if (UnixStatus < 0) { + return EFI_DEVICE_ERROR; + } + + FileSystemInfoBuffer = (EFI_FILE_SYSTEM_INFO *) Buffer; + FileSystemInfoBuffer->Size = SIZE_OF_EFI_FILE_SYSTEM_INFO + StrSize (PrivateRoot->VolumeLabel); + FileSystemInfoBuffer->ReadOnly = FALSE; + + // + // Succeeded + // + FileSystemInfoBuffer->VolumeSize = MultU64x32 (buf.f_blocks, buf.f_bsize); + FileSystemInfoBuffer->FreeSpace = MultU64x32 (buf.f_bavail, buf.f_bsize); + FileSystemInfoBuffer->BlockSize = buf.f_bsize; + + + StrCpy ((CHAR16 *) FileSystemInfoBuffer->VolumeLabel, PrivateRoot->VolumeLabel); + *BufferSize = SIZE_OF_EFI_FILE_SYSTEM_INFO + StrSize (PrivateRoot->VolumeLabel); + + } else if (CompareGuid (InformationType, &gEfiFileSystemVolumeLabelInfoIdGuid)) { + if (*BufferSize < StrSize (PrivateRoot->VolumeLabel)) { + *BufferSize = StrSize (PrivateRoot->VolumeLabel); + return EFI_BUFFER_TOO_SMALL; + } + + StrCpy ((CHAR16 *) Buffer, PrivateRoot->VolumeLabel); + *BufferSize = StrSize (PrivateRoot->VolumeLabel); + + } + + return Status; +} + + +/** + Set information about a file + + @param File Protocol instance pointer. + @param InformationType Type of information in Buffer. + @param BufferSize Size of buffer. + @param Buffer The data to write. + + @retval EFI_SUCCESS Data was returned. + @retval EFI_UNSUPPORTED InformationType is not supported. + @retval EFI_NO_MEDIA The device has no media. + @retval EFI_DEVICE_ERROR The device reported an error. + @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. + @retval EFI_WRITE_PROTECTED The device is write protected. + @retval EFI_ACCESS_DENIED The file was open for read only. + +**/ +EFI_STATUS +PosixFileSetInfo ( + IN EFI_FILE_PROTOCOL *This, + IN EFI_GUID *InformationType, + IN UINTN BufferSize, + IN VOID *Buffer + ) +{ + EMU_SIMPLE_FILE_SYSTEM_PRIVATE *PrivateRoot; + EMU_EFI_FILE_PRIVATE *PrivateFile; + EFI_FILE_INFO *OldFileInfo; + EFI_FILE_INFO *NewFileInfo; + EFI_STATUS Status; + UINTN OldInfoSize; + mode_t NewAttr; + struct stat OldAttr; + CHAR8 *OldFileName; + CHAR8 *NewFileName; + CHAR8 *CharPointer; + BOOLEAN AttrChangeFlag; + BOOLEAN NameChangeFlag; + BOOLEAN SizeChangeFlag; + BOOLEAN TimeChangeFlag; + struct tm NewLastAccessSystemTime; + struct tm NewLastWriteSystemTime; + EFI_FILE_SYSTEM_INFO *NewFileSystemInfo; + CHAR8 *AsciiFilePtr; + CHAR16 *UnicodeFilePtr; + int UnixStatus; + struct utimbuf Utime; + + + PrivateFile = EMU_EFI_FILE_PRIVATE_DATA_FROM_THIS (This); + PrivateRoot = EMU_SIMPLE_FILE_SYSTEM_PRIVATE_DATA_FROM_THIS (PrivateFile->SimpleFileSystem); + errno = 0; + Status = EFI_UNSUPPORTED; + OldFileInfo = NewFileInfo = NULL; + OldFileName = NewFileName = NULL; + AttrChangeFlag = NameChangeFlag = SizeChangeFlag = TimeChangeFlag = FALSE; + + // + // Set file system information. + // + if (CompareGuid (InformationType, &gEfiFileSystemInfoGuid)) { + if (BufferSize < (SIZE_OF_EFI_FILE_SYSTEM_INFO + StrSize (PrivateRoot->VolumeLabel))) { + Status = EFI_BAD_BUFFER_SIZE; + goto Done; + } + + NewFileSystemInfo = (EFI_FILE_SYSTEM_INFO *) Buffer; + + free (PrivateRoot->VolumeLabel); + + PrivateRoot->VolumeLabel = malloc (StrSize (NewFileSystemInfo->VolumeLabel)); + if (PrivateRoot->VolumeLabel == NULL) { + goto Done; + } + + StrCpy (PrivateRoot->VolumeLabel, NewFileSystemInfo->VolumeLabel); + + Status = EFI_SUCCESS; + goto Done; + } + + // + // Set volume label information. + // + if (CompareGuid (InformationType, &gEfiFileSystemVolumeLabelInfoIdGuid)) { + if (BufferSize < StrSize (PrivateRoot->VolumeLabel)) { + Status = EFI_BAD_BUFFER_SIZE; + goto Done; + } + + StrCpy (PrivateRoot->VolumeLabel, (CHAR16 *) Buffer); + + Status = EFI_SUCCESS; + goto Done; + } + + if (!CompareGuid (InformationType, &gEfiFileInfoGuid)) { + Status = EFI_UNSUPPORTED; + goto Done; + } + + if (BufferSize < SIZE_OF_EFI_FILE_INFO) { + Status = EFI_BAD_BUFFER_SIZE; + goto Done; + } + + // + // Set file/directory information. + // + + // + // Check for invalid set file information parameters. + // + NewFileInfo = (EFI_FILE_INFO *) Buffer; + if (NewFileInfo->Size <= sizeof (EFI_FILE_INFO) || + (NewFileInfo->Attribute &~(EFI_FILE_VALID_ATTR)) || + (sizeof (UINTN) == 4 && NewFileInfo->Size > 0xFFFFFFFF) + ) { + Status = EFI_INVALID_PARAMETER; + goto Done; + } + + // + // Get current file information so we can determine what kind + // of change request this is. + // + OldInfoSize = 0; + Status = UnixSimpleFileSystemFileInfo (PrivateFile, NULL, &OldInfoSize, NULL); + if (Status != EFI_BUFFER_TOO_SMALL) { + Status = EFI_DEVICE_ERROR; + goto Done; + } + + OldFileInfo = malloc (OldInfoSize); + if (OldFileInfo == NULL) { + goto Done; + } + + Status = UnixSimpleFileSystemFileInfo (PrivateFile, NULL, &OldInfoSize, OldFileInfo); + if (EFI_ERROR (Status)) { + goto Done; + } + + OldFileName = malloc (AsciiStrSize (PrivateFile->FileName)); + if (OldFileInfo == NULL) { + goto Done; + } + + AsciiStrCpy (OldFileName, PrivateFile->FileName); + + // + // Make full pathname from new filename and rootpath. + // + if (NewFileInfo->FileName[0] == '\\') { + NewFileName = malloc (AsciiStrLen (PrivateRoot->FilePath) + 1 + StrLen (NewFileInfo->FileName) + 1); + if (NewFileName == NULL) { + goto Done; + } + + AsciiStrCpy (NewFileName, PrivateRoot->FilePath); + AsciiFilePtr = NewFileName + AsciiStrLen(NewFileName); + UnicodeFilePtr = NewFileInfo->FileName + 1; + *AsciiFilePtr++ ='/'; + } else { + NewFileName = malloc (AsciiStrLen (PrivateFile->FileName) + 2 + StrLen (NewFileInfo->FileName) + 1); + if (NewFileName == NULL) { + goto Done; + } + + AsciiStrCpy (NewFileName, PrivateRoot->FilePath); + AsciiFilePtr = NewFileName + AsciiStrLen(NewFileName); + if ((AsciiFilePtr[-1] != '/') && (NewFileInfo->FileName[0] != '/')) { + // make sure there is a / between Root FilePath and NewFileInfo Filename + AsciiFilePtr[0] = '/'; + AsciiFilePtr[1] = '\0'; + AsciiFilePtr++; + } + UnicodeFilePtr = NewFileInfo->FileName; + } + // Convert to ascii. + while (*UnicodeFilePtr) { + *AsciiFilePtr++ = *UnicodeFilePtr++; + } + *AsciiFilePtr = 0; + + // + // Is there an attribute change request? + // + if (NewFileInfo->Attribute != OldFileInfo->Attribute) { + if ((NewFileInfo->Attribute & EFI_FILE_DIRECTORY) != (OldFileInfo->Attribute & EFI_FILE_DIRECTORY)) { + Status = EFI_INVALID_PARAMETER; + goto Done; + } + + AttrChangeFlag = TRUE; + } + + // + // Is there a name change request? + // bugbug: - Should really use EFI_UNICODE_COLLATION_PROTOCOL + // + if (StrCmp (NewFileInfo->FileName, OldFileInfo->FileName)) { + NameChangeFlag = TRUE; + } + + // + // Is there a size change request? + // + if (NewFileInfo->FileSize != OldFileInfo->FileSize) { + SizeChangeFlag = TRUE; + } + + // + // Is there a time stamp change request? + // + if (!IsZero (&NewFileInfo->CreateTime, sizeof (EFI_TIME)) && + CompareMem (&NewFileInfo->CreateTime, &OldFileInfo->CreateTime, sizeof (EFI_TIME)) + ) { + TimeChangeFlag = TRUE; + } else if (!IsZero (&NewFileInfo->LastAccessTime, sizeof (EFI_TIME)) && + CompareMem (&NewFileInfo->LastAccessTime, &OldFileInfo->LastAccessTime, sizeof (EFI_TIME)) + ) { + TimeChangeFlag = TRUE; + } else if (!IsZero (&NewFileInfo->ModificationTime, sizeof (EFI_TIME)) && + CompareMem (&NewFileInfo->ModificationTime, &OldFileInfo->ModificationTime, sizeof (EFI_TIME)) + ) { + TimeChangeFlag = TRUE; + } + + // + // All done if there are no change requests being made. + // + if (!(AttrChangeFlag || NameChangeFlag || SizeChangeFlag || TimeChangeFlag)) { + Status = EFI_SUCCESS; + goto Done; + } + + // + // Set file or directory information. + // + if (stat (OldFileName, &OldAttr) != 0) { + Status = ErrnoToEfiStatus (); + goto Done; + } + + // + // Name change. + // + if (NameChangeFlag) { + // + // Close the handles first + // + if (PrivateFile->IsOpenedByRead) { + Status = EFI_ACCESS_DENIED; + goto Done; + } + + for (CharPointer = NewFileName; *CharPointer != 0 && *CharPointer != L'/'; CharPointer++) { + } + + if (*CharPointer != 0) { + Status = EFI_ACCESS_DENIED; + goto Done; + } + + UnixStatus = rename (OldFileName, NewFileName); + if (UnixStatus == 0) { + // + // modify file name + // + free (PrivateFile->FileName); + + PrivateFile->FileName = malloc (AsciiStrSize (NewFileName)); + if (PrivateFile->FileName == NULL) { + goto Done; + } + + AsciiStrCpy (PrivateFile->FileName, NewFileName); + } else { + Status = EFI_DEVICE_ERROR; + goto Done; + } + } + + // + // Size change + // + if (SizeChangeFlag) { + if (PrivateFile->IsDirectoryPath) { + Status = EFI_UNSUPPORTED; + goto Done; + } + + if (PrivateFile->IsOpenedByRead || OldFileInfo->Attribute & EFI_FILE_READ_ONLY) { + Status = EFI_ACCESS_DENIED; + goto Done; + } + + if (ftruncate (PrivateFile->fd, NewFileInfo->FileSize) != 0) { + Status = ErrnoToEfiStatus (); + goto Done; + } + + } + + // + // Time change + // + if (TimeChangeFlag) { + NewLastAccessSystemTime.tm_year = NewFileInfo->LastAccessTime.Year; + NewLastAccessSystemTime.tm_mon = NewFileInfo->LastAccessTime.Month; + NewLastAccessSystemTime.tm_mday = NewFileInfo->LastAccessTime.Day; + NewLastAccessSystemTime.tm_hour = NewFileInfo->LastAccessTime.Hour; + NewLastAccessSystemTime.tm_min = NewFileInfo->LastAccessTime.Minute; + NewLastAccessSystemTime.tm_sec = NewFileInfo->LastAccessTime.Second; + NewLastAccessSystemTime.tm_isdst = 0; + + Utime.actime = mktime (&NewLastAccessSystemTime); + + NewLastWriteSystemTime.tm_year = NewFileInfo->ModificationTime.Year; + NewLastWriteSystemTime.tm_mon = NewFileInfo->ModificationTime.Month; + NewLastWriteSystemTime.tm_mday = NewFileInfo->ModificationTime.Day; + NewLastWriteSystemTime.tm_hour = NewFileInfo->ModificationTime.Hour; + NewLastWriteSystemTime.tm_min = NewFileInfo->ModificationTime.Minute; + NewLastWriteSystemTime.tm_sec = NewFileInfo->ModificationTime.Second; + NewLastWriteSystemTime.tm_isdst = 0; + + Utime.modtime = mktime (&NewLastWriteSystemTime); + + if (Utime.actime == (time_t)-1 || Utime.modtime == (time_t)-1) { + goto Done; + } + + if (utime (PrivateFile->FileName, &Utime) == -1) { + Status = ErrnoToEfiStatus (); + goto Done; + } + } + + // + // No matter about AttrChangeFlag, Attribute must be set. + // Because operation before may cause attribute change. + // + NewAttr = OldAttr.st_mode; + + if (NewFileInfo->Attribute & EFI_FILE_READ_ONLY) { + NewAttr &= ~(S_IRUSR | S_IRGRP | S_IROTH); + } else { + NewAttr |= S_IRUSR; + } + + if (chmod (NewFileName, NewAttr) != 0) { + Status = ErrnoToEfiStatus (); + } + +Done: + if (OldFileInfo != NULL) { + free (OldFileInfo); + } + + if (OldFileName != NULL) { + free (OldFileName); + } + + if (NewFileName != NULL) { + free (NewFileName); + } + + return Status; +} + + +/** + Flush data back for the file handle. + + @param This Protocol instance pointer. + + @retval EFI_SUCCESS Data was written. + @retval EFI_UNSUPPORTED Writes to Open directory are not supported. + @retval EFI_NO_MEDIA The device has no media. + @retval EFI_DEVICE_ERROR The device reported an error. + @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted. + @retval EFI_WRITE_PROTECTED The device is write protected. + @retval EFI_ACCESS_DENIED The file was open for read only. + @retval EFI_VOLUME_FULL The volume is full. + +**/ +EFI_STATUS +PosixFileFlush ( + IN EFI_FILE_PROTOCOL *This + ) +{ + EMU_EFI_FILE_PRIVATE *PrivateFile; + + + PrivateFile = EMU_EFI_FILE_PRIVATE_DATA_FROM_THIS (This); + + if (PrivateFile->IsDirectoryPath) { + return EFI_UNSUPPORTED; + } + + if (PrivateFile->IsOpenedByRead) { + return EFI_ACCESS_DENIED; + } + + if (PrivateFile->fd < 0) { + return EFI_DEVICE_ERROR; + } + + if (fsync (PrivateFile->fd) != 0) { + return ErrnoToEfiStatus (); + } + + return EFI_SUCCESS; +} + + + +EFI_STATUS +PosixFileSystmeThunkOpen ( + IN EMU_IO_THUNK_PROTOCOL *This + ) +{ + EMU_SIMPLE_FILE_SYSTEM_PRIVATE *Private; + UINTN i; + + if (This->Private != NULL) { + return EFI_ALREADY_STARTED; + } + + if (!CompareGuid (This->Protocol, &gEfiSimpleFileSystemProtocolGuid)) { + return EFI_UNSUPPORTED; + } + + Private = malloc (sizeof (EMU_SIMPLE_FILE_SYSTEM_PRIVATE)); + if (Private == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + Private->FilePath = malloc (StrLen (This->ConfigString) + 1); + if (Private->FilePath == NULL) { + free (Private); + return EFI_OUT_OF_RESOURCES; + } + + // Convert Unicode to Ascii + for (i = 0; This->ConfigString[i] != 0; i++) { + Private->FilePath[i] = This->ConfigString[i]; + } + Private->FilePath[i] = 0; + + + Private->VolumeLabel = malloc (StrLen (L"EFI_EMULATED")); + if (Private->VolumeLabel == NULL) { + free (Private->FilePath); + free (Private); + return EFI_OUT_OF_RESOURCES; + } + StrCpy (Private->VolumeLabel, L"EFI_EMULATED"); + + Private->Signature = EMU_SIMPLE_FILE_SYSTEM_PRIVATE_SIGNATURE; + Private->Thunk = This; + CopyMem (&Private->SimpleFileSystem, &gPosixFileSystemProtocol, sizeof (Private->SimpleFileSystem)); + Private->FileHandlesOpen = FALSE; + + This->Interface = &Private->SimpleFileSystem; + This->Private = Private; + return EFI_SUCCESS; +} + + +EFI_STATUS +PosixFileSystmeThunkClose ( + IN EMU_IO_THUNK_PROTOCOL *This + ) +{ + EMU_SIMPLE_FILE_SYSTEM_PRIVATE *Private; + + if (!CompareGuid (This->Protocol, &gEfiSimpleFileSystemProtocolGuid)) { + return EFI_UNSUPPORTED; + } + + Private = This->Private; + + if (Private->FileHandlesOpen) { + // + // Close only supported if all the EFI_FILE_HANDLEs have been closed. + // + return EFI_NOT_READY; + } + + if (This->Private != NULL) { + if (Private->VolumeLabel == NULL) { + free (Private->VolumeLabel); + } + free (This->Private); + } + + return EFI_SUCCESS; +} + + +EMU_IO_THUNK_PROTOCOL gPosixFileSystemThunkIo = { + &gEfiSimpleFileSystemProtocolGuid, + NULL, + NULL, + 0, + GasketPosixFileSystmeThunkOpen, + GasketPosixFileSystmeThunkClose, + NULL +}; + + diff --git a/InOsEmuPkg/Unix/Sec/Pthreads.c b/InOsEmuPkg/Unix/Sec/Pthreads.c new file mode 100644 index 0000000..273be5d --- /dev/null +++ b/InOsEmuPkg/Unix/Sec/Pthreads.c @@ -0,0 +1,233 @@ +/*++ @file + POSIX Pthreads to emulate APs and implement threads + +Copyright (c) 2011, Apple Inc. 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. + + +**/ + +#include "SecMain.h" +#include <pthread.h> + + +UINTN +EFIAPI +PthreadMutexLock ( + IN VOID *Mutex + ) +{ + return (UINTN)pthread_mutex_lock ((pthread_mutex_t *)Mutex); +} + + + +UINTN +EFIAPI +PthreadMutexUnLock ( + IN VOID *Mutex + ) +{ + return (UINTN)pthread_mutex_unlock ((pthread_mutex_t *)Mutex); +} + + +UINTN +EFIAPI +PthreadMutexTryLock ( + IN VOID *Mutex + ) +{ + return (UINTN)pthread_mutex_trylock ((pthread_mutex_t *)Mutex); +} + + +VOID * +PthreadMutexInit ( + IN VOID + ) +{ + pthread_mutex_t *Mutex; + int err; + + Mutex = malloc (sizeof (pthread_mutex_t)); + err = pthread_mutex_init (Mutex, NULL); + if (err == 0) { + return Mutex; + } + + return NULL; +} + + +UINTN +PthreadMutexDestroy ( + IN VOID *Mutex + ) +{ + if (Mutex != NULL) { + return pthread_mutex_destroy ((pthread_mutex_t *)Mutex); + } + + return -1; +} + +// Can't store this data on PthreadCreate stack so we need a global +typedef struct { + pthread_mutex_t Mutex; + PTREAD_THUNK_THEAD_ENTRY Start; +} THREAD_MANGLE; + +THREAD_MANGLE mThreadMangle = { + PTHREAD_MUTEX_INITIALIZER, + NULL +}; + +VOID * +SecFakePthreadStart ( + VOID *Context + ) +{ + PTREAD_THUNK_THEAD_ENTRY Start; + sigset_t SigMask; + + // Save global on the stack before we unlock + Start = mThreadMangle.Start; + pthread_mutex_unlock (&mThreadMangle.Mutex); + + // Mask all signals to the APs + sigfillset (&SigMask); + pthread_sigmask (SIG_BLOCK, &SigMask, NULL); + + // + // We have to start the thread in SEC as we need to follow + // OS X calling conventions. We can then call back into + // to the callers Start. + // + // This is a great example of how all problems in computer + // science can be solved by adding another level of indirection + // + return (VOID *)ReverseGasketUint64 ((CALL_BACK)Start, (UINTN)Context); +} + +UINTN +PthreadCreate ( + IN VOID *Thread, + IN VOID *Attribute, + IN PTREAD_THUNK_THEAD_ENTRY Start, + IN VOID *Context + ) +{ + int err; + BOOLEAN EnabledOnEntry; + + // + // Threads inherit interrupt state so disable interrupts before we start thread + // + if (SecInterruptEanbled ()) { + SecDisableInterrupt (); + EnabledOnEntry = TRUE; + } else { + EnabledOnEntry = FALSE; + } + + // Aquire lock for global, SecFakePthreadStart runs in a different thread. + pthread_mutex_lock (&mThreadMangle.Mutex); + mThreadMangle.Start = Start; + + err = pthread_create (Thread, Attribute, SecFakePthreadStart, Context); + if (err != 0) { + // Thread failed to launch so release the lock; + pthread_mutex_unlock (&mThreadMangle.Mutex); + } + + if (EnabledOnEntry) { + // Restore interrupt state + SecEnableInterrupt (); + } + + return err; +} + + +VOID +PthreadExit ( + IN VOID *ValuePtr + ) +{ + pthread_exit (ValuePtr); + return; +} + + +UINTN +PthreadSelf ( + VOID + ) +{ + // POSIX currently allows pthread_t to be a structure or arithmetic type. + // Check out sys/types.h to make sure this will work if you are porting. + // On OS X (Darwin) pthread_t is a pointer to a structure so this code works. + return (UINTN)pthread_self (); +} + + +EMU_PTREAD_THUNK_PROTOCOL gPthreadThunk = { + GasketPthreadMutexLock, + GasketPthreadMutexUnLock, + GasketPthreadMutexTryLock, + GasketPthreadMutexInit, + GasketPthreadMutexDestroy, + GasketPthreadCreate, + GasketPthreadExit, + GasketPthreadSelf +}; + + +EFI_STATUS +PthreadOpen ( + IN EMU_IO_THUNK_PROTOCOL *This + ) +{ + if (This->Instance != 0) { + // Only single instance is supported + return EFI_NOT_FOUND; + } + + if (This->ConfigString[0] == L'0') { + // If AP count is zero no need for threads + return EFI_NOT_FOUND; + } + + This->Interface = &gPthreadThunk; + + return EFI_SUCCESS; +} + + +EFI_STATUS +PthreadClose ( + IN EMU_IO_THUNK_PROTOCOL *This + ) +{ + return EFI_SUCCESS; +} + + +EMU_IO_THUNK_PROTOCOL gPthreadThunkIo = { + &gEmuPthreadThunkProtocolGuid, + NULL, + NULL, + 0, + GasketPthreadOpen, + GasketPthreadClose, + NULL +}; + + diff --git a/InOsEmuPkg/Unix/Sec/SecMain.c b/InOsEmuPkg/Unix/Sec/SecMain.c new file mode 100644 index 0000000..8677ab5 --- /dev/null +++ b/InOsEmuPkg/Unix/Sec/SecMain.c @@ -0,0 +1,1148 @@ +/*++ @file + +Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR> +Portions copyright (c) 2008 - 2011, Apple Inc. All rights reserved.<BR> +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. + +**/ + +#include "SecMain.h" + +#ifdef __APPLE__ +#define MAP_ANONYMOUS MAP_ANON +char *gGdbWorkingFileName = NULL; +#endif + + +// +// Globals +// + +EMU_THUNK_PPI mSecEmuThunkPpi = { + GasketSecUnixPeiAutoScan, + GasketSecUnixFdAddress, + GasketSecEmuThunkAddress, + GasketSecUnixPeiLoadFile +}; + +EFI_PEI_TEMPORARY_RAM_SUPPORT_PPI mSecTemporaryRamSupportPpi = { + GasketSecTemporaryRamSupport +}; + + + +// +// 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; +EMU_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; +EMU_SYSTEM_MEMORY *gSystemMemory; + + + +UINTN mImageContextModHandleArraySize = 0; +IMAGE_CONTEXT_TO_MOD_HANDLE *mImageContextModHandleArray = NULL; + + + +EFI_PHYSICAL_ADDRESS * +MapMemory ( + INTN fd, + UINT64 length, + INTN prot, + INTN flags); + +EFI_STATUS +MapFile ( + IN CHAR8 *FileName, + IN OUT EFI_PHYSICAL_ADDRESS *BaseAddress, + OUT UINT64 *Length + ); + +EFI_STATUS +EFIAPI +SecNt32PeCoffRelocateImage ( + IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext + ); + + +int +main ( + IN int Argc, + IN char **Argv, + IN char **Envp + ) +/*++ + +Routine Description: + Main entry point to SEC for Unix. 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 *) PcdGetPtr (PcdEmuMemorySize); + FirmwareVolumesStr = (CHAR16 *) PcdGetPtr (PcdEmuFirmwareVolume); + + printf ("\nEDK SEC Main UNIX Emulation Environment from edk2.sourceforge.net\n"); + + // + // PPIs pased into PEI_CORE + // + AddThunkPpi (EFI_PEI_PPI_DESCRIPTOR_PPI, &gEfiTemporaryRamSupportPpiGuid, &mSecTemporaryRamSupportPpi); + AddThunkPpi (EFI_PEI_PPI_DESCRIPTOR_PPI, &gEmuThunkPpiGuid, &mSecEmuThunkPpi); + AddThunkPpi (EFI_PEI_PPI_DESCRIPTOR_PPI, &gEmuPeiServicesTableUpdatePpiGuid, NULL); + + SecInitThunkProtocol (); + + // + // Emulator Bus Driver Thunks + // + AddThunkProtocol (&gX11ThunkIo, (CHAR16 *)PcdGetPtr (PcdEmuGop), TRUE); + AddThunkProtocol (&gPosixFileSystemThunkIo, (CHAR16 *)PcdGetPtr (PcdEmuFileSystem), TRUE); + + // + // Emulator other Thunks + // + AddThunkProtocol (&gPthreadThunkIo, (CHAR16 *)PcdGetPtr (PcdEmuApCount), FALSE); + + // EmuSecLibConstructor (); + +#ifdef __APPLE__ + // + // We can't use dlopen on OS X, so we need a scheme to get symboles into gdb + // We need to create a temp file that contains gdb commands so we can load + // symbols when we load every PE/COFF image. + // + Index = strlen (*Argv); + gGdbWorkingFileName = malloc (Index + strlen(".gdb") + 1); + strcpy (gGdbWorkingFileName, *Argv); + strcat (gGdbWorkingFileName, ".gdb"); +#endif + + + // + // Allocate space for gSystemMemory Array + // + gSystemMemoryCount = CountSeperatorsInString (MemorySizeStr, '!') + 1; + gSystemMemory = calloc (gSystemMemoryCount, sizeof (EMU_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 (EMU_FD_INFO)); + if (gFdInfo == NULL) { + printf ("ERROR : Can not allocate memory for fd info. Exiting.\n"); + exit (1); + } + + printf (" BootMode 0x%02x\n", (unsigned int)PcdGet32 (PcdEmuBootMode)); + + // + // 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 UnixOpenFile will allocate a new mapping + // + InitialStackMemorySize = STACK_SIZE; + InitialStackMemory = (UINTN)MapMemory(0, + (UINT32) InitialStackMemorySize, + PROT_READ | PROT_WRITE | PROT_EXEC, + 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", + (unsigned int)(InitialStackMemorySize / 1024), + (unsigned long)InitialStackMemory); + + for (StackPointer = (UINTN*) (UINTN) InitialStackMemory; + StackPointer < (UINTN*)(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, (unsigned int)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 Unix 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); + + + 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; +} + + + +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); + + + // + // 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 = PcdGet32 (PcdEmuFirmwareFdSize); + 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 = SecUnixPeiLoadFile ( + PeiCorePe32File, + &PeiImageAddress, + &PeiCoreSize, + &PeiCoreEntryPoint + ); + if (EFI_ERROR (Status)) { + return ; + } + + // + // Transfer control to the PEI Core + // + PeiSwitchStacks ( + (SWITCH_STACK_ENTRY_POINT) (UINTN) PeiCoreEntryPoint, + SecCoreData, + (VOID *)GetThunkPpiList (), + NULL, + TopOfStack + ); + // + // If we get here, then the PEI Core returned. This is an error + // + return ; +} + +EFI_STATUS +EFIAPI +SecUnixPeiAutoScan ( + 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 + UnixOpenFile. + +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 +SecEmuThunkAddress ( + VOID + ) +/*++ + +Routine Description: + Since the SEC is the only Unix program in stack it must export + an interface to do POSIX calls. gUnix is initailized in UnixThunk.c. + +Arguments: + InterfaceSize - sizeof (EFI_WIN_NT_THUNK_PROTOCOL); + InterfaceBase - Address of the gUnix global + +Returns: + EFI_SUCCESS - Data returned + +**/ +{ + return &gEmuThunkProtocol; +} + + +EFI_STATUS +SecUnixPeiLoadFile ( + IN VOID *Pe32Data, + OUT EFI_PHYSICAL_ADDRESS *ImageAddress, + OUT UINT64 *ImageSize, + OUT 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 = PeCoffLoaderGetImageInfo (&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) MapMemory ( + 0, + (UINT32) (ImageContext.ImageSize + (ImageContext.SectionAlignment * 2)), + PROT_READ | PROT_WRITE | PROT_EXEC, + MAP_ANONYMOUS | MAP_PRIVATE + ); + if (ImageContext.ImageAddress == 0) { + return EFI_OUT_OF_RESOURCES; + } + + // + // Align buffer on section boundry + // + ImageContext.ImageAddress += ImageContext.SectionAlignment - 1; + ImageContext.ImageAddress &= ~((EFI_PHYSICAL_ADDRESS)(ImageContext.SectionAlignment - 1)); + + + Status = PeCoffLoaderLoadImage (&ImageContext); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = PeCoffLoaderRelocateImage (&ImageContext); + if (EFI_ERROR (Status)) { + return Status; + } + + + SecPeCoffRelocateImageExtraAction (&ImageContext); + + // + // BugBug: Flush Instruction Cache Here when CPU Lib is ready + // + + *ImageAddress = ImageContext.ImageAddress; + *ImageSize = ImageContext.ImageSize; + *EntryPoint = ImageContext.EntryPoint; + + return EFI_SUCCESS; +} + + +RETURN_STATUS +EFIAPI +SecPeCoffGetEntryPoint ( + IN VOID *Pe32Data, + IN OUT VOID **EntryPoint + ) +{ + EFI_STATUS Status; + EFI_PHYSICAL_ADDRESS ImageAddress; + UINT64 ImageSize; + EFI_PHYSICAL_ADDRESS PhysEntryPoint; + + Status = SecUnixPeiLoadFile (Pe32Data, &ImageAddress, &ImageSize, &PhysEntryPoint); + + *EntryPoint = (VOID *)(UINTN)PhysEntryPoint; + return Status; +} + + + +EFI_STATUS +EFIAPI +SecUnixFdAddress ( + IN UINTN Index, + IN OUT EFI_PHYSICAL_ADDRESS *FdBase, + IN OUT UINT64 *FdSize, + IN OUT EFI_PHYSICAL_ADDRESS *FixUp + ) +/*++ + +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 + FixUp - Difference between actual FD address and build address + +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; + *FixUp = 0; + + if (*FdBase == 0 && *FdSize == 0) { + return EFI_UNSUPPORTED; + } + + if (Index == 0) { + // + // FD 0 has XIP code and well known PCD values + // If the memory buffer could not be allocated at the FD build address + // the Fixup is the difference. + // + *FixUp = *FdBase - PcdGet64 (PcdEmuFdBaseAddress); + } + + 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 +AddHandle ( + IN PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext, + IN VOID *ModHandle + ) +/*++ + +Routine Description: + Store the ModHandle in an array indexed by the Pdb File name. + The ModHandle is needed to unload the image. + +Arguments: + ImageContext - Input data returned from PE Laoder Library. Used to find the + .PDB file name of the PE Image. + ModHandle - Returned from LoadLibraryEx() and stored for call to + FreeLibrary(). + +Returns: + EFI_SUCCESS - ModHandle was stored. + +**/ +{ + UINTN Index; + IMAGE_CONTEXT_TO_MOD_HANDLE *Array; + UINTN PreviousSize; + + + Array = mImageContextModHandleArray; + for (Index = 0; Index < mImageContextModHandleArraySize; Index++, Array++) { + if (Array->ImageContext == NULL) { + // + // Make a copy of the stirng and store the ModHandle + // + Array->ImageContext = ImageContext; + Array->ModHandle = ModHandle; + return EFI_SUCCESS; + } + } + + // + // No free space in mImageContextModHandleArray so grow it by + // IMAGE_CONTEXT_TO_MOD_HANDLE entires. realloc will + // copy the old values to the new locaiton. But it does + // not zero the new memory area. + // + PreviousSize = mImageContextModHandleArraySize * sizeof (IMAGE_CONTEXT_TO_MOD_HANDLE); + mImageContextModHandleArraySize += MAX_IMAGE_CONTEXT_TO_MOD_HANDLE_ARRAY_SIZE; + + mImageContextModHandleArray = realloc (mImageContextModHandleArray, mImageContextModHandleArraySize * sizeof (IMAGE_CONTEXT_TO_MOD_HANDLE)); + if (mImageContextModHandleArray == NULL) { + ASSERT (FALSE); + return EFI_OUT_OF_RESOURCES; + } + + memset (mImageContextModHandleArray + PreviousSize, 0, MAX_IMAGE_CONTEXT_TO_MOD_HANDLE_ARRAY_SIZE * sizeof (IMAGE_CONTEXT_TO_MOD_HANDLE)); + + return AddHandle (ImageContext, ModHandle); +} + + +VOID * +RemoveHandle ( + IN PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext + ) +/*++ + +Routine Description: + Return the ModHandle and delete the entry in the array. + +Arguments: + ImageContext - Input data returned from PE Laoder Library. Used to find the + .PDB file name of the PE Image. + +Returns: + ModHandle - ModHandle assoicated with ImageContext is returned + NULL - No ModHandle associated with ImageContext + +**/ +{ + UINTN Index; + IMAGE_CONTEXT_TO_MOD_HANDLE *Array; + + if (ImageContext->PdbPointer == NULL) { + // + // If no PDB pointer there is no ModHandle so return NULL + // + return NULL; + } + + Array = mImageContextModHandleArray; + for (Index = 0; Index < mImageContextModHandleArraySize; Index++, Array++) { + if (Array->ImageContext == ImageContext) { + // + // If you find a match return it and delete the entry + // + Array->ImageContext = NULL; + return Array->ModHandle; + } + } + + return NULL; +} + + + +// +// Target for gdb breakpoint in a script that uses gGdbWorkingFileName to source a +// add-symbol-file command. Hey what can you say scripting in gdb is not that great.... +// +// Put .gdbinit in the CWD where you do gdb SecMain.dll for source level debug +// +// cat .gdbinit +// b SecGdbScriptBreak +// command +// silent +// source SecMain.dll.gdb +// c +// end +// +VOID +SecGdbScriptBreak ( + VOID + ) +{ +} + +VOID +SecUnixLoaderBreak ( + VOID + ) +{ +} + +BOOLEAN +IsPdbFile ( + IN CHAR8 *PdbFileName + ) +{ + UINTN Len; + + if (PdbFileName == NULL) { + return FALSE; + } + + Len = strlen (PdbFileName); + if ((Len < 5)|| (PdbFileName[Len - 4] != '.')) { + return FALSE; + } + + if ((PdbFileName[Len - 3] == 'P' || PdbFileName[Len - 3] == 'p') && + (PdbFileName[Len - 2] == 'D' || PdbFileName[Len - 2] == 'd') && + (PdbFileName[Len - 1] == 'B' || PdbFileName[Len - 1] == 'b')) { + return TRUE; + } + + return FALSE; +} + + +#define MAX_SPRINT_BUFFER_SIZE 0x200 + +void +PrintLoadAddress ( + IN PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext + ) +{ + if (ImageContext->PdbPointer == NULL) { + fprintf (stderr, + "0x%08lx Loading NO DEBUG with entry point 0x%08lx\n", + (unsigned long)(ImageContext->ImageAddress), + (unsigned long)ImageContext->EntryPoint + ); + } else { + fprintf (stderr, + "0x%08lx Loading %s with entry point 0x%08lx\n", + (unsigned long)(ImageContext->ImageAddress + ImageContext->SizeOfHeaders), + ImageContext->PdbPointer, + (unsigned long)ImageContext->EntryPoint + ); + } + // Keep output synced up + fflush (stderr); +} + + +VOID +EFIAPI +SecPeCoffRelocateImageExtraAction ( + IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext + ) +{ + +#ifdef __APPLE__ + BOOLEAN EnabledOnEntry; + + // + // Make sure writting of the file is an atomic operation + // + if (SecInterruptEanbled ()) { + SecDisableInterrupt (); + EnabledOnEntry = TRUE; + } else { + EnabledOnEntry = FALSE; + } + + PrintLoadAddress (ImageContext); + + // + // In mach-o (OS X executable) dlopen() can only load files in the MH_DYLIB of MH_BUNDLE format. + // To convert to PE/COFF we need to construct a mach-o with the MH_PRELOAD format. We create + // .dSYM files for the PE/COFF images that can be used by gdb for source level debugging. + // + FILE *GdbTempFile; + + // + // In the Mach-O to PE/COFF conversion the size of the PE/COFF headers is not accounted for. + // Thus we need to skip over the PE/COFF header when giving load addresses for our symbol table. + // + if (ImageContext->PdbPointer != NULL && !IsPdbFile (ImageContext->PdbPointer)) { + // + // Now we have a database of the images that are currently loaded + // + + // + // 'symbol-file' will clear out currnet symbol mappings in gdb. + // you can do a 'add-symbol-file filename address' for every image we loaded to get source + // level debug in gdb. Note Sec, being a true application will work differently. + // + // We add the PE/COFF header size into the image as the mach-O does not have a header in + // loaded into system memory. + // + // This gives us a data base of gdb commands and after something is unloaded that entry will be + // removed. We don't yet have the scheme of how to comunicate with gdb, but we have the + // data base of info ready to roll. + // + // We could use qXfer:libraries:read, but OS X GDB does not currently support it. + // <library-list> + // <library name="/lib/libc.so.6"> // ImageContext->PdbPointer + // <segment address="0x10000000"/> // ImageContext->ImageAddress + ImageContext->SizeOfHeaders + // </library> + // </library-list> + // + + // + // Write the file we need for the gdb script + // + GdbTempFile = fopen (gGdbWorkingFileName, "w"); + if (GdbTempFile != NULL) { + fprintf (GdbTempFile, "add-symbol-file %s 0x%08lx\n", ImageContext->PdbPointer, (long unsigned int)(ImageContext->ImageAddress + ImageContext->SizeOfHeaders)); + fclose (GdbTempFile); + + // + // Target for gdb breakpoint in a script that uses gGdbWorkingFileName to set a breakpoint. + // Hey what can you say scripting in gdb is not that great.... + // + SecGdbScriptBreak (); + } else { + ASSERT (FALSE); + } + + AddHandle (ImageContext, ImageContext->PdbPointer); + + if (EnabledOnEntry) { + SecEnableInterrupt (); + } + + + } + +#else + + void *Handle = NULL; + void *Entry = NULL; + + if (ImageContext->PdbPointer == NULL) { + return; + } + + if (!IsPdbFile (ImageContext->PdbPointer)) { + return; + } + + fprintf (stderr, + "Loading %s 0x%08lx - entry point 0x%08lx\n", + ImageContext->PdbPointer, + (unsigned long)ImageContext->ImageAddress, + (unsigned long)ImageContext->EntryPoint); + + Handle = dlopen (ImageContext->PdbPointer, RTLD_NOW); + + if (Handle) { + Entry = dlsym (Handle, "_ModuleEntryPoint"); + } else { + printf("%s\n", dlerror()); + } + + if (Entry != NULL) { + ImageContext->EntryPoint = (UINTN)Entry; + printf("Change %s Entrypoint to :0x%08lx\n", ImageContext->PdbPointer, (unsigned long)Entry); + } + + SecUnixLoaderBreak (); + +#endif + + return; +} + + +VOID +EFIAPI +SecPeCoffUnloadImageExtraAction ( + IN PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext + ) +{ + VOID *Handle; + + Handle = RemoveHandle (ImageContext); + +#ifdef __APPLE__ + FILE *GdbTempFile; + BOOLEAN EnabledOnEntry; + + if (Handle != NULL) { + // + // Need to skip .PDB files created from VC++ + // + if (!IsPdbFile (ImageContext->PdbPointer)) { + if (SecInterruptEanbled ()) { + SecDisableInterrupt (); + EnabledOnEntry = TRUE; + } else { + EnabledOnEntry = FALSE; + } + + // + // Write the file we need for the gdb script + // + GdbTempFile = fopen (gGdbWorkingFileName, "w"); + if (GdbTempFile != NULL) { + fprintf (GdbTempFile, "remove-symbol-file %s\n", ImageContext->PdbPointer); + fclose (GdbTempFile); + + // + // Target for gdb breakpoint in a script that uses gGdbWorkingFileName to set a breakpoint. + // Hey what can you say scripting in gdb is not that great.... + // + SecGdbScriptBreak (); + } else { + ASSERT (FALSE); + } + + if (EnabledOnEntry) { + SecEnableInterrupt (); + } + } + } + +#else + // + // Don't want to confuse gdb with symbols for something that got unloaded + // + if (Handle != NULL) { + dlclose (Handle); + } + +#endif + return; +} + + diff --git a/InOsEmuPkg/Unix/Sec/SecMain.h b/InOsEmuPkg/Unix/Sec/SecMain.h new file mode 100644 index 0000000..6e352b1 --- /dev/null +++ b/InOsEmuPkg/Unix/Sec/SecMain.h @@ -0,0 +1,306 @@ +/*++ @file
+
+Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>
+Portions copyright (c) 2008 - 2011, Apple Inc. All rights reserved.<BR>
+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.
+
+**/
+
+#ifndef _SEC_MAIN_H__
+#define _SEC_MAIN_H__
+
+#include <PiPei.h>
+#include <Uefi.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>
+#include <Library/ReportStatusCodeLib.h>
+
+#include <Library/ThunkPpiList.h>
+#include <Library/ThunkProtocolList.h>
+
+#include <Ppi/EmuThunk.h>
+#include <Ppi/StatusCode.h>
+#include <Ppi/TemporaryRamSupport.h>
+#include <Ppi/EmuPeiServicesTableUpdate.h>
+
+#include <Protocol/SimplePointer.h>
+#include <Protocol/SimpleTextIn.h>
+#include <Protocol/SimpleTextInEx.h>
+#include <Protocol/UgaDraw.h>
+#include <Protocol/SimpleFileSystem.h>
+
+#include <Protocol/EmuThunk.h>
+#include <Protocol/EmuIoThunk.h>
+#include <Protocol/EmuGraphicsWindow.h>
+#include <Protocol/EmuPthreadThunk.h>
+
+#include <Guid/FileInfo.h>
+#include <Guid/FileSystemInfo.h>
+#include <Guid/FileSystemVolumeLabelInfo.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/termios.h>
+#include <sys/time.h>
+
+#if __CYGWIN__
+#include <sys/dirent.h>
+#else
+#include <sys/dir.h>
+#endif
+
+#include <sys/mman.h>
+#include <dlfcn.h>
+
+#include <unistd.h>
+#include <poll.h>
+#include <fcntl.h>
+#include <time.h>
+#include <signal.h>
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/ioctl.h>
+
+#include <sys/socket.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <net/if.h>
+#include <ifaddrs.h>
+
+#ifdef __APPLE__
+#include <net/if_dl.h>
+#include <net/bpf.h>
+#include <sys/param.h>
+#include <sys/mount.h>
+#define _XOPEN_SOURCE
+#ifndef _Bool
+ #define _Bool char // for clang debug
+#endif
+#else
+#include <termio.h>
+#include <sys/vfs.h>
+#endif
+
+#include <utime.h>
+
+#include "Gasket.h"
+
+
+#define STACK_SIZE 0x20000
+
+typedef struct {
+ EFI_PHYSICAL_ADDRESS Address;
+ UINT64 Size;
+} EMU_FD_INFO;
+
+typedef struct {
+ EFI_PHYSICAL_ADDRESS Memory;
+ UINT64 Size;
+} EMU_SYSTEM_MEMORY;
+
+
+#define MAX_IMAGE_CONTEXT_TO_MOD_HANDLE_ARRAY_SIZE 0x100
+
+typedef struct {
+ PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext;
+ VOID *ModHandle;
+} IMAGE_CONTEXT_TO_MOD_HANDLE;
+
+
+EFI_STATUS
+EFIAPI
+SecUnixPeiLoadFile (
+ VOID *Pe32Data,
+ EFI_PHYSICAL_ADDRESS *ImageAddress,
+ UINT64 *ImageSize,
+ EFI_PHYSICAL_ADDRESS *EntryPoint
+ );
+
+int
+main (
+ IN int Argc,
+ IN char **Argv,
+ IN char **Envp
+ );
+
+VOID
+SecLoadFromCore (
+ IN UINTN LargestRegion,
+ IN UINTN LargestRegionSize,
+ IN UINTN BootFirmwareVolumeBase,
+ IN VOID *PeiCoreFile
+ );
+
+EFI_STATUS
+SecLoadFile (
+ IN VOID *Pe32Data,
+ IN EFI_PHYSICAL_ADDRESS *ImageAddress,
+ IN UINT64 *ImageSize,
+ IN EFI_PHYSICAL_ADDRESS *EntryPoint
+ );
+
+EFI_STATUS
+SecFfsFindPeiCore (
+ IN EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader,
+ OUT VOID **Pe32Data
+ );
+
+EFI_STATUS
+SecFfsFindNextFile (
+ IN EFI_FV_FILETYPE SearchType,
+ IN EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader,
+ IN OUT EFI_FFS_FILE_HEADER **FileHeader
+ );
+
+EFI_STATUS
+SecFfsFindSectionData (
+ IN EFI_SECTION_TYPE SectionType,
+ IN EFI_FFS_FILE_HEADER *FfsFileHeader,
+ IN OUT VOID **SectionData
+ );
+
+EFI_STATUS
+EFIAPI
+SecUnixPeCoffLoaderLoadAsDll (
+ IN CHAR8 *PdbFileName,
+ IN VOID **ImageEntryPoint,
+ OUT VOID **ModHandle
+ );
+
+EFI_STATUS
+EFIAPI
+SecUnixPeCoffLoaderFreeLibrary (
+ OUT VOID *ModHandle
+ );
+
+EFI_STATUS
+EFIAPI
+SecUnixFdAddress (
+ IN UINTN Index,
+ IN OUT EFI_PHYSICAL_ADDRESS *FdBase,
+ IN OUT UINT64 *FdSize,
+ IN OUT EFI_PHYSICAL_ADDRESS *FixUp
+ )
+;
+
+EFI_STATUS
+EFIAPI
+GasketSecUnixFdAddress (
+ IN UINTN Index,
+ IN OUT EFI_PHYSICAL_ADDRESS *FdBase,
+ IN OUT UINT64 *FdSize,
+ IN OUT EFI_PHYSICAL_ADDRESS *FixUp
+ )
+;
+
+
+EFI_STATUS
+GetImageReadFunction (
+ IN PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext,
+ IN EFI_PHYSICAL_ADDRESS *TopOfMemory
+ );
+
+EFI_STATUS
+EFIAPI
+SecImageRead (
+ IN VOID *FileHandle,
+ IN UINTN FileOffset,
+ IN OUT UINTN *ReadSize,
+ OUT VOID *Buffer
+ );
+
+CHAR16 *
+AsciiToUnicode (
+ IN CHAR8 *Ascii,
+ IN UINTN *StrLen OPTIONAL
+ );
+
+UINTN
+CountSeperatorsInString (
+ IN const CHAR16 *String,
+ IN CHAR16 Seperator
+ );
+
+EFI_STATUS
+EFIAPI
+SecTemporaryRamSupport (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PHYSICAL_ADDRESS TemporaryMemoryBase,
+ IN EFI_PHYSICAL_ADDRESS PermanentMemoryBase,
+ IN UINTN CopySize
+ );
+
+EFI_STATUS
+EFIAPI
+GasketSecTemporaryRamSupport (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PHYSICAL_ADDRESS TemporaryMemoryBase,
+ IN EFI_PHYSICAL_ADDRESS PermanentMemoryBase,
+ IN UINTN CopySize
+ );
+
+
+RETURN_STATUS
+EFIAPI
+SecPeCoffGetEntryPoint (
+ IN VOID *Pe32Data,
+ IN OUT VOID **EntryPoint
+ );
+
+VOID
+EFIAPI
+SecPeCoffRelocateImageExtraAction (
+ IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
+ );
+
+VOID
+EFIAPI
+SecPeCoffLoaderUnloadImageExtraAction (
+ IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
+ );
+
+
+VOID
+EFIAPI
+PeiSwitchStacks (
+ IN SWITCH_STACK_ENTRY_POINT EntryPoint,
+ IN VOID *Context1, OPTIONAL
+ IN VOID *Context2, OPTIONAL
+ IN VOID *Context3, OPTIONAL
+ IN VOID *NewStack
+ );
+
+VOID
+SecInitThunkProtocol (
+ VOID
+ );
+
+
+VOID SecSleep (UINT64 Milliseconds);
+VOID SecEnableInterrupt (VOID);
+VOID SecDisableInterrupt (VOID);
+BOOLEAN SecInterruptEanbled (VOID);
+
+
+extern EMU_THUNK_PROTOCOL gEmuThunkProtocol;
+extern EMU_IO_THUNK_PROTOCOL gX11ThunkIo;
+extern EMU_IO_THUNK_PROTOCOL gPosixFileSystemThunkIo;
+extern EMU_IO_THUNK_PROTOCOL gPthreadThunkIo;
+
+
+#endif
diff --git a/InOsEmuPkg/Unix/Sec/SecMain.inf b/InOsEmuPkg/Unix/Sec/SecMain.inf new file mode 100644 index 0000000..24a36be --- /dev/null +++ b/InOsEmuPkg/Unix/Sec/SecMain.inf @@ -0,0 +1,118 @@ +## @file
+# Entry Point of Emu Emulator
+#
+# Main executable file of Unix Emulator that loads PEI core after initialization finished.
+# Copyright (c) 2008 - 2010, Intel Corporation. All rights reserved.<BR>
+# Portions copyright (c) 2008 - 2011, Apple Inc. All rights reserved.<BR>
+#
+# 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 = 8863C0AD-7724-C84B-88E5-A33B116D1485
+ MODULE_TYPE = USER_DEFINED
+# MODULE_TYPE = BASE
+ VERSION_STRING = 1.0
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+
+[Sources]
+ SecMain.c
+ EmuThunk.c
+ FwVol.c
+ X11GraphicsWindow.c
+ Pthreads.c
+ PosixFileSystem.c
+
+[Sources.X64]
+ X64/Gasket.S # convert between Emu x86_64 ABI and EFI X64 ABI
+ X64/SwitchStack.S
+
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ InOsEmuPkg/InOsEmuPkg.dec
+ InOsEmuPkg/InOsEmuPkg.dec
+
+[LibraryClasses]
+ DebugLib
+ PcdLib
+ PrintLib
+ BaseMemoryLib
+ BaseLib
+ PeCoffLib
+ ThunkPpiList
+ ThunkProtocolList
+
+
+[Ppis]
+ gEfiPeiStatusCodePpiGuid # PPI ALWAYS_PRODUCED
+ gEfiTemporaryRamSupportPpiGuid
+ gEmuThunkPpiGuid
+ gEmuPeiServicesTableUpdatePpiGuid
+
+[Protocols]
+ gEmuIoThunkProtocolGuid
+ gEmuIoThunkProtocolGuid
+ gEmuGraphicsWindowProtocolGuid
+ gEmuPthreadThunkProtocolGuid
+ gEfiSimpleFileSystemProtocolGuid
+
+
+[Guids]
+ gEfiFileSystemVolumeLabelInfoIdGuid # SOMETIMES_CONSUMED
+ gEfiFileInfoGuid # SOMETIMES_CONSUMED
+ gEfiFileSystemInfoGuid # SOMETIMES_CONSUMED
+
+[Pcd]
+ gInOsEmuPkgTokenSpaceGuid.PcdEmuBootMode
+ gInOsEmuPkgTokenSpaceGuid.PcdEmuFirmwareVolume
+ gInOsEmuPkgTokenSpaceGuid.PcdEmuMemorySize
+ gInOsEmuPkgTokenSpaceGuid.PcdEmuFdBaseAddress
+ gInOsEmuPkgTokenSpaceGuid.PcdEmuFirmwareFdSize
+ gInOsEmuPkgTokenSpaceGuid.PcdEmuFirmwareBlockSize
+ gInOsEmuPkgTokenSpaceGuid.PcdEmuApCount
+ gInOsEmuPkgTokenSpaceGuid.PcdEmuPhysicalDisk
+ gInOsEmuPkgTokenSpaceGuid.PcdEmuVirtualDisk
+ gInOsEmuPkgTokenSpaceGuid.PcdEmuGop|L"GOP Window"
+ gInOsEmuPkgTokenSpaceGuid.PcdEmuFileSystem
+ gInOsEmuPkgTokenSpaceGuid.PcdEmuSerialPort
+ gInOsEmuPkgTokenSpaceGuid.PcdEmuNetworkInterface
+
+
+[BuildOptions]
+ GCC:*_*_IA32_DLINK_FLAGS == -o $(BIN_DIR)/SecMain -m elf_i386 -dynamic-linker /lib/ld-linux.so.2 /usr/lib/crt1.o /usr/lib/crti.o -L/usr/X11R6/lib -lXext -lX11 /usr/lib/crtn.o
+ GCC:*_*_*_DLINK2_FLAGS == -lc
+ GCC:*_*_IA32_CC_FLAGS == -m32 -g -fshort-wchar -fno-strict-aliasing -Wall -malign-double -idirafter/usr/include -c -include $(DEST_DIR_DEBUG)/AutoGen.h -DSTRING_ARRAY_NAME=$(BASE_NAME)Strings
+ GCC:*_*_IA32_PP_FLAGS == -m32 -E -x assembler-with-cpp -include $(DEST_DIR_DEBUG)/AutoGen.h
+ GCC:*_*_IA32_ASM_FLAGS == -m32 -c -x assembler -imacros $(DEST_DIR_DEBUG)/AutoGen.h
+
+ GCC:*_*_X64_DLINK_FLAGS == -o $(BIN_DIR)/SecMain -m elf_x86_64 -dynamic-linker /lib64/ld-linux-x86-64.so.2 /usr/lib/crt1.o /usr/lib/crti.o -L/usr/X11R6/lib -lXext -lX11 /usr/lib/crtn.o
+ GCC:*_*_X64_CC_FLAGS == -m64 -g -fshort-wchar -fno-strict-aliasing -Wall -malign-double -idirafter/usr/include -c -include $(DEST_DIR_DEBUG)/AutoGen.h -DSTRING_ARRAY_NAME=$(BASE_NAME)Strings
+ GCC:*_*_X64_PP_FLAGS == -m64 -E -x assembler-with-cpp -include $(DEST_DIR_DEBUG)/AutoGen.h
+ GCC:*_*_X64_ASM_FLAGS == -m64 -c -x assembler -imacros $(DEST_DIR_DEBUG)/AutoGen.h
+
+#
+# Need to do this link via gcc and not ld as the pathing to libraries changes from OS version to OS version
+#
+ XCODE:*_*_IA32_DLINK_PATH == gcc
+ XCODE:*_*_IA32_DLINK_FLAGS == -arch i386 -o $(BIN_DIR)/SecMain -L/usr/X11R6/lib -lXext -lX11 -framework IOKit -framework Carbon
+ XCODE:*_*_IA32_ASM_FLAGS == -arch i386 -g
+
+ XCODE:*_*_X64_DLINK_PATH == gcc
+ XCODE:*_*_X64_DLINK_FLAGS == -o $(BIN_DIR)/SecMain -L/usr/X11R6/lib -lXext -lX11 -lIOKit -framework Carbon
+ XCODE:*_*_X64_ASM_FLAGS == -g
diff --git a/InOsEmuPkg/Unix/Sec/X11GraphicsWindow.c b/InOsEmuPkg/Unix/Sec/X11GraphicsWindow.c new file mode 100644 index 0000000..1920f33 --- /dev/null +++ b/InOsEmuPkg/Unix/Sec/X11GraphicsWindow.c @@ -0,0 +1,976 @@ +/*++ @file + +Copyright (c) 2004 - 2009, Intel Corporation. All rights reserved.<BR> +Portions copyright (c) 2008 - 2011, Apple Inc. All rights reserved.<BR> +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. + +**/ + +#include "SecMain.h" + +#include <sys/ipc.h> +#include <sys/shm.h> + +#include <X11/Xlib.h> +#include <X11/Xutil.h> +#include <X11/Xos.h> +#include <X11/extensions/XShm.h> +#include <X11/keysym.h> +#include <X11/cursorfont.h> + +#define KEYSYM_LOWER 0 +#define KEYSYM_UPPER 1 + +/* XQueryPointer */ + +struct uga_drv_shift_mask { + unsigned char shift; + unsigned char size; + unsigned char csize; +}; + +#define NBR_KEYS 32 +typedef struct { + EMU_GRAPHICS_WINDOW_PROTOCOL GraphicsIo; + + 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_KEY_DATA keys[NBR_KEYS]; + + EFI_KEY_STATE KeyState; + + EMU_GRAPHICS_WINDOW_REGISTER_KEY_NOTIFY_CALLBACK MakeRegisterdKeyCallback; + EMU_GRAPHICS_WINDOW_REGISTER_KEY_NOTIFY_CALLBACK BreakRegisterdKeyCallback; + VOID *RegisterdKeyCallbackContext; + + int previous_x; + int previous_y; + EFI_SIMPLE_POINTER_STATE pointer_state; + int pointer_state_changed; +} GRAPHICS_IO_PRIVATE; + +void +HandleEvents(GRAPHICS_IO_PRIVATE *drv); + +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; +} + +int +TryCreateShmImage ( + IN GRAPHICS_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; + } + +#ifndef __APPLE__ + // + // This closes shared memory in real time on OS X. Only closes after folks quit using + // it on Linux. + // + /* Can this fail ? */ + shmctl (drv->xshm_info.shmid, IPC_RMID, NULL); +#endif + + 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; +} + + +EFI_STATUS +X11Size( + IN EMU_GRAPHICS_WINDOW_PROTOCOL *GraphicsIo, + IN UINT32 Width, + IN UINT32 Height + ) +{ + GRAPHICS_IO_PRIVATE *drv = (GRAPHICS_IO_PRIVATE *)GraphicsIo; + XSizeHints size_hints; + + /* Destroy current buffer if created. */ + if (drv->image != NULL) + { + /* Before destroy buffer, need to make sure the buffer available for access. */ + 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; +} + +void +handleKeyEvent(GRAPHICS_IO_PRIVATE *drv, XEvent *ev, BOOLEAN Make) +{ + KeySym *KeySym; + EFI_KEY_DATA KeyData; + int KeySymArraySize; + + if (Make) { + if (drv->key_count == NBR_KEYS) { + return; + } + } + + // keycode is a physical key on the keyboard + // KeySym is a mapping of a physical key + // KeyboardMapping is the array of KeySym for a given keycode. key, shifted key, option key, command key, ... + // + // Returns an array of KeySymArraySize of KeySym for the keycode. [0] is lower case, [1] is upper case, + // [2] and [3] are based on option and command modifiers. The problem we have is command V + // could be mapped to a crazy Unicode character so the old scheme of returning a string. + // + KeySym = XGetKeyboardMapping (drv->display, ev->xkey.keycode, 1, &KeySymArraySize); + + KeyData.Key.ScanCode = 0; + KeyData.Key.UnicodeChar = 0; + KeyData.KeyState.KeyShiftState = 0; + + // + // Skipping EFI_SCROLL_LOCK_ACTIVE & EFI_NUM_LOCK_ACTIVE since they are not on Macs + // + if ((ev->xkey.state & LockMask) == 0) { + drv->KeyState.KeyToggleState &= ~EFI_CAPS_LOCK_ACTIVE; + } else { + if (Make) { + drv->KeyState.KeyToggleState |= EFI_CAPS_LOCK_ACTIVE; + } + } + + // Skipping EFI_MENU_KEY_PRESSED and EFI_SYS_REQ_PRESSED + + switch (*KeySym) { + case XK_Control_R: + if (Make) { + drv->KeyState.KeyShiftState |= EFI_RIGHT_CONTROL_PRESSED; + } else { + drv->KeyState.KeyShiftState &= ~EFI_RIGHT_CONTROL_PRESSED; + } + break; + case XK_Control_L: + if (Make) { + drv->KeyState.KeyShiftState |= EFI_LEFT_CONTROL_PRESSED; + } else { + drv->KeyState.KeyShiftState &= ~EFI_LEFT_CONTROL_PRESSED; + } + break; + + case XK_Shift_R: + if (Make) { + drv->KeyState.KeyShiftState |= EFI_RIGHT_SHIFT_PRESSED; + } else { + drv->KeyState.KeyShiftState &= ~EFI_RIGHT_SHIFT_PRESSED; + } + break; + case XK_Shift_L: + if (Make) { + drv->KeyState.KeyShiftState |= EFI_LEFT_SHIFT_PRESSED; + } else { + drv->KeyState.KeyShiftState &= ~EFI_LEFT_SHIFT_PRESSED; + } + break; + + case XK_Mode_switch: + if (Make) { + drv->KeyState.KeyShiftState |= EFI_LEFT_ALT_PRESSED; + } else { + drv->KeyState.KeyShiftState &= ~EFI_LEFT_ALT_PRESSED; + } + break; + + case XK_Meta_R: + if (Make) { + drv->KeyState.KeyShiftState |= EFI_RIGHT_LOGO_PRESSED; + } else { + drv->KeyState.KeyShiftState &= ~EFI_RIGHT_LOGO_PRESSED; + } + break; + case XK_Meta_L: + if (Make) { + drv->KeyState.KeyShiftState |= EFI_LEFT_LOGO_PRESSED; + } else { + drv->KeyState.KeyShiftState &= ~EFI_LEFT_LOGO_PRESSED; + } + break; + + case XK_KP_Home: + case XK_Home: KeyData.Key.ScanCode = SCAN_HOME; break; + + case XK_KP_End: + case XK_End: KeyData.Key.ScanCode = SCAN_END; break; + + case XK_KP_Left: + case XK_Left: KeyData.Key.ScanCode = SCAN_LEFT; break; + + case XK_KP_Right: + case XK_Right: KeyData.Key.ScanCode = SCAN_RIGHT; break; + + case XK_KP_Up: + case XK_Up: KeyData.Key.ScanCode = SCAN_UP; break; + + case XK_KP_Down: + case XK_Down: KeyData.Key.ScanCode = SCAN_DOWN; break; + + case XK_KP_Delete: + case XK_Delete: KeyData.Key.ScanCode = SCAN_DELETE; break; + + case XK_KP_Insert: + case XK_Insert: KeyData.Key.ScanCode = SCAN_INSERT; break; + + case XK_KP_Page_Up: + case XK_Page_Up: KeyData.Key.ScanCode = SCAN_PAGE_UP; break; + + case XK_KP_Page_Down: + case XK_Page_Down: KeyData.Key.ScanCode = SCAN_PAGE_DOWN; break; + + case XK_Escape: KeyData.Key.ScanCode = SCAN_ESC; break; + + + case XK_KP_F1: + case XK_F1: KeyData.Key.ScanCode = SCAN_F1; break; + + case XK_KP_F2: + case XK_F2: KeyData.Key.ScanCode = SCAN_F2; break; + + case XK_KP_F3: + case XK_F3: KeyData.Key.ScanCode = SCAN_F3; break; + + case XK_KP_F4: + case XK_F4: KeyData.Key.ScanCode = SCAN_F4; break; + + case XK_F5: KeyData.Key.ScanCode = SCAN_F5; break; + case XK_F6: KeyData.Key.ScanCode = SCAN_F6; break; + case XK_F7: KeyData.Key.ScanCode = SCAN_F7; break; + + // Don't map into X11 by default on a Mac + // System Preferences->Keyboard->Keyboard Shortcuts can be configured + // to not use higher function keys as shortcuts and the will show up + // in X11. + case XK_F8: KeyData.Key.ScanCode = SCAN_F8; break; + case XK_F9: KeyData.Key.ScanCode = SCAN_F9; break; + case XK_F10: KeyData.Key.ScanCode = SCAN_F10; break; + + case XK_F11: KeyData.Key.ScanCode = SCAN_F11; break; + case XK_F12: KeyData.Key.ScanCode = SCAN_F12; break; + + case XK_F13: KeyData.Key.ScanCode = SCAN_F13; break; + case XK_F14: KeyData.Key.ScanCode = SCAN_F14; break; + case XK_F15: KeyData.Key.ScanCode = SCAN_F15; break; + case XK_F16: KeyData.Key.ScanCode = SCAN_F16; break; + case XK_F17: KeyData.Key.ScanCode = SCAN_F17; break; + case XK_F18: KeyData.Key.ScanCode = SCAN_F18; break; + case XK_F19: KeyData.Key.ScanCode = SCAN_F19; break; + case XK_F20: KeyData.Key.ScanCode = SCAN_F20; break; + case XK_F21: KeyData.Key.ScanCode = SCAN_F21; break; + case XK_F22: KeyData.Key.ScanCode = SCAN_F22; break; + case XK_F23: KeyData.Key.ScanCode = SCAN_F23; break; + case XK_F24: KeyData.Key.ScanCode = SCAN_F24; break; + + // No mapping in X11 + //case XK_: KeyData.Key.ScanCode = SCAN_MUTE; break; + //case XK_: KeyData.Key.ScanCode = SCAN_VOLUME_UP; break; + //case XK_: KeyData.Key.ScanCode = SCAN_VOLUME_DOWN; break; + //case XK_: KeyData.Key.ScanCode = SCAN_BRIGHTNESS_UP; break; + //case XK_: KeyData.Key.ScanCode = SCAN_BRIGHTNESS_DOWN; break; + //case XK_: KeyData.Key.ScanCode = SCAN_SUSPEND; break; + //case XK_: KeyData.Key.ScanCode = SCAN_HIBERNATE; break; + //case XK_: KeyData.Key.ScanCode = SCAN_TOGGLE_DISPLAY; break; + //case XK_: KeyData.Key.ScanCode = SCAN_RECOVERY; break; + //case XK_: KeyData.Key.ScanCode = SCAN_EJECT; break; + + case XK_BackSpace: KeyData.Key.UnicodeChar = 0x0008; break; + + case XK_KP_Tab: + case XK_Tab: KeyData.Key.UnicodeChar = 0x0009; break; + + case XK_Linefeed: KeyData.Key.UnicodeChar = 0x000a; break; + + case XK_KP_Enter: + case XK_Return: KeyData.Key.UnicodeChar = 0x000d; break; + + case XK_KP_Equal : KeyData.Key.UnicodeChar = L'='; break; + case XK_KP_Multiply : KeyData.Key.UnicodeChar = L'*'; break; + case XK_KP_Add : KeyData.Key.UnicodeChar = L'+'; break; + case XK_KP_Separator : KeyData.Key.UnicodeChar = L'~'; break; + case XK_KP_Subtract : KeyData.Key.UnicodeChar = L'-'; break; + case XK_KP_Decimal : KeyData.Key.UnicodeChar = L'.'; break; + case XK_KP_Divide : KeyData.Key.UnicodeChar = L'/'; break; + + case XK_KP_0 : KeyData.Key.UnicodeChar = L'0'; break; + case XK_KP_1 : KeyData.Key.UnicodeChar = L'1'; break; + case XK_KP_2 : KeyData.Key.UnicodeChar = L'2'; break; + case XK_KP_3 : KeyData.Key.UnicodeChar = L'3'; break; + case XK_KP_4 : KeyData.Key.UnicodeChar = L'4'; break; + case XK_KP_5 : KeyData.Key.UnicodeChar = L'5'; break; + case XK_KP_6 : KeyData.Key.UnicodeChar = L'6'; break; + case XK_KP_7 : KeyData.Key.UnicodeChar = L'7'; break; + case XK_KP_8 : KeyData.Key.UnicodeChar = L'8'; break; + case XK_KP_9 : KeyData.Key.UnicodeChar = L'9'; break; + + default: + ; + } + + // The global state is our state + KeyData.KeyState.KeyShiftState = drv->KeyState.KeyShiftState; + KeyData.KeyState.KeyToggleState = drv->KeyState.KeyToggleState; + + if (*KeySym < XK_BackSpace) { + if (((drv->KeyState.KeyShiftState & (EFI_LEFT_SHIFT_PRESSED | EFI_RIGHT_SHIFT_PRESSED)) != 0) || + ((drv->KeyState.KeyToggleState & EFI_CAPS_LOCK_ACTIVE) != 0) ) { + + KeyData.Key.UnicodeChar = (CHAR16)KeySym[KEYSYM_UPPER]; + + // Per UEFI spec since we converted the Unicode clear the shift bits we pass up + KeyData.KeyState.KeyShiftState &= ~(EFI_LEFT_SHIFT_PRESSED | EFI_RIGHT_SHIFT_PRESSED); + } else { + KeyData.Key.UnicodeChar = (CHAR16)KeySym[KEYSYM_LOWER]; + } + } else { + // XK_BackSpace is the start of XK_MISCELLANY. These are the XK_? keys we process in this file + ; + } + + if (Make) { + memcpy (&drv->keys[drv->key_wr], &KeyData, sizeof (EFI_KEY_DATA)); + drv->key_wr = (drv->key_wr + 1) % NBR_KEYS; + drv->key_count++; + if (drv->MakeRegisterdKeyCallback != NULL) { + ReverseGasketUint64Uint64 (drv->MakeRegisterdKeyCallback ,drv->RegisterdKeyCallbackContext, &KeyData); + } + } else { + if (drv->BreakRegisterdKeyCallback != NULL) { + ReverseGasketUint64Uint64 (drv->BreakRegisterdKeyCallback ,drv->RegisterdKeyCallbackContext, &KeyData); + } + } +} + + +void +handleMouseMoved(GRAPHICS_IO_PRIVATE *drv, XEvent *ev) +{ + if ( ev->xmotion.x != drv->previous_x ) + { + drv->pointer_state.RelativeMovementX += ( ev->xmotion.x - drv->previous_x ); + drv->previous_x = ev->xmotion.x; + drv->pointer_state_changed = 1; + } + + if ( ev->xmotion.y != drv->previous_y ) + { + drv->pointer_state.RelativeMovementY += ( ev->xmotion.y - drv->previous_y ); + drv->previous_y = ev->xmotion.y; + drv->pointer_state_changed = 1; + } + + drv->pointer_state.RelativeMovementZ = 0; +} + +void +handleMouseDown(GRAPHICS_IO_PRIVATE *drv, XEvent *ev, BOOLEAN Pressed) +{ + if ( ev->xbutton.button == Button1 ) + { + drv->pointer_state_changed = ( drv->pointer_state.LeftButton != Pressed ); + drv->pointer_state.LeftButton = Pressed; + } + if ( ev->xbutton.button == Button2 ) + { + drv->pointer_state_changed = ( drv->pointer_state.RightButton != Pressed ); + drv->pointer_state.RightButton = Pressed; + } +} + +void +Redraw(GRAPHICS_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); + XFlush(drv->display); +} + +void +HandleEvent(GRAPHICS_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, TRUE); + break; + case KeyRelease: + handleKeyEvent(drv, ev, FALSE); + break; + case MappingNotify: + XRefreshKeyboardMapping(&ev->xmapping); + break; + case MotionNotify: + handleMouseMoved(drv, ev); + break; + case ButtonPress: + handleMouseDown(drv, ev, TRUE); + break; + case ButtonRelease: + handleMouseDown(drv, ev, FALSE); + break; +#if 0 + case DestroyNotify: + XCloseDisplay (drv->display); + exit (1); + break; +#endif + case NoExpose: + default: + break; + } +} + +void +HandleEvents(GRAPHICS_IO_PRIVATE *drv) +{ + while (XPending(drv->display) != 0) + { + XEvent ev; + + XNextEvent (drv->display, &ev); + HandleEvent(drv, &ev); + } +} + +unsigned long +X11PixelToColor (GRAPHICS_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); +} + +EFI_UGA_PIXEL +X11ColorToPixel (GRAPHICS_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 +CheckKeyInternal( GRAPHICS_IO_PRIVATE *drv, BOOLEAN delay ) +{ + HandleEvents(drv); + if (drv->key_count != 0) + return EFI_SUCCESS; + if ( delay ) + /* EFI is polling. Be CPU-friendly. */ + SecSleep (20); + return EFI_NOT_READY; + } + +EFI_STATUS +X11CheckKey(EMU_GRAPHICS_WINDOW_PROTOCOL *GraphicsIo) +{ + GRAPHICS_IO_PRIVATE *drv = (GRAPHICS_IO_PRIVATE *)GraphicsIo; + return CheckKeyInternal(drv, TRUE); +} + +EFI_STATUS +EFIAPI +X11GetKey ( + IN EMU_GRAPHICS_WINDOW_PROTOCOL *GraphicsIo, + IN EFI_KEY_DATA *KeyData + ) +{ + GRAPHICS_IO_PRIVATE *drv = (GRAPHICS_IO_PRIVATE *)GraphicsIo; + EFI_STATUS status; + + status = CheckKeyInternal(drv, FALSE); + if (status != EFI_SUCCESS) + return status; + + CopyMem (KeyData, &drv->keys[drv->key_rd], sizeof (EFI_KEY_DATA)); + drv->key_rd = (drv->key_rd + 1) % NBR_KEYS; + drv->key_count--; + return EFI_SUCCESS; +} + + +EFI_STATUS +EFIAPI +X11KeySetState ( + IN EMU_GRAPHICS_WINDOW_PROTOCOL *GraphicsIo, + IN EFI_KEY_TOGGLE_STATE *KeyToggleState + ) +{ + GRAPHICS_IO_PRIVATE *drv = (GRAPHICS_IO_PRIVATE *)GraphicsIo; +// XKeyEvent event; + + if (*KeyToggleState & EFI_CAPS_LOCK_ACTIVE) { + if ((drv->KeyState.KeyToggleState & EFI_CAPS_LOCK_ACTIVE) == 0) { + // + // We could create an XKeyEvent and send a XK_Caps_Lock to + // the UGA/GOP Window + // + } + } + + drv->KeyState.KeyToggleState = *KeyToggleState; + return EFI_SUCCESS; +} + + +EFI_STATUS +EFIAPI +X11RegisterKeyNotify ( + IN EMU_GRAPHICS_WINDOW_PROTOCOL *GraphicsIo, + IN EMU_GRAPHICS_WINDOW_REGISTER_KEY_NOTIFY_CALLBACK MakeCallBack, + IN EMU_GRAPHICS_WINDOW_REGISTER_KEY_NOTIFY_CALLBACK BreakCallBack, + IN VOID *Context + ) +{ + GRAPHICS_IO_PRIVATE *drv = (GRAPHICS_IO_PRIVATE *)GraphicsIo; + + drv->MakeRegisterdKeyCallback = MakeCallBack; + drv->BreakRegisterdKeyCallback = BreakCallBack; + drv->RegisterdKeyCallbackContext = Context; + + return EFI_SUCCESS; +} + + +EFI_STATUS +X11Blt ( + IN EMU_GRAPHICS_WINDOW_PROTOCOL *GraphicsIo, + IN EFI_UGA_PIXEL *BltBuffer OPTIONAL, + IN EFI_UGA_BLT_OPERATION BltOperation, + IN EMU_GRAPHICS_WINDOWS__BLT_ARGS *Args + ) +{ + GRAPHICS_IO_PRIVATE *Private = (GRAPHICS_IO_PRIVATE *)GraphicsIo; + 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 (Args->SourceY + Args->Height > Private->height) { + return EFI_INVALID_PARAMETER; + } + + if (Args->SourceX + Args->Width > Private->width) { + return EFI_INVALID_PARAMETER; + } + } + + if (BltOperation == EfiUgaBltBufferToVideo + || BltOperation == EfiUgaVideoToVideo + || BltOperation == EfiUgaVideoFill) { + // + // Destination is Video + // + if (Args->DestinationY + Args->Height > Private->height) { + return EFI_INVALID_PARAMETER; + } + + if (Args->DestinationX + Args->Width > Private->width) { + return EFI_INVALID_PARAMETER; + } + } + + switch (BltOperation) { + case EfiUgaVideoToBltBuffer: + Blt = (EFI_UGA_PIXEL *)((UINT8 *)BltBuffer + (Args->DestinationY * Args->Delta) + Args->DestinationX * sizeof (EFI_UGA_PIXEL)); + Args->Delta -= Args->Width * sizeof (EFI_UGA_PIXEL); + for (SrcY = Args->SourceY; SrcY < (Args->Height + Args->SourceY); SrcY++) { + for (SrcX = Args->SourceX; SrcX < (Args->Width + Args->SourceX); SrcX++) { + *Blt++ = X11ColorToPixel(Private, + XGetPixel(Private->image, SrcX, SrcY)); + } + Blt = (EFI_UGA_PIXEL *) ((UINT8 *) Blt + Args->Delta); + } + break; + case EfiUgaBltBufferToVideo: + Blt = (EFI_UGA_PIXEL *)((UINT8 *)BltBuffer + (Args->SourceY * Args->Delta) + Args->SourceX * sizeof (EFI_UGA_PIXEL)); + Args->Delta -= Args->Width * sizeof (EFI_UGA_PIXEL); + for (DstY = Args->DestinationY; DstY < (Args->Height + Args->DestinationY); DstY++) { + for (DstX = Args->DestinationX; DstX < (Args->Width + Args->DestinationX); DstX++) { + XPutPixel(Private->image, DstX, DstY, X11PixelToColor(Private, *Blt)); + Blt++; + } + Blt = (EFI_UGA_PIXEL *) ((UINT8 *) Blt + Args->Delta); + } + break; + case EfiUgaVideoToVideo: + Dst = Private->image_data + (Args->DestinationX << Private->pixel_shift) + + Args->DestinationY * Private->line_bytes; + Src = Private->image_data + (Args->SourceX << Private->pixel_shift) + + Args->SourceY * Private->line_bytes; + Nbr = Args->Width << Private->pixel_shift; + if (Args->DestinationY < Args->SourceY) { + for (Index = 0; Index < Args->Height; Index++) { + memcpy (Dst, Src, Nbr); + Dst += Private->line_bytes; + Src += Private->line_bytes; + } + } + else { + Dst += (Args->Height - 1) * Private->line_bytes; + Src += (Args->Height - 1) * Private->line_bytes; + for (Index = 0; Index < Args->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 = X11PixelToColor(Private, *BltBuffer); + for (DstY = Args->DestinationY; DstY < (Args->Height + Args->DestinationY); DstY++) { + for (DstX = Args->DestinationX; DstX < (Args->Width + Args->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, + Args->SourceX, Args->SourceY, Args->Width, Args->Height, Args->DestinationX, Args->DestinationY); + while (1) { + XEvent ev; + + XNextEvent (Private->display, &ev); + HandleEvent(Private, &ev); + if (ev.type == NoExpose || ev.type == GraphicsExpose) + break; + } + break; + case EfiUgaVideoFill: + Color = X11PixelToColor(Private, *BltBuffer); + XSetForeground(Private->display, Private->gc, Color); + XFillRectangle(Private->display, Private->win, Private->gc, + Args->DestinationX, Args->DestinationY, Args->Width, Args->Height); + XFlush(Private->display); + break; + case EfiUgaBltBufferToVideo: + Redraw(Private, Args->DestinationX, Args->DestinationY, Args->Width, Args->Height); + break; + default: + break; + } + return EFI_SUCCESS; +} + +STATIC EFI_STATUS +CheckPointerInternal( GRAPHICS_IO_PRIVATE *drv, BOOLEAN delay ) +{ + HandleEvents(drv); + if (drv->pointer_state_changed != 0) + return EFI_SUCCESS; + if ( delay ) + /* EFI is polling. Be CPU-friendly. */ + SecSleep (20); + return EFI_NOT_READY; +} + +EFI_STATUS +X11CheckPointer(EMU_GRAPHICS_WINDOW_PROTOCOL *GraphicsIo) +{ + GRAPHICS_IO_PRIVATE *drv = (GRAPHICS_IO_PRIVATE *)GraphicsIo; + return( CheckPointerInternal( drv, TRUE ) ); +} + +EFI_STATUS +X11GetPointerState (EMU_GRAPHICS_WINDOW_PROTOCOL *GraphicsIo, EFI_SIMPLE_POINTER_STATE *state) +{ + GRAPHICS_IO_PRIVATE *drv = (GRAPHICS_IO_PRIVATE *)GraphicsIo; + EFI_STATUS status; + + status = CheckPointerInternal( drv, FALSE ); + if (status != EFI_SUCCESS) + return status; + + memcpy( state, &drv->pointer_state, sizeof( EFI_SIMPLE_POINTER_STATE ) ); + + drv->pointer_state.RelativeMovementX = 0; + drv->pointer_state.RelativeMovementY = 0; + drv->pointer_state.RelativeMovementZ = 0; + drv->pointer_state_changed = 0; + return EFI_SUCCESS; +} + + + +EFI_STATUS +X11GraphicsWindowOpen ( + IN EMU_IO_THUNK_PROTOCOL *This + ) +{ + GRAPHICS_IO_PRIVATE *drv; + unsigned int border_width = 0; + char *display_name = NULL; + int title_len; + + drv = (GRAPHICS_IO_PRIVATE *)calloc (1, sizeof (GRAPHICS_IO_PRIVATE)); + if (drv == NULL) + return EFI_OUT_OF_RESOURCES; + + drv->GraphicsIo.Size = GasketX11Size; + drv->GraphicsIo.CheckKey = GasketX11CheckKey; + drv->GraphicsIo.GetKey = GasketX11GetKey; + drv->GraphicsIo.KeySetState = GasketX11KeySetState; + drv->GraphicsIo.RegisterKeyNotify = GasketX11RegisterKeyNotify; + drv->GraphicsIo.Blt = GasketX11Blt; + drv->GraphicsIo.CheckPointer = GasketX11CheckPointer; + drv->GraphicsIo.GetPointerState = GasketX11GetPointerState; + + + drv->key_count = 0; + drv->key_rd = 0; + drv->key_wr = 0; + drv->KeyState.KeyShiftState = EFI_SHIFT_STATE_VALID; + drv->KeyState.KeyToggleState = EFI_TOGGLE_STATE_VALID; + drv->MakeRegisterdKeyCallback = NULL; + drv->BreakRegisterdKeyCallback = NULL; + drv->RegisterdKeyCallbackContext = NULL; + + + 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, + WhitePixel (drv->display, drv->screen), + BlackPixel (drv->display, drv->screen)); + + drv->depth = DefaultDepth (drv->display, drv->screen); + XDefineCursor (drv->display, drv->win, XCreateFontCursor (drv->display, XC_pirate)); + + /* Compute title len and convert to Ascii. */ + for (title_len = 0; This->ConfigString[title_len] != 0; title_len++) + ; + { + char title[title_len + 1]; + int i; + for (i = 0; i < title_len; i++) + title[i] = This->ConfigString[i]; + title[i] = 0; + + XStoreName (drv->display, drv->win, title); + } + +// XAutoRepeatOff (drv->display); + XSelectInput (drv->display, drv->win, + ExposureMask | KeyPressMask | KeyReleaseMask | PointerMotionMask | ButtonPressMask | ButtonReleaseMask ); + drv->gc = DefaultGC (drv->display, drv->screen); + + This->Private = (VOID *)drv; + This->Interface = (VOID *)drv; + return EFI_SUCCESS; +} + + +EFI_STATUS +X11GraphicsWindowClose ( + IN EMU_IO_THUNK_PROTOCOL *This + ) +{ + GRAPHICS_IO_PRIVATE *drv = (GRAPHICS_IO_PRIVATE *)This->Private; + + 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); + +#ifdef __APPLE__ + // Free up the shared memory + shmctl (drv->xshm_info.shmid, IPC_RMID, NULL); +#endif + + free(drv); + return EFI_SUCCESS; +} + + +EMU_IO_THUNK_PROTOCOL gX11ThunkIo = { + &gEmuGraphicsWindowProtocolGuid, + NULL, + NULL, + 0, + GasketX11GraphicsWindowOpen, + GasketX11GraphicsWindowClose, + NULL +}; + + diff --git a/InOsEmuPkg/Unix/Sec/X64/Gasket.S b/InOsEmuPkg/Unix/Sec/X64/Gasket.S new file mode 100644 index 0000000..fde3028 --- /dev/null +++ b/InOsEmuPkg/Unix/Sec/X64/Gasket.S @@ -0,0 +1,1054 @@ +#------------------------------------------------------------------------------ +# +# Manage differenced between UNIX ABI and EFI/Windows ABI +# +# EFI Arg passing: RCX, RDX, R8, R9 +# Callee allocates 32 bytes on stack to spill registers +# UNIX Arg passing: RDI, RSI, RDX, RCX, R8, R9 +# RSI, RDI calle-save on EFI, scatch on UNIX callign +# +# Copyright (c) 2008 - 2011, Apple Inc. All rights reserved.<BR> +# 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. +# +#------------------------------------------------------------------------------ + +// +// Gaskets are EFI ABI to UNIX ABI calls +// EFI ABI code will sub 40 (0x28) from %rsp before calling a function +// This is the 32 (0x20) byte to spill registers and 8 bytes to align stack on 16 byte boundry. +// + .text + +// 32 byte shadow to spill rcx-r9, 8 bytes to align stack on 16 byte boundry +// Any call with 0 - 4 arguments allocates 40 bytes on the stack. +// For more than 4 args you always have to increase in quanta of 16 so 5 or 6 args is 56, +// 7 or 8 args is 72, and 9 or 10 args is 88 + + + + .text + +// +// EMU_THUNK_PROTOCOL gaskets (EFIAPI to UNIX ABI) +// + + + + +ASM_GLOBAL ASM_PFX(GasketSecWriteStdErr) +ASM_PFX(GasketSecWriteStdErr): + pushq %rbp // stack frame is for the debugger + movq %rsp, %rbp + + pushq %rsi // %rsi & %rdi are volatile in Unix and callee-save in EFI ABI + pushq %rdi + + movq %rcx, %rdi // Swizzle args + movq %rdx, %rsi + + call ASM_PFX(SecWriteStdErr) + + popq %rdi // restore state + popq %rsi + popq %rbp + ret + + +ASM_GLOBAL ASM_PFX(GasketSecSetTimer) +ASM_PFX(GasketSecSetTimer): + pushq %rbp // stack frame is for the debugger + movq %rsp, %rbp + + pushq %rsi // %rsi & %rdi are volatile in Unix and callee-save in EFI ABI + pushq %rdi + + movq %rcx, %rdi // Swizzle args + movq %rdx, %rsi + + call ASM_PFX(SecSetTimer) + + popq %rdi // restore state + popq %rsi + popq %rbp + ret + + +ASM_GLOBAL ASM_PFX(GasketSecEnableInterrupt) +ASM_PFX(GasketSecEnableInterrupt): + pushq %rbp // stack frame is for the debugger + movq %rsp, %rbp + + pushq %rsi // %rsi & %rdi are volatile in Unix and callee-save in EFI ABI + pushq %rdi + + call ASM_PFX(SecEnableInterrupt) + + popq %rdi // restore state + popq %rsi + popq %rbp + ret + + +ASM_GLOBAL ASM_PFX(GasketSecDisableInterrupt) +ASM_PFX(GasketSecDisableInterrupt): + pushq %rbp // stack frame is for the debugger + movq %rsp, %rbp + + pushq %rsi // %rsi & %rdi are volatile in Unix and callee-save in EFI ABI + pushq %rdi + + call ASM_PFX(SecDisableInterrupt) + + popq %rdi // restore state + popq %rsi + popq %rbp + ret + +ASM_GLOBAL ASM_PFX(GasketQueryPerformanceFrequency) +ASM_PFX(GasketQueryPerformanceFrequency): + pushq %rbp // stack frame is for the debugger + movq %rsp, %rbp + + pushq %rsi // %rsi & %rdi are volatile in Unix and callee-save in EFI ABI + pushq %rdi + + call ASM_PFX(QueryPerformanceFrequency) + + popq %rdi // restore state + popq %rsi + popq %rbp + ret + + +ASM_GLOBAL ASM_PFX(GasketQueryPerformanceCounter) +ASM_PFX(GasketQueryPerformanceCounter): + pushq %rbp // stack frame is for the debugger + movq %rsp, %rbp + + pushq %rsi // %rsi & %rdi are volatile in Unix and callee-save in EFI ABI + pushq %rdi + + call ASM_PFX(QueryPerformanceCounter) + + popq %rdi // restore state + popq %rsi + popq %rbp + ret + + +ASM_GLOBAL ASM_PFX(GasketSecSleep) +ASM_PFX(GasketSecSleep): + pushq %rbp // stack frame is for the debugger + movq %rsp, %rbp + + pushq %rsi // %rsi & %rdi are volatile in Unix and callee-save in EFI ABI + pushq %rdi + + movq %rcx, %rdi // Swizzle args + + call ASM_PFX(SecSleep) + + popq %rdi // restore state + popq %rsi + popq %rbp + ret + + +ASM_GLOBAL ASM_PFX(GasketSecExit) +ASM_PFX(GasketSecExit): + pushq %rbp // stack frame is for the debugger + movq %rsp, %rbp + + movq %rcx, %rdi // Swizzle args + call ASM_PFX(SecExit) // Less to do as we will never return to EFI ABI world +LDEAD_LOOP: + jmp LDEAD_LOOP // _exit should never return + + +ASM_GLOBAL ASM_PFX(GasketSecGetTime) +ASM_PFX(GasketSecGetTime): + pushq %rbp // stack frame is for the debugger + movq %rsp, %rbp + + pushq %rsi // %rsi & %rdi are volatile in Unix and callee-save in EFI ABI + pushq %rdi + + movq %rcx, %rdi // Swizzle args + movq %rdx, %rsi + + call ASM_PFX(SecGetTime) + + popq %rdi // restore state + popq %rsi + popq %rbp + ret + +ASM_GLOBAL ASM_PFX(GasketSecSetTime) +ASM_PFX(GasketSecSetTime): + pushq %rbp // stack frame is for the debugger + movq %rsp, %rbp + + pushq %rsi // %rsi & %rdi are volatile in Unix and callee-save in EFI ABI + pushq %rdi + + movq %rcx, %rdi // Swizzle args + movq %rdx, %rsi + + call ASM_PFX(SecSetTime) + + popq %rdi // restore state + popq %rsi + popq %rbp + ret + + +ASM_GLOBAL ASM_PFX(GasketSecGetNextProtocol) +ASM_PFX(GasketSecGetNextProtocol): + pushq %rbp // stack frame is for the debugger + movq %rsp, %rbp + + pushq %rsi // %rsi & %rdi are volatile in Unix and callee-save in EFI ABI + pushq %rdi + + movq %rcx, %rdi // Swizzle args + movq %rdx, %rsi + movq %r8, %rdx + movq %r9, %rcx + + call ASM_PFX(SecGetNextProtocol) + + popq %rdi // restore state + popq %rsi + popq %rbp + ret + +// PPIs produced by SEC + +ASM_GLOBAL ASM_PFX(GasketSecPeCoffGetEntryPoint) +ASM_PFX(GasketSecPeCoffGetEntryPoint): + pushq %rbp // stack frame is for the debugger + movq %rsp, %rbp + + pushq %rsi // %rsi & %rdi are volatile in Unix and callee-save in EFI ABI + pushq %rdi + + movq %rcx, %rdi // Swizzle args + movq %rdx, %rsi + + call ASM_PFX(SecPeCoffGetEntryPoint) + + popq %rdi // restore state + popq %rsi + popq %rbp + ret + +ASM_GLOBAL ASM_PFX(GasketSecPeCoffRelocateImageExtraAction) +ASM_PFX(GasketSecPeCoffRelocateImageExtraAction): + pushq %rbp // stack frame is for the debugger + movq %rsp, %rbp + + pushq %rsi // %rsi & %rdi are volatile in Unix and callee-save in EFI ABI + pushq %rdi + + movq %rcx, %rdi // Swizzle args + + call ASM_PFX(SecPeCoffRelocateImageExtraAction) + + popq %rdi // restore state + popq %rsi + popq %rbp + ret + +ASM_GLOBAL ASM_PFX(GasketSecPeCoffUnloadImageExtraAction) +ASM_PFX(GasketSecPeCoffUnloadImageExtraAction): + pushq %rbp // stack frame is for the debugger + movq %rsp, %rbp + + pushq %rsi // %rsi & %rdi are volatile in Unix and callee-save in EFI ABI + pushq %rdi + + movq %rcx, %rdi // Swizzle args + + call ASM_PFX(SecPeCoffUnloadImageExtraAction) + + popq %rdi // restore state + popq %rsi + popq %rbp + ret + + +ASM_GLOBAL ASM_PFX(GasketSecEmuThunkAddress) +ASM_PFX(GasketSecEmuThunkAddress): + pushq %rbp // stack frame is for the debugger + movq %rsp, %rbp + + pushq %rsi // %rsi & %rdi are volatile in Unix and callee-save in EFI ABI + pushq %rdi + + call ASM_PFX(SecEmuThunkAddress) + + popq %rdi // restore state + popq %rsi + popq %rbp + ret + +// +// Gasket functions for EFI_EMU_UGA_IO_PROTOCOL +// + +ASM_GLOBAL ASM_PFX(GasketX11Size) +ASM_PFX(GasketX11Size): + pushq %rbp // stack frame is for the debugger + movq %rsp, %rbp + + pushq %rsi // %rsi & %rdi are volatile in Unix and callee-save in EFI ABI + pushq %rdi + + movq %rcx, %rdi // Swizzle args + movq %rdx, %rsi + movq %r8, %rdx + movq %r9, %rcx + + call ASM_PFX(X11Size) + + popq %rdi // restore state + popq %rsi + popq %rbp + ret + + +ASM_GLOBAL ASM_PFX(GasketX11CheckKey) +ASM_PFX(GasketX11CheckKey): + pushq %rbp // stack frame is for the debugger + movq %rsp, %rbp + + pushq %rsi // %rsi & %rdi are volatile in Unix and callee-save in EFI ABI + pushq %rdi + + movq %rcx, %rdi // Swizzle args + + call ASM_PFX(X11CheckKey) + + popq %rdi // restore state + popq %rsi + popq %rbp + ret + +ASM_GLOBAL ASM_PFX(GasketX11GetKey) +ASM_PFX(GasketX11GetKey): + pushq %rbp // stack frame is for the debugger + movq %rsp, %rbp + + pushq %rsi // %rsi & %rdi are volatile in Unix and callee-save in EFI ABI + pushq %rdi + + movq %rcx, %rdi // Swizzle args + movq %rdx, %rsi + + call ASM_PFX(X11GetKey) + + popq %rdi // restore state + popq %rsi + popq %rbp + ret + + +ASM_GLOBAL ASM_PFX(GasketX11KeySetState) +ASM_PFX(GasketX11KeySetState): + pushq %rbp // stack frame is for the debugger + movq %rsp, %rbp + + pushq %rsi // %rsi & %rdi are volatile in Unix and callee-save in EFI ABI + pushq %rdi + + movq %rcx, %rdi // Swizzle args + movq %rdx, %rsi + + call ASM_PFX(X11KeySetState) + + popq %rdi // restore state + popq %rsi + popq %rbp + ret + + +ASM_GLOBAL ASM_PFX(GasketX11RegisterKeyNotify) +ASM_PFX(GasketX11RegisterKeyNotify): + pushq %rbp // stack frame is for the debugger + movq %rsp, %rbp + + pushq %rsi // %rsi & %rdi are volatile in Unix and callee-save in EFI ABI + pushq %rdi + + movq %rcx, %rdi // Swizzle args + movq %rdx, %rsi + movq %r8, %rdx + movq %r9, %rcx + + call ASM_PFX(X11RegisterKeyNotify) + + popq %rdi // restore state + popq %rsi + popq %rbp + ret + + +ASM_GLOBAL ASM_PFX(GasketX11Blt) +ASM_PFX(GasketX11Blt): + pushq %rbp // stack frame is for the debugger + movq %rsp, %rbp + + pushq %rsi // %rsi & %rdi are volatile in Unix and callee-save in EFI ABI + pushq %rdi + + movq %rcx, %rdi // Swizzle args + movq %rdx, %rsi + movq %r8, %rdx + movq %r9, %rcx + + call ASM_PFX(X11Blt) + + popq %rdi // restore state + popq %rsi + popq %rbp + ret + + +ASM_GLOBAL ASM_PFX(GasketX11CheckPointer) +ASM_PFX(GasketX11CheckPointer): + pushq %rbp // stack frame is for the debugger + movq %rsp, %rbp + + pushq %rsi // %rsi & %rdi are volatile in Unix and callee-save in EFI ABI + pushq %rdi + + movq %rcx, %rdi // Swizzle args + + call ASM_PFX(X11CheckPointer) + + popq %rdi // restore state + popq %rsi + popq %rbp + ret + + +ASM_GLOBAL ASM_PFX(GasketX11GetPointerState) +ASM_PFX(GasketX11GetPointerState): + pushq %rbp // stack frame is for the debugger + movq %rsp, %rbp + + pushq %rsi // %rsi & %rdi are volatile in Unix and callee-save in EFI ABI + pushq %rdi + + movq %rcx, %rdi // Swizzle args + movq %rdx, %rsi + + call ASM_PFX(X11GetPointerState) + + popq %rdi // restore state + popq %rsi + popq %rbp + ret + + +ASM_GLOBAL ASM_PFX(GasketX11GraphicsWindowOpen) +ASM_PFX(GasketX11GraphicsWindowOpen): + pushq %rbp // stack frame is for the debugger + movq %rsp, %rbp + + pushq %rsi // %rsi & %rdi are volatile in Unix and callee-save in EFI ABI + pushq %rdi + + movq %rcx, %rdi // Swizzle args + + call ASM_PFX(X11GraphicsWindowOpen) + + popq %rdi // restore state + popq %rsi + popq %rbp + ret + + +ASM_GLOBAL ASM_PFX(GasketX11GraphicsWindowClose) +ASM_PFX(GasketX11GraphicsWindowClose): + pushq %rbp // stack frame is for the debugger + movq %rsp, %rbp + + pushq %rsi // %rsi & %rdi are volatile in Unix and callee-save in EFI ABI + pushq %rdi + + movq %rcx, %rdi // Swizzle args + movq %r9, %rcx + + call ASM_PFX(X11GraphicsWindowClose) + + popq %rdi // restore state + popq %rsi + popq %rbp + ret + + +// Pthreads + +ASM_GLOBAL ASM_PFX(GasketPthreadMutexLock) +ASM_PFX(GasketPthreadMutexLock): + pushq %rbp // stack frame is for the debugger + movq %rsp, %rbp + + pushq %rsi // %rsi & %rdi are volatile in Unix and callee-save in EFI ABI + pushq %rdi + + movq %rcx, %rdi // Swizzle args + + call ASM_PFX(PthreadMutexLock) + + popq %rdi // restore state + popq %rsi + popq %rbp + ret + + +ASM_GLOBAL ASM_PFX(GasketPthreadMutexUnLock) +ASM_PFX(GasketPthreadMutexUnLock): + pushq %rbp // stack frame is for the debugger + movq %rsp, %rbp + + pushq %rsi // %rsi & %rdi are volatile in Unix and callee-save in EFI ABI + pushq %rdi + + movq %rcx, %rdi // Swizzle args + + call ASM_PFX(PthreadMutexUnLock) + + popq %rdi // restore state + popq %rsi + popq %rbp + ret + +ASM_GLOBAL ASM_PFX(GasketPthreadMutexTryLock) +ASM_PFX(GasketPthreadMutexTryLock): + pushq %rbp // stack frame is for the debugger + movq %rsp, %rbp + + pushq %rsi // %rsi & %rdi are volatile in Unix and callee-save in EFI ABI + pushq %rdi + + movq %rcx, %rdi // Swizzle args + + call ASM_PFX(PthreadMutexTryLock) + + popq %rdi // restore state + popq %rsi + popq %rbp + ret + +ASM_GLOBAL ASM_PFX(GasketPthreadMutexInit) +ASM_PFX(GasketPthreadMutexInit): + pushq %rbp // stack frame is for the debugger + movq %rsp, %rbp + + pushq %rsi // %rsi & %rdi are volatile in Unix and callee-save in EFI ABI + pushq %rdi + + + call ASM_PFX(PthreadMutexInit) + + popq %rdi // restore state + popq %rsi + popq %rbp + ret + + + +ASM_GLOBAL ASM_PFX(GasketPthreadMutexDestroy) +ASM_PFX(GasketPthreadMutexDestroy): + pushq %rbp // stack frame is for the debugger + movq %rsp, %rbp + + pushq %rsi // %rsi & %rdi are volatile in Unix and callee-save in EFI ABI + pushq %rdi + + movq %rcx, %rdi // Swizzle args + + call ASM_PFX(PthreadMutexDestroy) + + popq %rdi // restore state + popq %rsi + popq %rbp + ret + + +ASM_GLOBAL ASM_PFX(GasketPthreadCreate) +ASM_PFX(GasketPthreadCreate): + pushq %rbp // stack frame is for the debugger + movq %rsp, %rbp + + pushq %rsi // %rsi & %rdi are volatile in Unix and callee-save in EFI ABI + pushq %rdi + + movq %rcx, %rdi // Swizzle args + movq %rdx, %rsi + movq %r8, %rdx + movq %r9, %rcx + + call ASM_PFX(PthreadCreate) + + popq %rdi // restore state + popq %rsi + popq %rbp + ret + + +ASM_GLOBAL ASM_PFX(GasketPthreadExit) +ASM_PFX(GasketPthreadExit): + pushq %rbp // stack frame is for the debugger + movq %rsp, %rbp + + pushq %rsi // %rsi & %rdi are volatile in Unix and callee-save in EFI ABI + pushq %rdi + + movq %rcx, %rdi // Swizzle args + + call ASM_PFX(PthreadExit) + + popq %rdi // restore state + popq %rsi + popq %rbp + ret + + + +ASM_GLOBAL ASM_PFX(GasketPthreadSelf) +ASM_PFX(GasketPthreadSelf): + pushq %rbp // stack frame is for the debugger + movq %rsp, %rbp + + pushq %rsi // %rsi & %rdi are volatile in Unix and callee-save in EFI ABI + pushq %rdi + + + call ASM_PFX(PthreadSelf) + + popq %rdi // restore state + popq %rsi + popq %rbp + ret + + +ASM_GLOBAL ASM_PFX(GasketPthreadOpen) +ASM_PFX(GasketPthreadOpen): + pushq %rbp // stack frame is for the debugger + movq %rsp, %rbp + + pushq %rsi // %rsi & %rdi are volatile in Unix and callee-save in EFI ABI + pushq %rdi + + movq %rcx, %rdi // Swizzle args + + call ASM_PFX(PthreadOpen) + + popq %rdi // restore state + popq %rsi + popq %rbp + ret + + +ASM_GLOBAL ASM_PFX(GasketPthreadClose) +ASM_PFX(GasketPthreadClose): + pushq %rbp // stack frame is for the debugger + movq %rsp, %rbp + + pushq %rsi // %rsi & %rdi are volatile in Unix and callee-save in EFI ABI + pushq %rdi + + movq %rcx, %rdi // Swizzle args + + call ASM_PFX(PthreadClose) + + popq %rdi // restore state + popq %rsi + popq %rbp + ret + + + + +// +// UNIX ABI to EFI ABI call +// +// UINTN +// ReverseGasketUint64 ( +// void *Api, +// UINTN Arg1 +// ); +ASM_GLOBAL ASM_PFX(ReverseGasketUint64) +ASM_PFX(ReverseGasketUint64): + pushq %rbp // stack frame is for the debugger + movq %rsp, %rbp + + movq %rdi, %rax // Swizzle args + movq %rsi, %rcx + + subq $32, %rsp // 32-byte shadow space + call *%rax + addq $32, %rsp + + popq %rbp + ret + +// +// UNIX ABI to EFI ABI call +// +// UINTN +// ReverseGasketUint64Uint64 ( +// void *Api, +// UINTN Arg1 +// UINTN Arg2 +// ); +ASM_GLOBAL ASM_PFX(ReverseGasketUint64Uint64) +ASM_PFX(ReverseGasketUint64Uint64): + pushq %rbp // stack frame is for the debugger + movq %rsp, %rbp + + movq %rdi, %rax // Swizzle args + movq %rsi, %rcx + + subq $32, %rsp // 32-byte shadow space + call *%rax + addq $32, %rsp + + popq %rbp + ret + + +// Sec PPI Callbacks - Check Me + +ASM_GLOBAL ASM_PFX(GasketSecUnixPeiLoadFile) +ASM_PFX(GasketSecUnixPeiLoadFile): + pushq %rbp // stack frame is for the debugger + movq %rsp, %rbp + + pushq %rsi // %rsi & %rdi are volatile in Unix and callee-save in EFI ABI + pushq %rdi + + movq %rcx, %rdi // Swizzle args + movq %rdx, %rsi + movq %r8, %rdx + movq %r9, %rcx + + call ASM_PFX(SecUnixPeiLoadFile) + + popq %rdi // restore state + popq %rsi + popq %rbp + ret + + + +ASM_GLOBAL ASM_PFX(GasketSecUnixPeiAutoScan) +ASM_PFX(GasketSecUnixPeiAutoScan): + pushq %rbp // stack frame is for the debugger + movq %rsp, %rbp + + pushq %rsi // %rsi & %rdi are volatile in Unix and callee-save in EFI ABI + pushq %rdi + + movq %rcx, %rdi // Swizzle args + movq %rdx, %rsi + movq %r8, %rdx + + call ASM_PFX(SecUnixPeiAutoScan) + + popq %rdi // restore state + popq %rsi + popq %rbp + ret + + +ASM_GLOBAL ASM_PFX(GasketSecUnixFdAddress) +ASM_PFX(GasketSecUnixFdAddress): + pushq %rbp // stack frame is for the debugger + movq %rsp, %rbp + + pushq %rsi // %rsi & %rdi are volatile in Unix and callee-save in EFI ABI + pushq %rdi + + movq %rcx, %rdi // Swizzle args + movq %rdx, %rsi + movq %r8, %rdx + movq %r9, %rcx + + call ASM_PFX(SecUnixFdAddress) + + popq %rdi // restore state + popq %rsi + popq %rbp + ret + + +// EmuIoThunk SimpleFileSystem + +ASM_GLOBAL ASM_PFX(GasketPosixOpenVolume) +ASM_PFX(GasketPosixOpenVolume): + pushq %rbp // stack frame is for the debugger + movq %rsp, %rbp + + pushq %rsi // %rsi & %rdi are volatile in Unix and callee-save in EFI ABI + pushq %rdi + + movq %rcx, %rdi // Swizzle args + movq %rdx, %rsi + movq %r8, %rdx + movq %r9, %rcx + + call ASM_PFX(PosixOpenVolume) + + popq %rdi // restore state + popq %rsi + popq %rbp + ret + + +ASM_GLOBAL ASM_PFX(GasketPosixFileOpen) +ASM_PFX(GasketPosixFileOpen): + pushq %rbp // stack frame is for the debugger + movq %rsp, %rbp + + pushq %rsi // %rsi & %rdi are volatile in Unix and callee-save in EFI ABI + pushq %rdi + + movq %rcx, %rdi // Swizzle args + movq %rdx, %rsi + movq %r8, %rdx + movq %r9, %rcx + movq 0x30(%rbp), %r8 + + call ASM_PFX(PosixFileOpen) + + popq %rdi // restore state + popq %rsi + popq %rbp + ret + + +ASM_GLOBAL ASM_PFX(GasketPosixFileCLose) +ASM_PFX(GasketPosixFileCLose): + pushq %rbp // stack frame is for the debugger + movq %rsp, %rbp + + pushq %rsi // %rsi & %rdi are volatile in Unix and callee-save in EFI ABI + pushq %rdi + + movq %rcx, %rdi // Swizzle args + + call ASM_PFX(PosixFileCLose) + + popq %rdi // restore state + popq %rsi + popq %rbp + ret + + +ASM_GLOBAL ASM_PFX(GasketPosixFileDelete) +ASM_PFX(GasketPosixFileDelete): + pushq %rbp // stack frame is for the debugger + movq %rsp, %rbp + + pushq %rsi // %rsi & %rdi are volatile in Unix and callee-save in EFI ABI + pushq %rdi + + movq %rcx, %rdi // Swizzle args + + call ASM_PFX(PosixFileDelete) + + popq %rdi // restore state + popq %rsi + popq %rbp + ret + + +ASM_GLOBAL ASM_PFX(GasketPosixFileRead) +ASM_PFX(GasketPosixFileRead): + pushq %rbp // stack frame is for the debugger + movq %rsp, %rbp + + pushq %rsi // %rsi & %rdi are volatile in Unix and callee-save in EFI ABI + pushq %rdi + + movq %rcx, %rdi // Swizzle args + movq %rdx, %rsi + movq %r8, %rdx + + call ASM_PFX(PosixFileRead) + + popq %rdi // restore state + popq %rsi + popq %rbp + ret + + +ASM_GLOBAL ASM_PFX(GasketPosixFileWrite) +ASM_PFX(GasketPosixFileWrite): + pushq %rbp // stack frame is for the debugger + movq %rsp, %rbp + + pushq %rsi // %rsi & %rdi are volatile in Unix and callee-save in EFI ABI + pushq %rdi + + movq %rcx, %rdi // Swizzle args + movq %rdx, %rsi + movq %r8, %rdx + + call ASM_PFX(PosixFileWrite) + + popq %rdi // restore state + popq %rsi + popq %rbp + ret + + +ASM_GLOBAL ASM_PFX(GasketPosixFileSetPossition) +ASM_PFX(GasketPosixFileSetPossition): + pushq %rbp // stack frame is for the debugger + movq %rsp, %rbp + + pushq %rsi // %rsi & %rdi are volatile in Unix and callee-save in EFI ABI + pushq %rdi + + movq %rcx, %rdi // Swizzle args + movq %rdx, %rsi + + call ASM_PFX(PosixFileSetPossition) + + popq %rdi // restore state + popq %rsi + popq %rbp + ret + + +ASM_GLOBAL ASM_PFX(GasketPosixFileGetPossition) +ASM_PFX(GasketPosixFileGetPossition): + pushq %rbp // stack frame is for the debugger + movq %rsp, %rbp + + pushq %rsi // %rsi & %rdi are volatile in Unix and callee-save in EFI ABI + pushq %rdi + + movq %rcx, %rdi // Swizzle args + movq %rdx, %rsi + + call ASM_PFX(PosixFileGetPossition) + + popq %rdi // restore state + popq %rsi + popq %rbp + ret + + +ASM_GLOBAL ASM_PFX(GasketPosixFileGetInfo) +ASM_PFX(GasketPosixFileGetInfo): + pushq %rbp // stack frame is for the debugger + movq %rsp, %rbp + + pushq %rsi // %rsi & %rdi are volatile in Unix and callee-save in EFI ABI + pushq %rdi + + movq %rcx, %rdi // Swizzle args + movq %rdx, %rsi + movq %r8, %rdx + movq %r9, %rcx + + call ASM_PFX(PosixFileGetInfo) + + popq %rdi // restore state + popq %rsi + popq %rbp + ret + + +ASM_GLOBAL ASM_PFX(GasketPosixFileSetInfo) +ASM_PFX(GasketPosixFileSetInfo): + pushq %rbp // stack frame is for the debugger + movq %rsp, %rbp + + pushq %rsi // %rsi & %rdi are volatile in Unix and callee-save in EFI ABI + pushq %rdi + + movq %rcx, %rdi // Swizzle args + movq %rdx, %rsi + movq %r8, %rdx + movq %r9, %rcx + + call ASM_PFX(PosixFileSetInfo) + + popq %rdi // restore state + popq %rsi + popq %rbp + ret + + +ASM_GLOBAL ASM_PFX(GasketPosixFileFlush) +ASM_PFX(GasketPosixFileFlush): + pushq %rbp // stack frame is for the debugger + movq %rsp, %rbp + + pushq %rsi // %rsi & %rdi are volatile in Unix and callee-save in EFI ABI + pushq %rdi + + movq %rcx, %rdi // Swizzle args + + call ASM_PFX(PosixFileFlush) + + popq %rdi // restore state + popq %rsi + popq %rbp + ret + + +ASM_GLOBAL ASM_PFX(GasketPosixFileSystmeThunkOpen) +ASM_PFX(GasketPosixFileSystmeThunkOpen): + pushq %rbp // stack frame is for the debugger + movq %rsp, %rbp + + pushq %rsi // %rsi & %rdi are volatile in Unix and callee-save in EFI ABI + pushq %rdi + + movq %rcx, %rdi // Swizzle args + + call ASM_PFX(PosixFileSystmeThunkOpen) + + popq %rdi // restore state + popq %rsi + popq %rbp + ret + + +ASM_GLOBAL ASM_PFX(GasketPosixFileSystmeThunkClose) +ASM_PFX(GasketPosixFileSystmeThunkClose): + pushq %rbp // stack frame is for the debugger + movq %rsp, %rbp + + pushq %rsi // %rsi & %rdi are volatile in Unix and callee-save in EFI ABI + pushq %rdi + + movq %rcx, %rdi // Swizzle args + + call ASM_PFX(PosixFileSystmeThunkClose) + + popq %rdi // restore state + popq %rsi + popq %rbp + ret + + + + + + + diff --git a/InOsEmuPkg/Unix/Sec/X64/SwitchStack.S b/InOsEmuPkg/Unix/Sec/X64/SwitchStack.S new file mode 100644 index 0000000..0d4e502 --- /dev/null +++ b/InOsEmuPkg/Unix/Sec/X64/SwitchStack.S @@ -0,0 +1,112 @@ +#------------------------------------------------------------------------------
+#
+# Copyright (c) 2006 - 2008, Intel Corporation. All rights reserved.<BR>
+# Portitions copyright (c) 2011, Apple Inc. 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.
+#
+#------------------------------------------------------------------------------
+
+
+#------------------------------------------------------------------------------
+# Routine Description:
+#
+# Routine for switching stacks with 3 parameters EFI ABI
+# Convert UNIX to EFI ABI
+#
+# Arguments:
+#
+# (rdi) EntryPoint - Entry point with new stack.
+# (rsi) Context1 - Parameter1 for entry point. (rcx)
+# (rdx) Context2 - Parameter2 for entry point. (rdx)
+# (rcx) Context3 - Parameter3 for entry point. (r8)
+# (r8) NewStack - The pointer to new stack.
+#
+# Returns:
+#
+# None
+#
+#------------------------------------------------------------------------------
+ASM_GLOBAL ASM_PFX(PeiSwitchStacks)
+ASM_PFX(PeiSwitchStacks):
+ pushq $0 // tells gdb to stop unwinding frame
+ movq %rsp, %rbp
+
+ movq %r8, %rsp
+
+ movq %rdi, %rax
+ movq %rsi, %rcx
+ movq %rcx, %r8
+
+ #
+ # Reserve space for register parameters (rcx, rdx, r8 & r9) on the stack,
+ # in case the callee wishes to spill them.
+ #
+ subq $32, %rsp // 32-byte shadow space plus alignment pad
+ call *%rax
+
+
+
+// EFI_STATUS
+// EFIAPI
+// SecTemporaryRamSupport (
+// IN CONST EFI_PEI_SERVICES **PeiServices, // %rcx
+// IN EFI_PHYSICAL_ADDRESS TemporaryMemoryBase, // %rdx
+// IN EFI_PHYSICAL_ADDRESS PermanentMemoryBase, // %r8
+// IN UINTN CopySize // %r9
+// )
+//
+ASM_GLOBAL ASM_PFX(GasketSecTemporaryRamSupport)
+ASM_PFX(GasketSecTemporaryRamSupport):
+ // Adjust callers %rbp to account for stack move
+ subq %rdx, %rbp // Calc offset of %rbp in Temp Memory
+ addq %r8, %rbp // add in permanent base to offset
+
+ pushq %rbp // stack frame is for the debugger
+ movq %rsp, %rbp
+
+ pushq %rsi // %rsi & %rdi are volatile in Unix and callee-save in EFI ABI
+ pushq %rdi
+
+ pushq %rdx // Save TemporaryMemoryBase
+ pushq %r8 // Save PermanentMemoryBase
+ pushq %r9 // Save CopySize
+
+ //
+ // Copy all of temp RAM to permanent memory, including stack
+ //
+ // CopyMem (PermanentMemoryBase, TemporaryMemoryBase, CopySize);
+ // %rdi, %rsi, %rdx
+ movq %r8, %rdi // Swizzle args
+ movq %rdx, %rsi
+ movq %r9, %rdx
+ call ASM_PFX(CopyMem)
+ // Temp mem stack now copied to permanent location. %esp still in temp memory
+
+ popq %r9 // CopySize (old stack)
+ popq %r8 // PermanentMemoryBase (old stack)
+ popq %rdx // TemporaryMemoryBase (old stack)
+
+ movq %rsp, %rcx // Move to new stack
+ subq %rdx, %rcx // Calc offset of stack in Temp Memory
+ addq %r8, %rcx // Calc PermanentMemoryBase address
+ movq %rcx, %rsp // Update stack
+ // Stack now points to permanent memory
+
+ // ZeroMem (TemporaryMemoryBase /* rdi */, CopySize /* rsi */);
+ movq %rdx, %rdi
+ movq %r9, %rsi
+ call ASM_PFX(ZeroMem)
+
+ // This data comes off the NEW stack
+ popq %rdi
+ popq %rsi
+ popq %rbp
+ ret
+
+
|