From 53e1e5c647b73e45569ed6e8b8a0a5b276aa685e Mon Sep 17 00:00:00 2001 From: darylm503 Date: Tue, 28 Jun 2011 02:34:10 +0000 Subject: =?UTF-8?q?Add=20device=20abstraction=20code=20for=20the=20UEFI=20?= =?UTF-8?q?Console=20and=20UEFI=20Shell-based=20file=20systems.=20Make=20a?= =?UTF-8?q?rgv=20use=20narrow=20characters=20instead=20of=20wide=20charact?= =?UTF-8?q?ers.=20Add=20setenv=20functionality.=20Add=20poll()=20system=20?= =?UTF-8?q?call.=20Change=20signal=20names=20into=20macros=20=E2=80=93=20r?= =?UTF-8?q?equired=20for=20standards=20compliance.=20=20The=20enums=20were?= =?UTF-8?q?=20renamed=20and=20moved=20to=20sys/signal.h=20and=20the=20new?= =?UTF-8?q?=20macros=20reference=20the=20enums.=20Added=20SIGBREAK,=20whic?= =?UTF-8?q?h=20is=20required=20for=20Python.=20Modify=20stdio=20functions?= =?UTF-8?q?=20to=20fail=20cleanly=20when=20called=20with=20a=20NULL=20File?= =?UTF-8?q?=20Pointer=20argument.=20Added=20=20that=20just=20?= =?UTF-8?q?includes=20.=20=20By=20adding=20this=20wrapper,?= =?UTF-8?q?=20we=20improve=20compatibility=20with=20*nix=20files=20which?= =?UTF-8?q?=20assume=20=20exists.=20Add=20=20Added=20m?= =?UTF-8?q?acros=20for=20bcopy(),=20bcmp()=20and=20strsep().=20Modify=20th?= =?UTF-8?q?e=20clock()=20function=20so=20that=20it=20does=20not=20hang=20w?= =?UTF-8?q?hen=20running=20under=20an=20emulation=20environment=20such=20a?= =?UTF-8?q?s=20NT32.=20Move=20TM=20structure=20specific=20macros=20from=20?= =?UTF-8?q?the=20private=20tzfile.h=20into=20=20Add=20strncasecmp?= =?UTF-8?q?=20function.=20Add=20strptime=20function.=20Add=20gettimeofday?= =?UTF-8?q?=20function.=20Add=20getcwd=20function.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@11908 6f19259b-4bc3-4df7-8a09-765794883524 --- StdLib/LibC/Uefi/Devices/Console/daConsole.c | 558 +++++++++++++++++++++++++++ 1 file changed, 558 insertions(+) create mode 100644 StdLib/LibC/Uefi/Devices/Console/daConsole.c (limited to 'StdLib/LibC/Uefi/Devices/Console/daConsole.c') diff --git a/StdLib/LibC/Uefi/Devices/Console/daConsole.c b/StdLib/LibC/Uefi/Devices/Console/daConsole.c new file mode 100644 index 0000000000..c579959081 --- /dev/null +++ b/StdLib/LibC/Uefi/Devices/Console/daConsole.c @@ -0,0 +1,558 @@ +/** @file + Abstract device driver for the UEFI Console. + + Manipulates abstractions for stdin, stdout, stderr. + + Copyright (c) 2010 - 2011, Intel Corporation. All rights reserved.
+ This program and the accompanying materials are licensed and made available under + the terms and conditions of the BSD License 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 +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +static const CHAR16* const +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 DeviceNode *ConNode[NUM_SPECIAL]; +static ConInstance *ConInstanceList; + +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; +} + +static +int +EFIAPI +da_ConClose( + IN struct __filedes *filp +) +{ + ConInstance *Stream; + + Stream = BASE_CR(filp->f_ops, ConInstance, Abstraction); + // Quick check to see if Stream looks reasonable + if(Stream->Cookie != CON_COOKIE) { // Cookie == 'IoAb' + EFIerrno = RETURN_INVALID_PARAMETER; + return -1; // Looks like a bad File Descriptor pointer + } + gMD->StdIo[Stream->InstanceNum] = NULL; // Mark the stream as closed + return RETURN_SUCCESS; +} + +static +off_t +EFIAPI +da_ConSeek( + struct __filedes *filp, + off_t Position, + int whence ///< Ignored by Console +) +{ + ConInstance *Stream; + EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *Proto; + XYoffset CursorPos; + + Stream = BASE_CR(filp->f_ops, ConInstance, Abstraction); + // Quick check to see if Stream looks reasonable + if(Stream->Cookie != CON_COOKIE) { // Cookie == 'IoAb' + EFIerrno = RETURN_INVALID_PARAMETER; + return -1; // Looks like a bad This pointer + } + if(Stream->InstanceNum == STDIN_FILENO) { + // Seek is not valid for stdin + EFIerrno = RETURN_UNSUPPORTED; + return -1; + } + // Everything is OK to do the final verification and "seek". + Proto = (EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *)Stream->Dev; + CursorPos.Offset = Position; + + EFIerrno = Proto->SetCursorPosition(Proto, + (INTN)CursorPos.XYpos.Column, + (INTN)CursorPos.XYpos.Row); + + if(RETURN_ERROR(EFIerrno)) { + return -1; + } + else { + return Position; + } +} + +static +ssize_t +EFIAPI +da_ConRead( + IN OUT struct __filedes *filp, + IN OUT off_t *offset, // Console ignores this + IN size_t 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 = RETURN_SUCCESS; + UINTN i; + + Stream = BASE_CR(filp->f_ops, ConInstance, Abstraction); + // Quick check to see if Stream looks reasonable + if(Stream->Cookie != CON_COOKIE) { // Cookie == 'IoAb' + EFIerrno = RETURN_INVALID_PARAMETER; + return -1; // Looks like a bad This pointer + } + if(Stream->InstanceNum != STDIN_FILENO) { + // Read only valid for stdin + EFIerrno = RETURN_UNSUPPORTED; + return -1; + } + // 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 { + if((Stream->UnGetKey.UnicodeChar == CHAR_NULL) && (Stream->UnGetKey.ScanCode == SCAN_NULL)) { + Status = gBS->WaitForEvent( 1, &Proto->WaitForKey, &Edex); + if(Status != RETURN_SUCCESS) { + break; + } + Status = Proto->ReadKeyStroke(Proto, &Key); + if(Status != RETURN_SUCCESS) { + break; + } + } + else { + Key.ScanCode = Stream->UnGetKey.ScanCode; + Key.UnicodeChar = Stream->UnGetKey.UnicodeChar; + Stream->UnGetKey.ScanCode = SCAN_NULL; + Stream->UnGetKey.UnicodeChar = CHAR_NULL; + } + if(Key.ScanCode == SCAN_NULL) { + *OutPtr++ = Key.UnicodeChar; + ++i; + } + if(iswcntrl(Key.UnicodeChar)) { // If a control character, or a scan code + break; + } + } while(i < NumChar); + + *OutPtr = L'\0'; // Terminate the input buffer + EFIerrno = Status; + return (ssize_t)(i * sizeof(CHAR16)); // Will be 0 if we didn't get a key +} + +/* 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. + @param[in] Buffer The WCS string to be displayed + + @return The number of characters written. +*/ +static +ssize_t +EFIAPI +da_ConWrite( + IN struct __filedes *filp, + IN off_t *Position, + IN size_t BufferSize, + IN const void *Buffer + ) +{ + EFI_STATUS Status; + EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *Proto; + ConInstance *Stream; + ssize_t NumChar; + //XYoffset CursorPos; + + Stream = BASE_CR(filp->f_ops, ConInstance, Abstraction); + // Quick check to see if Stream looks reasonable + if(Stream->Cookie != CON_COOKIE) { // Cookie == 'IoAb' + EFIerrno = RETURN_INVALID_PARAMETER; + return -1; // Looks like a bad This pointer + } + if(Stream->InstanceNum == STDIN_FILENO) { + // Write is not valid for stdin + EFIerrno = RETURN_UNSUPPORTED; + return -1; + } + // Everything is OK to do the write. + Proto = (EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *)Stream->Dev; + + // Convert string from MBCS to WCS and translate \n to \r\n. + NumChar = WideTtyCvt(gMD->UString, (const char *)Buffer, BufferSize); + //if(NumChar > 0) { + // BufferSize = (size_t)(NumChar * sizeof(CHAR16)); + //} + BufferSize = NumChar; + + //if( Position != NULL) { + // CursorPos.Offset = (UINT64)*Position; + + // Status = Proto->SetCursorPosition(Proto, + // (INTN)CursorPos.XYpos.Column, + // (INTN)CursorPos.XYpos.Row); + // if(RETURN_ERROR(Status)) { + // return -1; + // } + //} + + // Send the Unicode buffer to the console + Status = Proto->OutputString( Proto, gMD->UString); + // Depending on status, update BufferSize and return + if(RETURN_ERROR(Status)) { + BufferSize = 0; // We don't really know how many characters made it out + } + else { + //BufferSize = NumChar; + Stream->NumWritten += NumChar; + } + EFIerrno = Status; + return BufferSize; +} + +/** Console-specific helper function for the fstat() function. + + st_size Set to number of characters read for stdin and number written for stdout and stderr. + st_physsize 1 for stdin, 0 if QueryMode error, else max X and Y coordinates for the current mode. + st_curpos 0 for stdin, current X & Y coordinates for stdout and stderr + st_blksize Set to 1 since this is a character device + + All other members of the stat structure are left unchanged. +**/ +static +int +EFIAPI +da_ConStat( + struct __filedes *filp, + struct stat *Buffer, + void *Something + ) +{ + ConInstance *Stream; + EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *Proto; + XYoffset CursorPos; + INT32 OutMode; + UINTN ModeCol; + UINTN ModeRow; + +// ConGetInfo + Stream = BASE_CR(filp->f_ops, ConInstance, Abstraction); + // Quick check to see if Stream looks reasonable + if ((Stream->Cookie != CON_COOKIE) || // Cookie == 'IoAb' + (Buffer == NULL)) + { + EFIerrno = RETURN_INVALID_PARAMETER; + return -1; + } + // All of our parameters are correct, so fill in the information. + Buffer->st_blksize = 1; + +// ConGetPosition + if(Stream->InstanceNum == STDIN_FILENO) { + // This is stdin + Buffer->st_curpos = 0; + Buffer->st_size = (off_t)Stream->NumRead; + Buffer->st_physsize = 1; + } + else { + Proto = (EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *)Stream->Dev; + CursorPos.XYpos.Column = (UINT32)Proto->Mode->CursorColumn; + CursorPos.XYpos.Row = (UINT32)Proto->Mode->CursorRow; + Buffer->st_curpos = (off_t)CursorPos.Offset; + Buffer->st_size = (off_t)Stream->NumWritten; + + OutMode = Proto->Mode->Mode; + EFIerrno = Proto->QueryMode(Proto, (UINTN)OutMode, &ModeCol, &ModeRow); + if(RETURN_ERROR(EFIerrno)) { + Buffer->st_physsize = 0; + } + else { + CursorPos.XYpos.Column = (UINT32)ModeCol; + CursorPos.XYpos.Row = (UINT32)ModeRow; + Buffer->st_physsize = (off_t)CursorPos.Offset; + } + } + return 0; +} + +static +int +EFIAPI +da_ConIoctl( + struct __filedes *filp, + ULONGN cmd, + void *argp + ) +{ + return -EPERM; +} + +/** Open an abstract Console Device. +**/ +int +EFIAPI +da_ConOpen( + struct __filedes *filp, + void *DevInstance, + wchar_t *Path, // Not used for console devices + wchar_t *Flags // Not used for console devices + ) +{ + ConInstance *Stream; + + if((filp == NULL) || + (DevInstance == NULL)) + { + EFIerrno = RETURN_INVALID_PARAMETER; + return -1; + } + Stream = (ConInstance *)DevInstance; + // Quick check to see if Stream looks reasonable + if(Stream->Cookie != CON_COOKIE) { // Cookie == 'IoAb' + EFIerrno = RETURN_INVALID_PARAMETER; + return -1; // Looks like a bad This pointer + } + gMD->StdIo[Stream->InstanceNum] = (ConInstance *)DevInstance; + filp->f_iflags |= (S_IFREG | _S_IFCHR | _S_ICONSOLE); + filp->f_offset = 0; + filp->f_ops = &Stream->Abstraction; + + return 0; +} + +#include +/* Returns a bit mask describing which operations could be completed immediately. + + (POLLIN | POLLRDNORM) A Unicode character is available to read + (POLLIN) A ScanCode is ready. + (POLLOUT) The device is ready for output - always set on stdout and stderr. + +*/ +static +short +EFIAPI +da_ConPoll( + struct __filedes *filp, + short events + ) +{ + EFI_SIMPLE_TEXT_INPUT_PROTOCOL *Proto; + ConInstance *Stream; + EFI_STATUS Status = RETURN_SUCCESS; + short RdyMask = 0; + + Stream = BASE_CR(filp->f_ops, ConInstance, Abstraction); + // Quick check to see if Stream looks reasonable + if(Stream->Cookie != CON_COOKIE) { // Cookie == 'IoAb' + EFIerrno = RETURN_INVALID_PARAMETER; + return POLLNVAL; // Looks like a bad filp pointer + } + if(Stream->InstanceNum == 0) { + // Only input is supported for this device + Proto = (EFI_SIMPLE_TEXT_INPUT_PROTOCOL *)Stream->Dev; + if((Stream->UnGetKey.UnicodeChar == CHAR_NULL) && (Stream->UnGetKey.ScanCode == SCAN_NULL)) { + Status = Proto->ReadKeyStroke(Proto, &Stream->UnGetKey); + if(Status == RETURN_SUCCESS) { + RdyMask = POLLIN; + if(Stream->UnGetKey.UnicodeChar != CHAR_NULL) { + RdyMask |= POLLRDNORM; + } + } + else { + Stream->UnGetKey.ScanCode = SCAN_NULL; + Stream->UnGetKey.UnicodeChar = CHAR_NULL; + } + } + } + else if(Stream->InstanceNum < NUM_SPECIAL) { // Not 0, is it 1 or 2? + // Only output is supported for this device + RdyMask = POLLOUT; + } + else { + RdyMask = POLLERR; // Not one of the standard streams + } + EFIerrno = Status; + + return (RdyMask & (events | POLL_RETONLY)); +} + +/** Construct the Console stream devices: stdin, stdout, stderr. + + Allocate the instance structure and populate it with the information for + each stream device. +**/ +RETURN_STATUS +EFIAPI +__Cons_construct( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable +) +{ + ConInstance *Stream; + RETURN_STATUS Status = RETURN_SUCCESS; + int i; + + ConInstanceList = (ConInstance *)AllocateZeroPool(NUM_SPECIAL * sizeof(ConInstance)); + if(ConInstanceList == NULL) { + return RETURN_OUT_OF_RESOURCES; + } + + for( i = 0; i < NUM_SPECIAL; ++i) { + // Get pointer to instance. + Stream = &ConInstanceList[i]; + + Stream->Cookie = CON_COOKIE; + Stream->InstanceNum = i; + + switch(i) { + case STDIN_FILENO: + Stream->Dev = SystemTable->ConIn; + break; + case STDOUT_FILENO: + Stream->Dev = SystemTable->ConOut; + break; + case STDERR_FILENO: + if(SystemTable->StdErr == NULL) { + Stream->Dev = SystemTable->ConOut; + } + else { + Stream->Dev = SystemTable->StdErr; + } + break; + default: + return RETURN_VOLUME_CORRUPTED; // This is a "should never happen" case. + } + + Stream->Abstraction.fo_close = &da_ConClose; + Stream->Abstraction.fo_read = &da_ConRead; + Stream->Abstraction.fo_write = &da_ConWrite; + Stream->Abstraction.fo_stat = &da_ConStat; + Stream->Abstraction.fo_lseek = &da_ConSeek; + Stream->Abstraction.fo_fcntl = &fnullop_fcntl; + Stream->Abstraction.fo_ioctl = &da_ConIoctl; + Stream->Abstraction.fo_poll = &da_ConPoll; + Stream->Abstraction.fo_flush = &fnullop_flush; + Stream->Abstraction.fo_delete = &fbadop_delete; + Stream->Abstraction.fo_mkdir = &fbadop_mkdir; + Stream->Abstraction.fo_rmdir = &fbadop_rmdir; + Stream->Abstraction.fo_rename = &fbadop_rename; + + Stream->NumRead = 0; + Stream->NumWritten = 0; + Stream->UnGetKey.ScanCode = SCAN_NULL; + Stream->UnGetKey.UnicodeChar = CHAR_NULL; + + if(Stream->Dev == NULL) { + continue; // No device for this stream. + } + ConNode[i] = __DevRegister(stdioNames[i], NULL, &da_ConOpen, Stream, 1, sizeof(ConInstance), stdioFlags[i]); + if(ConNode[i] == NULL) { + Status = EFIerrno; + break; + } + Stream->Parent = ConNode[i]; + } + return Status; +} + +RETURN_STATUS +EFIAPI +__Cons_deconstruct( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable +) +{ + int i; + + for(i = 0; i < NUM_SPECIAL; ++i) { + if(ConNode[i] != NULL) { + FreePool(ConNode[i]); + } + } + if(ConInstanceList != NULL) { + FreePool(ConInstanceList); + } + + return RETURN_SUCCESS; +} + +/* ######################################################################### */ +#if 0 /* Not implemented for Console */ + +static +int +EFIAPI +da_ConCntl( + struct __filedes *filp, + UINT32, + void *, + void * + ) +{ +} + +static +int +EFIAPI +da_ConFlush( + struct __filedes *filp + ) +{ + return 0; +} +#endif /* Not implemented for Console */ -- cgit v1.2.3