summaryrefslogtreecommitdiff
path: root/StdLib/LibC/Uefi
diff options
context:
space:
mode:
Diffstat (limited to 'StdLib/LibC/Uefi')
-rw-r--r--StdLib/LibC/Uefi/Console.c393
-rw-r--r--StdLib/LibC/Uefi/SysCalls.c1198
-rw-r--r--StdLib/LibC/Uefi/SysEfi.h37
-rw-r--r--StdLib/LibC/Uefi/Uefi.inf49
-rw-r--r--StdLib/LibC/Uefi/Xform.c173
5 files changed, 1850 insertions, 0 deletions
diff --git a/StdLib/LibC/Uefi/Console.c b/StdLib/LibC/Uefi/Console.c
new file mode 100644
index 0000000000..0c3a21cf45
--- /dev/null
+++ b/StdLib/LibC/Uefi/Console.c
@@ -0,0 +1,393 @@
+/** @file
+ File abstractions of the console.
+
+ Manipulates EFI_FILE_PROTOCOL abstractions for stdin, stdout, stderr.
+
+ Copyright (c) 2010, 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 that 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 <Uefi.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+
+#include <LibConfig.h>
+#include <sys/EfiCdefs.h>
+
+#include <stdio.h>
+#include <sys/fcntl.h>
+#include <MainData.h>
+#include <Efi/Console.h>
+
+static const CHAR16 * stdioNames[NUM_SPECIAL] = {
+ L"stdin:", L"stdout:", L"stderr:"
+};
+static const int stdioFlags[NUM_SPECIAL] = {
+ O_RDONLY, // stdin
+ O_WRONLY, // stdout
+ O_WRONLY // stderr
+};
+
+static const int stdioMode[NUM_SPECIAL] = {
+ 0444, // stdin
+ 0222, // stdout
+ 0222 // stderr
+};
+
+static
+EFI_STATUS
+EFIAPI
+ConClose(
+ IN EFI_FILE_PROTOCOL *This
+ )
+{
+ ConInstance *Stream;
+
+ Stream = BASE_CR(This, ConInstance, Abstraction);
+ // Quick check to see if Stream looks reasonable
+ if(Stream->Cookie != 0x62416F49) { // Cookie == 'IoAb'
+ return RETURN_INVALID_PARAMETER; // Looks like a bad This pointer
+ }
+ // Nothing to Flush.
+ // Mark the Stream as closed.
+ Stream->Dev = NULL;
+
+ return RETURN_SUCCESS;
+}
+
+static
+EFI_STATUS
+EFIAPI
+ConDelete(
+ IN EFI_FILE_PROTOCOL *This
+ )
+{
+ return RETURN_UNSUPPORTED;
+}
+
+static
+EFI_STATUS
+EFIAPI
+ConRead(
+ IN EFI_FILE_PROTOCOL *This,
+ IN OUT UINTN *BufferSize,
+ OUT VOID *Buffer
+ )
+{
+ EFI_SIMPLE_TEXT_INPUT_PROTOCOL *Proto;
+ ConInstance *Stream;
+ CHAR16 *OutPtr;
+ EFI_INPUT_KEY Key;
+ UINTN NumChar;
+ UINTN Edex;
+ EFI_STATUS Status;
+ UINTN i;
+
+ Stream = BASE_CR(This, ConInstance, Abstraction);
+ // Quick check to see if Stream looks reasonable
+ if(Stream->Cookie != 0x62416F49) { // Cookie == 'IoAb'
+ return RETURN_INVALID_PARAMETER; // Looks like a bad This pointer
+ }
+ if(Stream->Dev == NULL) {
+ // Can't read from an unopened Stream
+ return RETURN_DEVICE_ERROR;
+ }
+ if(Stream != &gMD->StdIo[0]) {
+ // Read only valid for stdin
+ return RETURN_UNSUPPORTED;
+ }
+ // It looks like things are OK for trying to read
+ // We will accumulate *BufferSize characters or until we encounter
+ // an "activation" character. Currently any control character.
+ Proto = (EFI_SIMPLE_TEXT_INPUT_PROTOCOL *)Stream->Dev;
+ OutPtr = Buffer;
+ NumChar = (*BufferSize - 1) / sizeof(CHAR16);
+ i = 0;
+ do {
+ Status = gBS->WaitForEvent( 1, &Proto->WaitForKey, &Edex);
+ if(Status != EFI_SUCCESS) {
+ break;
+ }
+ Status = Proto->ReadKeyStroke(Proto, &Key);
+ if(Status != EFI_SUCCESS) {
+ break;
+ }
+ if(Key.ScanCode == SCAN_NULL) {
+ *OutPtr++ = Key.UnicodeChar;
+ ++i;
+ }
+ if(Key.UnicodeChar < 0x0020) { // If a control character, or a scan code
+ break;
+ }
+ } while(i < NumChar);
+ *BufferSize = i * sizeof(CHAR16);
+ return Status;
+}
+
+/* Write a NULL terminated WCS to the EFI console.
+
+ @param[in,out] BufferSize Number of bytes in Buffer. Set to zero if
+ the string couldn't be displayed.
+ @parem[in] Buffer The WCS string to be displayed
+
+*/
+static
+EFI_STATUS
+EFIAPI
+ConWrite(
+ IN EFI_FILE_PROTOCOL *This,
+ IN OUT UINTN *BufferSize,
+ IN VOID *Buffer
+ )
+{
+ EFI_STATUS Status;
+ EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *Proto;
+ ConInstance *Stream;
+ CHAR16 *MyBuf;
+ UINTN NumChar;
+
+ Stream = BASE_CR(This, ConInstance, Abstraction);
+ // Quick check to see if Stream looks reasonable
+ if(Stream->Cookie != 0x62416F49) { // Cookie == 'IoAb'
+ return RETURN_INVALID_PARAMETER; // Looks like a bad This pointer
+ }
+ if(Stream->Dev == NULL) {
+ // Can't write to an unopened Stream
+ return RETURN_DEVICE_ERROR;
+ }
+ if(Stream == &gMD->StdIo[0]) {
+ // Write is not valid for stdin
+ return RETURN_UNSUPPORTED;
+ }
+ // Everything is OK to do the write.
+ Proto = (EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *)Stream->Dev;
+ MyBuf = (CHAR16 *)Buffer;
+ NumChar = *BufferSize;
+
+ // Send MyBuf to the console
+ Status = Proto->OutputString( Proto, MyBuf);
+ // Depending on status, update BufferSize and return
+ if(Status != EFI_SUCCESS) {
+ *BufferSize = 0; // We don't really know how many characters made it out
+ }
+ else {
+ *BufferSize = NumChar;
+ Stream->NumWritten += NumChar;
+ }
+ return Status;
+}
+
+static
+EFI_STATUS
+EFIAPI
+ConGetPosition(
+ IN EFI_FILE_PROTOCOL *This,
+ OUT UINT64 *Position
+ )
+{
+ ConInstance *Stream;
+ EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *Proto;
+ XYoffset CursorPos;
+
+ Stream = BASE_CR(This, ConInstance, Abstraction);
+ // Quick check to see if Stream looks reasonable
+ if(Stream->Cookie != 0x62416F49) { // Cookie == 'IoAb'
+ return RETURN_INVALID_PARAMETER; // Looks like a bad This pointer
+ }
+ if(Stream == &gMD->StdIo[0]) {
+ // This is stdin
+ *Position = Stream->NumRead;
+ }
+ else {
+ Proto = (EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *)Stream->Dev;
+ CursorPos.XYpos.Column = (UINT32)Proto->Mode->CursorColumn;
+ CursorPos.XYpos.Row = (UINT32)Proto->Mode->CursorRow;
+ *Position = CursorPos.Offset;
+ }
+ return RETURN_SUCCESS;
+}
+
+static
+EFI_STATUS
+EFIAPI
+ConSetPosition(
+ IN EFI_FILE_PROTOCOL *This,
+ IN UINT64 Position
+ )
+{
+ ConInstance *Stream;
+ EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *Proto;
+ XYoffset CursorPos;
+
+ Stream = BASE_CR(This, ConInstance, Abstraction);
+ // Quick check to see if Stream looks reasonable
+ if(Stream->Cookie != 0x62416F49) { // Cookie == 'IoAb'
+ return RETURN_INVALID_PARAMETER; // Looks like a bad This pointer
+ }
+ if(Stream->Dev == NULL) {
+ // Can't write to an unopened Stream
+ return RETURN_DEVICE_ERROR;
+ }
+ if(Stream == &gMD->StdIo[0]) {
+ // Seek is not valid for stdin
+ return RETURN_UNSUPPORTED;
+ }
+ // Everything is OK to do the final verification and "seek".
+ Proto = (EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *)Stream->Dev;
+ CursorPos.Offset = Position;
+
+ return Proto->SetCursorPosition(Proto,
+ (INTN)CursorPos.XYpos.Column,
+ (INTN)CursorPos.XYpos.Row);
+}
+
+static
+EFI_STATUS
+EFIAPI
+ConGetInfo(
+ IN EFI_FILE_PROTOCOL *This,
+ IN EFI_GUID *InformationType,
+ IN OUT UINTN *BufferSize,
+ OUT VOID *Buffer
+ )
+{
+ EFI_FILE_INFO *InfoBuf;
+ ConInstance *Stream;
+
+ Stream = BASE_CR(This, ConInstance, Abstraction);
+ // Quick check to see if Stream looks reasonable
+ if((Stream->Cookie != 0x62416F49) || // Cookie == 'IoAb'
+ (Buffer == NULL))
+ {
+ return RETURN_INVALID_PARAMETER;
+ }
+ if(*BufferSize < sizeof(EFI_FILE_INFO)) {
+ *BufferSize = sizeof(EFI_FILE_INFO);
+ return RETURN_BUFFER_TOO_SMALL;
+ }
+ // All of our parameters are correct, so fill in the information.
+ (void) ZeroMem(Buffer, sizeof(EFI_FILE_INFO));
+ InfoBuf = (EFI_FILE_INFO *)Buffer;
+ InfoBuf->Size = sizeof(EFI_FILE_INFO);
+ InfoBuf->FileSize = 1;
+ InfoBuf->PhysicalSize = 1;
+ *BufferSize = sizeof(EFI_FILE_INFO);
+
+ return RETURN_SUCCESS;
+}
+
+static
+EFI_STATUS
+EFIAPI
+ConSetInfo(
+ IN EFI_FILE_PROTOCOL *This,
+ IN EFI_GUID *InformationType,
+ IN UINTN BufferSize,
+ IN VOID *Buffer
+ )
+{
+ return RETURN_UNSUPPORTED;
+}
+
+static
+EFI_STATUS
+EFIAPI
+ConFlush(
+ IN EFI_FILE_PROTOCOL *This
+ )
+{
+ return RETURN_SUCCESS;
+}
+
+EFI_STATUS
+EFIAPI
+ConOpen(
+ IN EFI_FILE_PROTOCOL *This,
+ OUT EFI_FILE_PROTOCOL **NewHandle,
+ IN CHAR16 *FileName,
+ IN UINT64 OpenMode, // Ignored
+ IN UINT64 Attributes // Ignored
+ )
+{
+ ConInstance *Stream;
+ EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *Proto;
+ UINTN Columns;
+ UINTN Rows;
+ int i;
+
+ if((NewHandle == NULL) ||
+ (FileName == NULL))
+ {
+ return RETURN_INVALID_PARAMETER;
+ }
+ // Process FileName
+ for(i = 0; i < NUM_SPECIAL; ++i) {
+ if(StrCmp( stdioNames[i], FileName) == 0) {
+ break;
+ }
+ }
+ if(i >= NUM_SPECIAL) {
+ return RETURN_NO_MAPPING;
+ }
+ // Get pointer to instance.
+ Stream = &gMD->StdIo[i];
+ if(Stream->Dev == NULL) {
+ // If this stream has been closed, then
+ // Initialize instance.
+ Stream->Cookie = 0x62416F49;
+ Stream->NumRead = 0;
+ Stream->NumWritten = 0;
+ switch(i) {
+ case 0:
+ Stream->Dev = gST->ConIn;
+ break;
+ case 1:
+ Stream->Dev = gST->ConOut;
+ break;
+ case 2:
+ if(gST->StdErr == NULL) {
+ Stream->Dev = gST->ConOut;
+ }
+ else {
+ Stream->Dev = gST->StdErr;
+ }
+ break;
+ default:
+ return RETURN_VOLUME_CORRUPTED; // This is a "should never happen" case.
+ }
+ Stream->Abstraction.Revision = 0x00010000;
+ Stream->Abstraction.Open = &ConOpen;
+ Stream->Abstraction.Close = &ConClose;
+ Stream->Abstraction.Delete = &ConDelete;
+ Stream->Abstraction.Read = &ConRead;
+ Stream->Abstraction.Write = &ConWrite;
+ Stream->Abstraction.GetPosition = &ConGetPosition;
+ Stream->Abstraction.SetPosition = &ConSetPosition;
+ Stream->Abstraction.GetInfo = &ConGetInfo;
+ Stream->Abstraction.SetInfo = &ConSetInfo;
+ Stream->Abstraction.Flush = &ConFlush;
+ // Get additional information if this is an Output stream
+ if(i != 0) {
+ Proto = Stream->Dev;
+ Stream->ConOutMode = Proto->Mode->Mode;
+ if( Proto->QueryMode(Proto, Stream->ConOutMode, &Columns, &Rows) != RETURN_SUCCESS) {
+ Stream->Dev = NULL; // Mark this stream as closed
+ return RETURN_INVALID_PARAMETER;
+ }
+ Stream->MaxConXY.XYpos.Column = (UINT32)Columns;
+ Stream->MaxConXY.XYpos.Row = (UINT32)Rows;
+ }
+ }
+ // Save NewHandle and return.
+ *NewHandle = &Stream->Abstraction;
+
+ return RETURN_SUCCESS;
+}
diff --git a/StdLib/LibC/Uefi/SysCalls.c b/StdLib/LibC/Uefi/SysCalls.c
new file mode 100644
index 0000000000..624d45878e
--- /dev/null
+++ b/StdLib/LibC/Uefi/SysCalls.c
@@ -0,0 +1,1198 @@
+/** @file
+ EFI versions of NetBSD system calls.
+
+ Copyright (c) 2010 - 2011, 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 that accompanies this distribution.
+ The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.
+
+ 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 <Uefi.h>
+#include <Library/UefiLib.h>
+#include <Library/BaseLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/ShellLib.h>
+
+#include <LibConfig.h>
+#include <sys/EfiCdefs.h>
+
+#include <sys/ansi.h>
+#include <errno.h>
+#include <stdarg.h>
+#include <string.h>
+#include <wchar.h>
+#include <sys/fcntl.h>
+#include <sys/stat.h>
+#include <sys/syslimits.h>
+#include "SysEfi.h"
+#include <MainData.h>
+#include <extern.h> // Library/include/extern.h: Private to implementation
+#include <Efi/Console.h>
+
+/* Macros only used in this file. */
+// Parameters for the ValidateFD function.
+#define VALID_OPEN 1
+#define VALID_CLOSED 0
+#define VALID_DONT_CARE -1
+
+
+/* EFI versions of BSD system calls used in stdio */
+
+/* Normalize path so that forward slashes are replaced with backslashes.
+ Backslashes are required for UEFI.
+*/
+static void
+NormalizePath( const CHAR16 *path)
+{
+ CHAR16 *temp;
+
+ for( temp = (CHAR16 *)path; *temp; ++temp) {
+ if(*temp == L'/') {
+ *temp = L'\\';
+ }
+ }
+}
+
+/* Validate that fd refers to a valid file descriptor.
+ IsOpen is interpreted as follows:
+ - Positive fd must be OPEN
+ - Zero fd must be CLOSED
+ - Negative fd may be OPEN or CLOSED
+
+ @retval TRUE fd is VALID
+ @retval FALSE fd is INVALID
+*/
+static BOOLEAN
+ValidateFD( int fd, int IsOpen)
+{
+ BOOLEAN retval = FALSE;
+
+ if((fd >= 0) && (fd < OPEN_MAX)) {
+ retval = TRUE;
+ if(IsOpen >= 0) {
+ retval = (BOOLEAN)(gMD->fdarray[fd].State != 0); // TRUE if OPEN
+ if(IsOpen == VALID_CLOSED) {
+ retval = (BOOLEAN)!retval; // We want TRUE if CLOSED
+ }
+ }
+ }
+ return retval;
+}
+
+/* Find and reserve a free File Descriptor.
+
+ Returns the first free File Descriptor greater than or equal to the,
+ already validated, fd specified by Minfd.
+
+ @return Returns -1 if there are no free FDs. Otherwise returns the
+ found fd.
+*/
+static int
+FindFreeFD( int MinFd )
+{
+ struct __filedes *Mfd;
+ int i;
+ int fd = -1;
+
+ Mfd = gMD->fdarray;
+
+ // Get an available fd
+ for(i=MinFd; i < OPEN_MAX; ++i) {
+ if(Mfd[i].State == 0) {
+ Mfd[i].State = S_ISYSTEM; // Temporarily mark this fd as reserved
+ fd = i;
+ break;
+ }
+ }
+ return fd;
+}
+
+/** The isatty() function tests whether fildes, an open file descriptor,
+ is associated with a terminal device.
+
+ @retval 1 fildes is associated with a terminal.
+ @retval 0 fildes is not associated with a terminal. errno is set to
+ EBADF if fildes is not a valid open FD.
+**/
+int
+isatty (int fildes)
+{
+ int retval = 0;
+ EFI_FILE_HANDLE FileHandle;
+
+ if(ValidateFD( fildes, VALID_OPEN)) {
+ FileHandle = gMD->fdarray[fildes].FileHandle;
+ retval = (FileHandle >= &gMD->StdIo[0].Abstraction) &&
+ (FileHandle <= &gMD->StdIo[2].Abstraction);
+ }
+ else {
+ errno = EBADF;
+ }
+ return retval;
+}
+
+static BOOLEAN
+IsDupFd( int fd)
+{
+ EFI_FILE_HANDLE FileHandle;
+ int i;
+ BOOLEAN Ret = FALSE;
+
+ if(ValidateFD( fd, VALID_OPEN )) {
+ FileHandle = gMD->fdarray[fd].FileHandle;
+ for(i=0; i < OPEN_MAX; ++i) {
+ if(i == fd) continue;
+ if(gMD->fdarray[i].State != 0) { // TRUE if fd is OPEN
+ if(gMD->fdarray[i].FileHandle == FileHandle) {
+ Ret = TRUE;
+ break;
+ }
+ }
+ }
+ }
+ return Ret;
+}
+
+static int
+_closeX (int fd, int NewState)
+{
+ struct __filedes *Mfd;
+ RETURN_STATUS Status;
+ int retval = 0;
+
+ Status = EFIerrno = RETURN_SUCCESS; // In case of error before the EFI call.
+
+ // Verify my pointers and get my FD.
+ if(ValidateFD( fd, VALID_OPEN )) {
+ Mfd = &gMD->fdarray[fd];
+ // Check if there are duplicates using this FileHandle
+ if(! IsDupFd(fd)) {
+ // Only do the close if no one else is using the FileHandle
+ if(isatty(fd)) {
+ Status = Mfd->FileHandle->Close( Mfd->FileHandle);
+ }
+ else {
+ Status = ShellCloseFile( (SHELL_FILE_HANDLE *)&Mfd->FileHandle);
+ }
+ }
+ Mfd->State = NewState; // Close this FD or reserve it
+ if(Status != RETURN_SUCCESS) {
+ errno = EFI2errno(Status);
+ EFIerrno = Status;
+ retval = -1;
+ }
+ }
+ else {
+ // Bad FD
+ errno = EBADF;
+ retval = -1;
+ }
+ return retval;
+}
+
+/** The close() function shall deallocate the file descriptor indicated by fd.
+ To deallocate means to make the file descriptor available for return by
+ subsequent calls to open() or other functions that allocate file
+ descriptors. All outstanding record locks owned by the process on the file
+ associated with the file descriptor shall be removed (that is, unlocked).
+
+ @return Upon successful completion, 0 shall be returned; otherwise,
+ -1 shall be returned and errno set to indicate the error.
+**/
+int
+close (int fd)
+{
+ //Print(L"Closing fd %d\n", fd);
+ return _closeX(fd, 0);
+}
+
+/* Wide character version of unlink */
+int
+Uunlink (const wchar_t *Path)
+{
+ EFI_FILE_HANDLE FileHandle;
+ RETURN_STATUS Status;
+
+ EFIerrno = RETURN_SUCCESS;
+
+ NormalizePath( Path);
+ // We can only delete open files.
+ Status = ShellOpenFileByName( Path, (SHELL_FILE_HANDLE *)&FileHandle, 3, 0);
+ if(Status != RETURN_SUCCESS) {
+ errno = EFI2errno(Status);
+ EFIerrno = Status;
+ return -1;
+ }
+ Status = ShellDeleteFile( (SHELL_FILE_HANDLE *)&FileHandle);
+ if(Status != RETURN_SUCCESS) {
+ errno = EFI2errno(Status);
+ EFIerrno = Status;
+ return -1;
+ }
+ return 0;
+}
+
+/**
+**/
+int
+unlink (const char *path)
+{
+ // Convert path from MBCS to WCS
+ (void)AsciiStrToUnicodeStr( path, gMD->UString);
+
+ return Uunlink(gMD->UString);
+}
+
+/** The fcntl() function shall perform the operations described below on open
+ files. The fildes argument is a file descriptor.
+
+ The available values for cmd are defined in <fcntl.h> and are as follows:
+ - F_DUPFD - Return a new file descriptor which shall be the lowest
+ numbered available (that is, not already open) file
+ descriptor greater than or equal to the third argument, arg,
+ taken as an integer of type int. The new file descriptor
+ shall refer to the same open file description as the original
+ file descriptor, and shall share any locks. The FD_CLOEXEC
+ flag associated with the new file descriptor shall be cleared
+ to keep the file open across calls to one of the exec functions.
+ - F_GETFD - Get the file descriptor flags defined in <fcntl.h> that are
+ associated with the file descriptor fildes. File descriptor
+ flags are associated with a single file descriptor and do not
+ affect other file descriptors that refer to the same file.
+ - F_SETFD - Set the file descriptor flags defined in <fcntl.h>, that are
+ associated with fildes, to the third argument, arg, taken
+ as type int. If the FD_CLOEXEC flag in the third argument
+ is 0, the file shall remain open across the exec
+ functions; otherwise, the file shall be closed upon
+ successful execution of one of the exec functions.
+ - F_GETFL - Get the file status flags and file access modes, defined in
+ <fcntl.h>, for the file description associated with fildes.
+ The file access modes can be extracted from the return
+ value using the mask O_ACCMODE, which is defined in
+ <fcntl.h>. File status flags and file access modes are
+ associated with the file description and do not affect
+ other file descriptors that refer to the same file with
+ different open file descriptions.
+ - F_SETFL - Set the file status flags, defined in <fcntl.h>, for the file
+ description associated with fildes from the corresponding
+ bits in the third argument, arg, taken as type int. Bits
+ corresponding to the file access mode and the file creation
+ flags, as defined in <fcntl.h>, that are set in arg shall
+ be ignored. If any bits in arg other than those mentioned
+ here are changed by the application, the result is unspecified.
+ - F_GETOWN - If fildes refers to a socket, get the process or process group
+ ID specified to receive SIGURG signals when out-of-band
+ data is available. Positive values indicate a process ID;
+ negative values, other than -1, indicate a process group
+ ID. If fildes does not refer to a socket, the results are
+ unspecified.
+ - F_SETOWN - If fildes refers to a socket, set the process or process
+ group ID specified to receive SIGURG signals when
+ out-of-band data is available, using the value of the third
+ argument, arg, taken as type int. Positive values indicate
+ a process ID; negative values, other than -1, indicate a
+ process group ID. If fildes does not refer to a socket, the
+ results are unspecified.
+
+ The fcntl() function shall fail if:
+
+ [EBADF] The fildes argument is not a valid open file descriptor.
+ [EINVAL] The cmd argument is invalid, or the cmd argument is F_DUPFD
+ and arg is negative or greater than or equal to {OPEN_MAX}.
+ [EMFILE] The argument cmd is F_DUPFD and {OPEN_MAX} file descriptors
+ are currently open in the calling process, or no file
+ descriptors greater than or equal to arg are available.
+ [EOVERFLOW] One of the values to be returned cannot be represented correctly.
+
+ @return Upon successful completion, the value returned shall depend on
+ cmd as follows:
+ - F_DUPFD - A new file descriptor.
+ - F_GETFD - Value of flags defined in <fcntl.h>. The return value
+ shall not be negative.
+ - F_SETFD - Value other than -1.
+ - F_GETFL - Value of file status flags and access modes. The return
+ value is not negative.
+ - F_SETFL - Value other than -1.
+ - F_GETOWN - Value of the socket owner process or process group;
+ this will not be -1.
+ - F_SETOWN - Value other than -1.
+ Otherwise, -1 shall be returned and errno set to indicate the error.
+
+**/
+int
+fcntl (int fildes, int cmd, ...)
+{
+ va_list p3;
+ struct __filedes *MyFd;
+ int retval = -1;
+ int temp;
+
+//Print(L"%a( %d, %d, ...)\n", __func__, fildes, cmd);
+ va_start(p3, cmd);
+
+ if(ValidateFD( fildes, VALID_OPEN )) {
+ MyFd = &gMD->fdarray[fildes];
+
+ switch(cmd) {
+ case F_DUPFD:
+ temp = va_arg(p3, int);
+ if(ValidateFD( temp, VALID_DONT_CARE )) {
+ temp = FindFreeFD( temp );
+ if(temp < 0) {
+ errno = EMFILE;
+ break;
+ }
+ /* temp is now a valid fd reserved for further use
+ so copy fd into temp.
+ */
+ (void)memcpy(&gMD->fdarray[temp], MyFd, sizeof(struct __filedes));
+ retval = temp;
+ }
+ else {
+ errno = EINVAL;
+ }
+ break;
+ //case F_SETFD:
+ case F_SETFL:
+ retval = MyFd->Oflags; // Get original value
+ temp = va_arg(p3, int);
+ temp &= O_SETMASK; // Only certain bits can be set
+ temp |= retval & O_SETMASK;
+ MyFd->Oflags = temp; // Set new value
+ break;
+ //case F_SETFL:
+ case F_SETFD:
+ retval = MyFd->State;
+ break;
+ case F_SETOWN:
+ retval = MyFd->SocProc;
+ MyFd->SocProc = va_arg(p3, int);
+ break;
+ case F_GETFD:
+ //retval = MyFd->Oflags;
+ retval = MyFd->State;
+ break;
+ case F_GETFL:
+ //retval = MyFd->State;
+ retval = MyFd->Oflags;
+ break;
+ case F_GETOWN:
+ retval = MyFd->SocProc;
+ break;
+ default:
+ errno = EINVAL;
+ break;
+ }
+ }
+ else {
+ // Bad FD
+ errno = EBADF;
+ }
+ va_end(p3);
+ return retval;;
+}
+
+/** The dup() function provides an alternative interface to the
+ service provided by fcntl() using the F_DUPFD command. The call:
+ - fid = dup(fildes);
+ shall be equivalent to:
+ - fid = fcntl(fildes, F_DUPFD, 0);
+
+ @return Upon successful completion a non-negative integer, namely the
+ file descriptor, shall be returned; otherwise, -1 shall be
+ returned and errno set to indicate the error.
+**/
+int
+dup (int fildes)
+{
+ return fcntl(fildes, F_DUPFD, 0);
+}
+
+/** The dup2() function provides an alternative interface to the
+ service provided by fcntl() using the F_DUPFD command. The call:
+ - fid = dup2(fildes, fildes2);
+ shall be equivalent to:
+ - close(fildes2);
+ - fid = fcntl(fildes, F_DUPFD, fildes2);
+ except for the following:
+ - If fildes2 is less than 0 or greater than or equal to {OPEN_MAX},
+ dup2() shall return -1 with errno set to [EBADF].
+ - If fildes is a valid file descriptor and is equal to fildes2, dup2()
+ shall return fildes2 without closing it.
+ - If fildes is not a valid file descriptor, dup2() shall return -1 and
+ shall not close fildes2.
+ - The value returned shall be equal to the value of fildes2 upon
+ successful completion, or -1 upon failure.
+
+ @return Upon successful completion a non-negative integer, namely
+ fildes2, shall be returned; otherwise, -1 shall be
+ returned and errno set to EBADF indicate the error.
+**/
+int
+dup2 (int fildes, int fildes2)
+{
+ int retval = -1;
+
+ if(ValidateFD( fildes, VALID_OPEN)) {
+ retval = fildes2;
+ if( fildes != fildes2) {
+ if(ValidateFD( fildes2, VALID_DONT_CARE)) {
+ gMD->fdarray[fildes2].State = S_ISYSTEM; // Mark the file closed, but reserved
+ (void)memcpy(&gMD->fdarray[fildes2], // Duplicate fildes into fildes2
+ &gMD->fdarray[fildes], sizeof(struct __filedes));
+ }
+ else {
+ errno = EBADF;
+ retval = -1;
+ }
+ }
+ }
+ else {
+ errno = EBADF;
+ }
+ return retval;
+}
+
+/** Reposition a file's read/write offset.
+
+ The lseek() function repositions the offset of the file descriptor fildes
+ to the argument offset according to the directive how. The argument
+ fildes must be an open file descriptor. lseek() repositions the file
+ pointer fildes as follows:
+
+ If how is SEEK_SET, the offset is set to offset bytes.
+
+ If how is SEEK_CUR, the offset is set to its current location
+ plus offset bytes.
+
+ If how is SEEK_END, the offset is set to the size of the file
+ plus offset bytes.
+
+ The lseek() function allows the file offset to be set beyond the end of
+ the existing end-of-file of the file. If data is later written at this
+ point, subsequent reads of the data in the gap return bytes of zeros
+ (until data is actually written into the gap).
+
+ Some devices are incapable of seeking. The value of the pointer associ-
+ ated with such a device is undefined.
+
+ @return Upon successful completion, lseek() returns the resulting offset
+ location as measured in bytes from the beginning of the file.
+ Otherwise, a value of -1 is returned and errno is set to
+ indicate the error.
+**/
+__off_t
+lseek (int fildes, __off_t offset, int how)
+{
+ __off_t CurPos = -1;
+ RETURN_STATUS Status = RETURN_SUCCESS;
+ EFI_FILE_HANDLE FileHandle;
+
+ EFIerrno = RETURN_SUCCESS; // In case of error without an EFI call
+
+ if( how == SEEK_SET || how == SEEK_CUR || how == SEEK_END) {
+ if(ValidateFD( fildes, VALID_OPEN)) {
+ // Both of our parameters have been verified as valid
+ FileHandle = gMD->fdarray[fildes].FileHandle;
+ CurPos = 0;
+ if(isatty(fildes)) {
+ Status = FileHandle->SetPosition( FileHandle, offset);
+ CurPos = offset;
+ }
+ else {
+ if(how != SEEK_SET) {
+ // We are doing a relative seek
+ if(how == SEEK_END) {
+ // seeking relative to EOF, so position there first.
+ Status = ShellSetFilePosition( (SHELL_FILE_HANDLE)FileHandle, 0xFFFFFFFFFFFFFFFFULL);
+ }
+ if(Status == RETURN_SUCCESS) {
+ // Now, determine our current position.
+ Status = ShellGetFilePosition( (SHELL_FILE_HANDLE)FileHandle, (UINT64 *)&CurPos);
+ }
+ }
+ if(Status == RETURN_SUCCESS) {
+ /* CurPos now indicates the point we are seeking from, so seek... */
+ Status = ShellSetFilePosition( (SHELL_FILE_HANDLE)FileHandle, (UINT64)(CurPos + offset));
+ if(Status == RETURN_SUCCESS) {
+ // Now, determine our final position.
+ Status = ShellGetFilePosition( (SHELL_FILE_HANDLE)FileHandle, (UINT64 *)&CurPos);
+ }
+ }
+ if(Status != RETURN_SUCCESS) {
+ EFIerrno = Status;
+ CurPos = -1;
+ if(Status == EFI_UNSUPPORTED) {
+ errno = EISDIR;
+ }
+ else {
+ errno = EFI2errno(Status);
+ }
+ }
+ }
+ }
+ else {
+ errno = EBADF; // Bad File Descriptor
+ }
+ }
+ else {
+ errno = EINVAL; // Invalid how argument
+ }
+ return CurPos;
+}
+
+/** The directory path is created with the access permissions specified by
+ perms.
+
+ The directory is closed after it is created.
+
+ @retval 0 The directory was created successfully.
+ @retval -1 An error occurred and an error code is stored in errno.
+**/
+int
+mkdir (const char *path, __mode_t perms)
+{
+ EFI_FILE_HANDLE FileHandle;
+ RETURN_STATUS Status;
+ EFI_FILE_INFO *FileInfo;
+
+ // Convert name from MBCS to WCS
+ (void)AsciiStrToUnicodeStr( path, gMD->UString);
+ NormalizePath( gMD->UString);
+
+//Print(L"%a( \"%s\", 0x%8X)\n", __func__, gMD->UString, perms);
+ Status = ShellCreateDirectory( gMD->UString, (SHELL_FILE_HANDLE *)&FileHandle);
+ if(Status == RETURN_SUCCESS) {
+ FileInfo = ShellGetFileInfo( FileHandle);
+ if(FileInfo != NULL) {
+ FileInfo->Attribute = Omode2EFI(perms);
+ Status = ShellSetFileInfo( FileHandle, FileInfo);
+ FreePool(FileInfo);
+ if(Status == RETURN_SUCCESS) {
+ (void)ShellCloseFile((SHELL_FILE_HANDLE *)&FileHandle);
+ return 0;
+ }
+ }
+ }
+ errno = EFI2errno(Status);
+ EFIerrno = Status;
+
+ return -1;
+}
+
+/** Open a file.
+
+ The EFI ShellOpenFileByName() function is used to perform the low-level
+ file open operation. The primary task of open() is to translate from the
+ flags used in the <stdio.h> environment to those used by the EFI function.
+
+ The only valid flag combinations for ShellOpenFileByName() are:
+ - Read
+ - Read/Write
+ - Create/Read/Write
+
+ The mode value is saved in the FD to indicate permissions for further operations.
+
+ O_RDONLY -- flags = EFI_FILE_MODE_READ -- this is always done
+ O_WRONLY -- flags |= EFI_FILE_MODE_WRITE
+ O_RDWR -- flags |= EFI_FILE_MODE_WRITE -- READ is already set
+
+ O_NONBLOCK -- ignored
+ O_APPEND -- Seek to EOF before every write
+ O_CREAT -- flags |= EFI_FILE_MODE_CREATE
+ O_TRUNC -- delete first then create new
+ O_EXCL -- if O_CREAT is also set, open will fail if the file already exists.
+**/
+int
+open (const char *name, int oflags, int mode)
+{
+ EFI_FILE_HANDLE FileHandle;
+ struct __filedes *Mfd;
+ RETURN_STATUS Status;
+ UINT64 OpenMode;
+ UINT64 Attributes;
+ int fd = -1;
+ UINT32 NewState;
+
+ EFIerrno = RETURN_SUCCESS;
+ Mfd = gMD->fdarray;
+
+ // Convert name from MBCS to WCS
+ (void)AsciiStrToUnicodeStr( name, gMD->UString);
+ NormalizePath( gMD->UString);
+
+ // Convert oflags to Attributes
+ OpenMode = Oflags2EFI(oflags);
+ if(OpenMode == 0) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ //Attributes = Omode2EFI(mode);
+ Attributes = 0;
+
+ // Could add a test to see if the file name begins with a period.
+ // If it does, then add the HIDDEN flag to Attributes.
+
+ // Get an available fd
+ fd = FindFreeFD( 0 );
+
+ if( fd < 0 ) {
+ // All available FDs are in use
+ errno = EMFILE;
+ return -1;
+ }
+
+ Status = ConOpen( NULL, &FileHandle, gMD->UString, OpenMode, Attributes);
+ if(Status == RETURN_NO_MAPPING) {
+ // Not a console device, how about a regular file device?
+
+ /* Do we care if the file already exists?
+ If O_TRUNC, then delete the file. It will be created anew subsequently.
+ If O_EXCL, then error if the file exists and O_CREAT is set.
+
+ !!!!!!!!! Change this to use ShellSetFileInfo() to actually truncate the file
+ !!!!!!!!! instead of deleting and re-creating it.
+ */
+ if((oflags & O_TRUNC) || ((oflags & (O_EXCL | O_CREAT)) == (O_EXCL | O_CREAT))) {
+ Status = ShellIsFile( gMD->UString );
+ if(Status == RETURN_SUCCESS) {
+ // The file exists
+ if(oflags & O_TRUNC) {
+ // We do a truncate by deleting the existing file and creating a new one.
+ if(Uunlink(gMD->UString) != 0) {
+ Mfd[fd].State = 0; // Release our reservation on this FD
+ return -1; // errno and EFIerrno are already set.
+ }
+ }
+ else if(oflags & (O_EXCL | O_CREAT)) {
+ errno = EEXIST;
+ EFIerrno = Status;
+ Mfd[fd].State = 0; // Release our reservation on this FD
+ return -1;
+ }
+ }
+ }
+ // Call the EFI Shell's Open function
+ Status = ShellOpenFileByName( gMD->UString, (SHELL_FILE_HANDLE *)&FileHandle, OpenMode, Attributes);
+ if(RETURN_ERROR(Status)) {
+ Mfd[fd].State = 0; // Release our reservation on this FD
+ // Set errno based upon Status
+ errno = EFI2errno(Status);
+ EFIerrno = Status;
+ return -1;
+ }
+ // Successfully got a regular File
+ NewState = S_IFREG;
+ }
+ else if(Status != RETURN_SUCCESS) {
+ // Set errno based upon Status
+ errno = EFI2errno(Status);
+ EFIerrno = Status;
+ return -1;
+ }
+ else {
+ // Succesfully got a Console stream
+ NewState = S_IFREG | _S_ITTY | _S_IFCHR;
+ }
+
+ // Update the info in the fd
+ Mfd[fd].FileHandle = FileHandle;
+ Mfd[fd].Oflags = oflags;
+ Mfd[fd].Omode = mode;
+
+ // Re-use OpenMode in order to build our final State value
+ OpenMode = ( mode & S_ACC_READ ) ? S_ACC_READ : 0;
+ OpenMode |= ( mode & S_ACC_WRITE ) ? S_ACC_WRITE : 0;
+
+ Mfd[fd].State = NewState | (UINT32)OpenMode;
+
+ // return the fd of our now open file
+ return fd;
+}
+
+/** The rename() function changes the name of a file.
+ The old argument points to the pathname of the file to be renamed. The new
+ argument points to the new pathname of the file.
+
+ If the old argument points to the pathname of a file that is not a
+ directory, the new argument shall not point to the pathname of a
+ directory. If the file named by the new argument exists, it shall be
+ removed and old renamed to new. Write access permission is required for
+ both the directory containing old and the directory containing new.
+
+ If the old argument points to the pathname of a directory, the new
+ argument shall not point to the pathname of a file that is not a
+ directory. If the directory named by the new argument exists, it shall be
+ removed and old renamed to new.
+
+ The new pathname shall not contain a path prefix that names old. Write
+ access permission is required for the directory containing old and the
+ directory containing new. If the old argument points to the pathname of a
+ directory, write access permission may be required for the directory named
+ by old, and, if it exists, the directory named by new.
+
+ If the rename() function fails for any reason other than [EIO], any file
+ named by new shall be unaffected.
+
+ @return Upon successful completion, rename() shall return 0; otherwise,
+ -1 shall be returned, errno shall be set to indicate the error,
+ and neither the file named by old nor the file named by new
+ shall be changed or created.
+**/
+int
+rename (const char *old, const char *new)
+{
+ // UINT64 InfoSize;
+ // RETURN_STATUS Status;
+ // EFI_FILE_INFO *NewFileInfo = NULL;
+ // EFI_FILE_INFO *OldFileInfo;
+ // char *Newfn;
+ // int OldFd;
+
+ //// Open old file
+ // OldFd = open(old, O_RDONLY, 0);
+ // if(OldFd >= 0) {
+ // NewFileInfo = malloc(sizeof(EFI_FILE_INFO) + PATH_MAX);
+ // if(NewFileInfo != NULL) {
+ // OldFileInfo = ShellGetFileInfo( FileHandle);
+ // if(OldFileInfo != NULL) {
+ // // Copy the Old file info into our new buffer, and free the old.
+ // memcpy(OldFileInfo, NewFileInfo, sizeof(EFI_FILE_INFO));
+ // FreePool(OldFileInfo);
+ // // Strip off all but the file name portion of new
+ // NewFn = strrchr(new, '/');
+ // if(NewFn == NULL) {
+ // NewFn = strrchr(new '\\');
+ // if(NewFn == NULL) {
+ // NewFn = new;
+ // }
+ // }
+ // // Convert new name from MBCS to WCS
+ // (void)AsciiStrToUnicodeStr( NewFn, gMD->UString);
+ // // Copy the new file name into our new file info buffer
+ // wcsncpy(NewFileInfo->FileName, gMD->UString, wcslen(gMD->UString)+1);
+ // // Apply the new file name
+ // Status = ShellSetFileInfo(FileHandle);
+ // if(Status == EFI_SUCCESS) {
+ // // File has been successfully renamed. We are DONE!
+ // return 0;
+ // }
+ // errno = EFI2errno( Status );
+ // EFIerrno = Status;
+ // }
+ // else {
+ // errno = EIO;
+ // }
+ // }
+ // else {
+ // errno = ENOMEM;
+ // }
+ // }
+ return -1;
+}
+
+/**
+**/
+int
+rmdir (const char *path)
+{
+ EFI_FILE_HANDLE FileHandle;
+ RETURN_STATUS Status;
+ EFI_FILE_INFO *FileInfo = NULL;
+ int Count = 0;
+ BOOLEAN NoFile = FALSE;
+
+ errno = 0; // Make it easier to see if we have an error later
+
+ // Convert name from MBCS to WCS
+ (void)AsciiStrToUnicodeStr( path, gMD->UString);
+ NormalizePath( gMD->UString);
+
+//Print(L"%a( \"%s\")\n", __func__, gMD->UString);
+ Status = ShellOpenFileByName( gMD->UString, (SHELL_FILE_HANDLE *)&FileHandle,
+ (EFI_FILE_MODE_READ || EFI_FILE_MODE_WRITE), 0);
+ if(Status == RETURN_SUCCESS) {
+ FileInfo = ShellGetFileInfo( (SHELL_FILE_HANDLE)FileHandle);
+ if(FileInfo != NULL) {
+ if((FileInfo->Attribute & EFI_FILE_DIRECTORY) == 0) {
+ errno = ENOTDIR;
+ }
+ else {
+ // See if the directory has any entries other than ".." and ".".
+ FreePool(FileInfo); // Free up the buffer from ShellGetFileInfo()
+ Status = ShellFindFirstFile( (SHELL_FILE_HANDLE)FileHandle, &FileInfo);
+ if(Status == RETURN_SUCCESS) {
+ ++Count;
+ while(Count < 3) {
+ Status = ShellFindNextFile( (SHELL_FILE_HANDLE)FileHandle, FileInfo, &NoFile);
+ if(Status == RETURN_SUCCESS) {
+ if(NoFile) {
+ break;
+ }
+ ++Count;
+ }
+ else {
+ Count = 99;
+ }
+ }
+ FreePool(FileInfo); // Free buffer from ShellFindFirstFile()
+ if(Count < 3) {
+ // Directory is empty
+ Status = ShellDeleteFile( (SHELL_FILE_HANDLE *)&FileHandle);
+ if(Status == RETURN_SUCCESS) {
+ EFIerrno = RETURN_SUCCESS;
+ return 0;
+ /* ######## SUCCESSFUL RETURN ######## */
+ }
+ }
+ else {
+ if(Count == 99) {
+ errno = EIO;
+ }
+ else {
+ errno = ENOTEMPTY;
+ }
+ }
+ }
+ }
+ }
+ else {
+ errno = EIO;
+ }
+ }
+ EFIerrno = Status;
+ if(errno == 0) {
+ errno = EFI2errno( Status );
+ }
+ return -1;
+}
+
+/* Internal File Info. worker function for stat and fstat. */
+static
+EFI_STATUS
+_EFI_FileInfo( EFI_FILE_INFO *FileInfo, struct stat *statbuf)
+{
+ UINT64 Attributes;
+ RETURN_STATUS Status;
+ mode_t newmode;
+
+ if(FileInfo != NULL) {
+ // Got the info, now populate statbuf with it
+ statbuf->st_blksize = S_BLKSIZE;
+ statbuf->st_size = FileInfo->Size;
+ statbuf->st_physsize = FileInfo->PhysicalSize;
+ statbuf->st_birthtime = Efi2Time( &FileInfo->CreateTime);
+ statbuf->st_atime = Efi2Time( &FileInfo->LastAccessTime);
+ statbuf->st_mtime = Efi2Time( &FileInfo->ModificationTime);
+ Attributes = FileInfo->Attribute;
+ newmode = (mode_t)(Attributes << S_EFISHIFT) | S_ACC_READ;
+ if((Attributes & EFI_FILE_DIRECTORY) == 0) {
+ newmode |= _S_IFREG;
+ if((Attributes & EFI_FILE_READ_ONLY) == 0) {
+ statbuf->st_mode |= S_ACC_WRITE;
+ }
+ }
+ else {
+ newmode |= _S_IFDIR;
+ }
+ statbuf->st_mode = newmode;
+ Status = RETURN_SUCCESS;
+ }
+ else {
+ Status = RETURN_DEVICE_ERROR;
+ }
+ return Status;
+}
+
+/** The fstat() function obtains information about an open file associated
+ with the file descriptor fildes, and shall write it to the area pointed to
+ by buf.
+
+ The buf argument is a pointer to a stat structure, as defined
+ in <sys/stat.h>, into which information is placed concerning the file.
+
+ The structure members st_mode, st_ino, st_dev, st_uid, st_gid, st_atime,
+ st_ctime, and st_mtime shall have meaningful values. The value of the
+ member st_nlink shall be set to the number of links to the file.
+
+ The fstat() function shall update any time-related fields before writing
+ into the stat structure.
+
+ The fstat() function is implemented using the ShellGetFileInfo()
+ function.
+
+ The stat structure members which don't have direct analogs to EFI file
+ information are filled in as follows:
+ - st_mode Populated with information from fildes
+ - st_ino Set to zero. (inode)
+ - st_dev Set to zero.
+ - st_uid Set to zero.
+ - st_gid Set to zero.
+ - st_nlink Set to one.
+
+ @param[in] fildes File descriptor as returned from open().
+ @param[out] statbuf Buffer in which the file status is put.
+
+ @retval 0 Successful Completion.
+ @retval -1 An error has occurred and errno has been set to
+ identify the error.
+**/
+int
+fstat (int fildes, struct stat *statbuf)
+{
+ EFI_FILE_HANDLE FileHandle;
+ RETURN_STATUS Status = RETURN_SUCCESS;
+ EFI_FILE_INFO *FileInfo = NULL;
+ UINTN FinfoSize = sizeof(EFI_FILE_INFO);
+
+ if(ValidateFD( fildes, VALID_OPEN)) {
+ FileHandle = gMD->fdarray[fildes].FileHandle;
+ if(isatty(fildes)) {
+ FileInfo = AllocateZeroPool(FinfoSize);
+ if(FileInfo != NULL) {
+ Status = FileHandle->GetInfo( FileHandle, 0, &FinfoSize, FileInfo);
+ }
+ else {
+ Status = RETURN_OUT_OF_RESOURCES;
+ }
+ }
+ else {
+ FileInfo = ShellGetFileInfo( FileHandle);
+ }
+ Status = _EFI_FileInfo( FileInfo, statbuf);
+ }
+ errno = EFI2errno(Status);
+ EFIerrno = Status;
+
+ if(FileInfo != NULL) {
+ FreePool(FileInfo); // Release the buffer allocated by the GetInfo function
+ }
+
+ return errno? -1 : 0;
+}
+
+/** Obtains information about the file pointed to by path.
+
+ Opens the file pointed to by path, calls _EFI_FileInfo with the file's handle,
+ then closes the file.
+
+ @retval 0 Successful Completion.
+ @retval -1 An error has occurred and errno has been set to
+ identify the error.
+**/
+int
+stat (const char *path, void *statbuf)
+{
+ EFI_FILE_HANDLE FileHandle;
+ RETURN_STATUS Status;
+ EFI_FILE_INFO *FileInfo;
+
+ errno = 0; // Make it easier to see if we have an error later
+
+ // Convert name from MBCS to WCS
+ (void)AsciiStrToUnicodeStr( path, gMD->UString);
+ NormalizePath( gMD->UString);
+
+ Status = ShellOpenFileByName( gMD->UString, (SHELL_FILE_HANDLE *)&FileHandle, EFI_FILE_MODE_READ, 0ULL);
+ if(Status == RETURN_SUCCESS) {
+ FileInfo = ShellGetFileInfo( FileHandle);
+ Status = _EFI_FileInfo( FileInfo, (struct stat *)statbuf);
+ (void)ShellCloseFile( (SHELL_FILE_HANDLE *)&FileHandle);
+ }
+ errno = EFI2errno(Status);
+ EFIerrno = Status;
+
+ return errno? -1 : 0;
+}
+
+/** Same as stat since EFI doesn't have symbolic links. **/
+int
+lstat (const char *path, struct stat *statbuf)
+{
+ return stat(path, statbuf);
+}
+
+/** Read from a file.
+
+ The read() function shall attempt to read nbyte bytes from the file
+ associated with the open file descriptor, fildes, into the buffer pointed
+ to by buf.
+
+ Before any action described below is taken, and if nbyte is zero, the
+ read() function may detect and return errors as described below. In the
+ absence of errors, or if error detection is not performed, the read()
+ function shall return zero and have no other results.
+
+ On files that support seeking (for example, a regular file), the read()
+ shall start at a position in the file given by the file offset associated
+ with fildes. The file offset shall be incremented by the number of bytes
+ actually read.
+
+ Files that do not support seeking - for example, terminals - always read
+ from the current position. The value of a file offset associated with
+ such a file is undefined.
+
+ No data transfer shall occur past the current end-of-file. If the
+ starting position is at or after the end-of-file, 0 shall be returned.
+
+ The read() function reads data previously written to a file. If any
+ portion of a regular file prior to the end-of-file has not been written,
+ read() shall return bytes with value 0. For example, lseek() allows the
+ file offset to be set beyond the end of existing data in the file. If data
+ is later written at this point, subsequent reads in the gap between the
+ previous end of data and the newly written data shall return bytes with
+ value 0 until data is written into the gap.
+
+ Upon successful completion, where nbyte is greater than 0, read() shall
+ mark for update the st_atime field of the file, and shall return the
+ number of bytes read. This number shall never be greater than nbyte. The
+ value returned may be less than nbyte if the number of bytes left in the
+ file is less than nbyte, if the read() request was interrupted by a
+ signal, or if the file is a pipe or FIFO or special file and has fewer
+ than nbyte bytes immediately available for reading. For example, a read()
+ from a file associated with a terminal may return one typed line of data.
+
+ If fildes does not refer to a directory, the function reads the requested
+ number of bytes from the file at the file’s current position and returns
+ them in buf. If the read goes beyond the end of the file, the read
+ length is truncated to the end of the file. The file’s current position is
+ increased by the number of bytes returned.
+
+ If fildes refers to a directory, the function reads the directory entry at
+ the file’s current position and returns the entry in buf. If buf
+ is not large enough to hold the current directory entry, then
+ errno is set to EBUFSIZE, EFIerrno is set to EFI_BUFFER_TOO_SMALL, and the
+ current file position is not updated. The size of the buffer needed to read
+ the entry will be returned as a negative number. On success, the current
+ position is updated to the next directory entry. If there are no more
+ directory entries, the read returns a zero-length buffer.
+ EFI_FILE_INFO is the structure returned as the directory entry.
+
+ @return Upon successful completion, read() returns a non-negative integer
+ indicating the number of bytes actually read. Otherwise, the
+ functions return a negative value and sets errno to indicate the
+ error. If errno is EBUFSIZE, the absolute value of the
+ return value indicates the size of the buffer needed to read
+ the directory entry.
+**/
+ssize_t
+read (int fildes, void *buf, size_t nbyte)
+{
+ ssize_t BufSize;
+ EFI_FILE_HANDLE FileHandle;
+ RETURN_STATUS Status;
+
+ BufSize = (ssize_t)nbyte;
+ if(ValidateFD( fildes, VALID_OPEN)) {
+ FileHandle = gMD->fdarray[fildes].FileHandle;
+ if(isatty(fildes)) {
+ Status = FileHandle->Read( FileHandle, (UINTN *)&BufSize, buf);
+ }
+ else {
+ Status = ShellReadFile( FileHandle, (UINTN *)&BufSize, buf);
+ }
+ if(Status != RETURN_SUCCESS) {
+ EFIerrno = Status;
+ errno = EFI2errno(Status);
+ if(Status == RETURN_BUFFER_TOO_SMALL) {
+ BufSize = -BufSize;
+ }
+ else {
+ BufSize = -1;
+ }
+ }
+ }
+ else {
+ errno = EBADF;
+ }
+ return BufSize;
+}
+
+ssize_t
+WideTtyCvt( CHAR16 *dest, const char *buf, size_t n)
+{
+ UINTN i;
+ wint_t wc;
+
+ for(i = 0; i < n; ++i) {
+ wc = btowc(*buf++);
+ if( wc == 0) {
+ break;
+ };
+ if(wc < 0) {
+ wc = BLOCKELEMENT_LIGHT_SHADE;
+ }
+ if(wc == L'\n') {
+ *dest++ = L'\r';
+ }
+ *dest++ = (CHAR16)wc;
+ }
+ *dest = 0;
+ return (ssize_t)i;
+}
+
+/** Write data to a file.
+
+ This function writes the specified number of bytes to the file at the current
+ file position. The current file position is advanced the actual number of bytes
+ written, which is returned in BufferSize. Partial writes only occur when there
+ has been a data error during the write attempt (such as "volume space full").
+ The file is automatically grown to hold the data if required. Direct writes to
+ opened directories are not supported.
+
+ If fildes refers to a terminal device, isatty() returns TRUE, a partial write
+ will occur if a NULL or EOF character is encountered before n characters have
+ been written. Characters inserted due to line-end translations will not be
+ counted. Unconvertable characters are translated into the UEFI character
+ BLOCKELEMENT_LIGHT_SHADE.
+
+ Since the UEFI console device works on wide characters, the buffer is assumed
+ to contain a single-byte character stream which is then translated to wide
+ characters using the btowc() functions. The resulting wide character stream
+ is what is actually sent to the UEFI console.
+
+ QUESTION: Should writes to stdout or stderr always succeed?
+**/
+ssize_t
+write (int fildes, const void *buf, size_t n)
+{
+ ssize_t BufSize;
+ EFI_FILE_HANDLE FileHandle;
+ RETURN_STATUS Status = RETURN_SUCCESS;
+ ssize_t UniBufSz;
+
+ BufSize = (ssize_t)n;
+
+ if(ValidateFD( fildes, VALID_OPEN)) {
+ FileHandle = gMD->fdarray[fildes].FileHandle;
+ if(isatty(fildes)) {
+ // Convert string from MBCS to WCS and translate \n to \r\n.
+ UniBufSz = WideTtyCvt(gMD->UString, (const char *)buf, n);
+ if(UniBufSz > 0) {
+ BufSize = (ssize_t)(UniBufSz * sizeof(CHAR16));
+ Status = FileHandle->Write( FileHandle, (UINTN *)&BufSize, (void *)gMD->UString);
+ BufSize = (ssize_t)n; // Always pretend all was output
+ }
+ }
+ else {
+ Status = ShellWriteFile( FileHandle, (UINTN *)&BufSize, (void *)buf);
+ }
+ if(Status != RETURN_SUCCESS) {
+ EFIerrno = Status;
+ errno = EFI2errno(Status);
+ if(Status == EFI_UNSUPPORTED) {
+ errno = EISDIR;
+ }
+ BufSize = -1;
+ }
+ }
+ else {
+ errno = EBADF;
+ }
+ return BufSize;
+}
diff --git a/StdLib/LibC/Uefi/SysEfi.h b/StdLib/LibC/Uefi/SysEfi.h
new file mode 100644
index 0000000000..fa9dc38cdd
--- /dev/null
+++ b/StdLib/LibC/Uefi/SysEfi.h
@@ -0,0 +1,37 @@
+/** @file
+ Declarations local to the Uefi SysCalls module of the Standard C Library.
+
+ Copyright (c) 2010, 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 that 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 _SYSEFI_H
+#define _SYSEFI_H
+#include <Protocol/SimpleFileSystem.h>
+
+#define EFI_FILE_MODE_MASK ( EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE | EFI_FILE_MODE_CREATE )
+#define OMODE_MASK 0xFFFF00UL
+#define OMODE_SHIFT 8
+
+#define S_ACC_READ ( S_IRUSR | S_IRGRP | S_IROTH | S_IXUSR | S_IXGRP | S_IXOTH )
+#define S_ACC_WRITE ( S_IWUSR | S_IWGRP | S_IWOTH )
+#define S_ACC_MASK ( S_IRWXU | S_IRWXG | S_IRWXO )
+
+UINT64
+Oflags2EFI( int oflags);
+
+UINT64
+Omode2EFI( int mode);
+
+/* Converts the first several EFI status values into the appropriate errno value.
+*/
+int
+EFI2errno( RETURN_STATUS Status);
+
+#endif /* _SYSEFI_H */
diff --git a/StdLib/LibC/Uefi/Uefi.inf b/StdLib/LibC/Uefi/Uefi.inf
new file mode 100644
index 0000000000..ca6437abe0
--- /dev/null
+++ b/StdLib/LibC/Uefi/Uefi.inf
@@ -0,0 +1,49 @@
+## @file
+# Standard C library: UEFI "system calls".
+#
+# Copyright (c) 2010, 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.
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = LibUefi
+ FILE_GUID = 39356e02-26bf-4cfb-9564-378ce25e702f
+ MODULE_TYPE = UEFI_APPLICATION
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = LibUefi
+
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF
+#
+
+[Sources]
+ SysCalls.c
+ Xform.c
+ Console.c
+
+[Packages]
+ StdLib/StdLib.dec
+ StdLibPrivateInternalFiles/DoNotUse.dec
+ MdePkg/MdePkg.dec
+ ShellPkg/ShellPkg.dec
+
+[LibraryClasses]
+ UefiLib
+ BaseLib
+ BaseMemoryLib
+ MemoryAllocationLib
+ UefiBootServicesTableLib
+ ShellLib
+ LibC
+ LibLocale
+ LibString
+ LibTime
diff --git a/StdLib/LibC/Uefi/Xform.c b/StdLib/LibC/Uefi/Xform.c
new file mode 100644
index 0000000000..21eff6fb9d
--- /dev/null
+++ b/StdLib/LibC/Uefi/Xform.c
@@ -0,0 +1,173 @@
+/** @file
+ Value transformations between stdio and the UEFI environment.
+
+ Copyright (c) 2010, 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 that 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 <Uefi.h>
+
+#include <LibConfig.h>
+#include <sys/EfiCdefs.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include "SysEfi.h"
+
+/** Translate the Open flags into a Uefi Open Modes value.
+
+ The Open Flags are:
+ O_RDONLY, O_WRONLY, O_RDWR // Pick only one
+
+ O_NONBLOCK, O_APPEND, O_CREAT, O_TRUNC, O_EXCL // ORed with one of the previous
+
+ The UEFI Open modes are:
+ // ******************************************************
+ // Open Modes
+ // ******************************************************
+ #define EFI_FILE_MODE_READ 0x0000000000000001
+ #define EFI_FILE_MODE_WRITE 0x0000000000000002
+ #define EFI_FILE_MODE_CREATE 0x8000000000000000
+
+
+*/
+UINT64
+Oflags2EFI( int oflags )
+{
+ UINT64 flags;
+
+ // Build the Open Modes
+ flags = (UINT64)((oflags & O_ACCMODE) + 1); // Handle the Read/Write flags
+ if(oflags & (O_CREAT | O_TRUNC)) { // Now add the Create flag.
+ // Also added if O_TRUNC set since we will need to create a new file.
+ // We just set the flags here since the only valid EFI mode with create
+ // is Read+Write+Create.
+ flags = EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE | EFI_FILE_MODE_CREATE;
+ }
+ return flags;
+}
+
+/* Transform the permissions flags from the open() call into the
+ Attributes bits needed by UEFI.
+
+ The UEFI File attributes are:
+ // ******************************************************
+ // File Attributes
+ // ******************************************************
+ #define EFI_FILE_READ_ONLY 0x0000000000000001
+ #define EFI_FILE_HIDDEN 0x0000000000000002
+ #define EFI_FILE_SYSTEM 0x0000000000000004
+ #define EFI_FILE_RESERVED 0x0000000000000008
+ #define EFI_FILE_DIRECTORY 0x0000000000000010
+ #define EFI_FILE_ARCHIVE 0x0000000000000020
+ #define EFI_FILE_VALID_ATTR 0x0000000000000037
+
+ The input permission flags consist of two groups:
+ ( S_IRUSR | S_IRGRP | S_IROTH ) -- S_ACC_READ
+ ( S_IWUSR | S_IWGRP | S_IWOTH ) -- S_ACC_WRITE
+
+ The only thing we can set, at this point, is whether or not
+ this is a SYSTEM file. If the group and other bits are
+ zero and the user bits are non-zero then set SYSTEM. Otherwise
+ the attributes are zero.
+
+ The attributes can be set later using fcntl().
+*/
+UINT64
+Omode2EFI( int mode)
+{
+ UINT64 flags = 0;
+
+ if((mode & (S_IRWXG | S_IRWXO)) == 0) {
+ if((mode & S_IRWXU) != 0) {
+ // Only user permissions so set system
+ flags = EFI_FILE_SYSTEM;
+ }
+ }
+ return flags;
+}
+
+/* Converts the first several EFI status values into the appropriate errno value.
+*/
+int
+EFI2errno( RETURN_STATUS Status)
+{
+ int retval;
+
+ switch(Status) {
+ case RETURN_SUCCESS:
+ retval = 0;
+ break;
+ case RETURN_INVALID_PARAMETER:
+ retval = EINVAL;
+ break;
+ case RETURN_UNSUPPORTED:
+ retval = ENODEV;
+ break;
+ case RETURN_BAD_BUFFER_SIZE:
+ case RETURN_BUFFER_TOO_SMALL:
+ retval = EBUFSIZE;
+ break;
+ case RETURN_NOT_READY:
+ retval = EBUSY;
+ break;
+ case RETURN_WRITE_PROTECTED:
+ retval = EROFS;
+ break;
+ case RETURN_OUT_OF_RESOURCES: // May be overridden by specific functions
+ retval = ENOMEM;
+ break;
+ case RETURN_VOLUME_FULL:
+ retval = ENOSPC;
+ break;
+ case RETURN_NOT_FOUND:
+ case RETURN_NO_MAPPING:
+ retval = ENOENT;
+ break;
+ case RETURN_TIMEOUT:
+ retval = ETIMEDOUT;
+ break;
+ case RETURN_NOT_STARTED:
+ retval = EAGAIN;
+ break;
+ case RETURN_ALREADY_STARTED:
+ retval = EALREADY;
+ break;
+ case RETURN_ABORTED:
+ retval = EINTR;
+ break;
+ case RETURN_ICMP_ERROR:
+ case RETURN_TFTP_ERROR:
+ case RETURN_PROTOCOL_ERROR:
+ retval = EPROTO;
+ break;
+ case RETURN_INCOMPATIBLE_VERSION:
+ retval = EPERM;
+ break;
+ case RETURN_ACCESS_DENIED:
+ case RETURN_SECURITY_VIOLATION:
+ retval = EACCES;
+ break;
+/* case RETURN_LOAD_ERROR:
+ case RETURN_DEVICE_ERROR:
+ case RETURN_VOLUME_CORRUPTED:
+ case RETURN_NO_MEDIA:
+ case RETURN_MEDIA_CHANGED:
+ case RETURN_NO_RESPONSE:
+ case RETURN_CRC_ERROR:
+ case RETURN_END_OF_MEDIA:
+ case RETURN_END_OF_FILE:
+ case RETURN_INVALID_LANGUAGE:
+*/
+ default:
+ retval = EIO;
+ break;
+ }
+ return retval;
+}