| /** @file | |
| Establish the program environment and the "main" entry point. | |
| All of the global data in the gMD structure is initialized to 0, NULL, or | |
| SIG_DFL; as appropriate. | |
| Copyright (c) 2010 - 2014, 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/DebugLib.h> | |
| #include <Library/ShellCEntryLib.h> | |
| #include <Library/MemoryAllocationLib.h> | |
| #include <Library/TimerLib.h> | |
| #include <LibConfig.h> | |
| #include <errno.h> | |
| #include <stdio.h> | |
| #include <stdlib.h> | |
| #include <string.h> | |
| #include <time.h> | |
| #include <MainData.h> | |
| #include <unistd.h> | |
| extern int main( int, char**); | |
| extern int __sse2_available; | |
| struct __MainData *gMD; | |
| /* Worker function to keep GCC happy. */ | |
| void __main() | |
| { | |
| ; | |
| } | |
| /** Clean up data as required by the exit() function. | |
| **/ | |
| void | |
| exitCleanup(INTN ExitVal) | |
| { | |
| void (*CleanUp)(void); // Pointer to Cleanup Function | |
| int i; | |
| if(gMD != NULL) { | |
| gMD->ExitValue = (int)ExitVal; | |
| CleanUp = gMD->cleanup; // Preserve the pointer to the Cleanup Function | |
| // Call all registered atexit functions in reverse order | |
| i = gMD->num_atexit; | |
| if( i > 0) { | |
| do { | |
| (gMD->atexit_handler[--i])(); | |
| } while( i > 0); | |
| } | |
| if (CleanUp != NULL) { | |
| CleanUp(); | |
| } | |
| } | |
| } | |
| /* Create mbcs versions of the Argv strings. */ | |
| static | |
| char ** | |
| ArgvConvert(UINTN Argc, CHAR16 **Argv) | |
| { | |
| ssize_t AVsz; /* Size of a single nArgv string, or -1 */ | |
| UINTN count; | |
| char **nArgv; | |
| char *string; | |
| INTN nArgvSize; /* Cumulative size of narrow Argv[i] */ | |
| DEBUG_CODE_BEGIN(); | |
| DEBUG((DEBUG_INIT, "ArgvConvert called with %d arguments.\n", Argc)); | |
| for(count = 0; count < ((Argc > 5)? 5: Argc); ++count) { | |
| DEBUG((DEBUG_INIT, "Argument[%d] = \"%s\".\n", count, Argv[count])); | |
| } | |
| DEBUG_CODE_END(); | |
| nArgvSize = Argc; | |
| /* Determine space needed for narrow Argv strings. */ | |
| for(count = 0; count < Argc; ++count) { | |
| AVsz = (ssize_t)wcstombs(NULL, Argv[count], ARG_MAX); | |
| if(AVsz < 0) { | |
| DEBUG((DEBUG_ERROR, "ABORTING: Argv[%d] contains an unconvertable character.\n", count)); | |
| exit(EXIT_FAILURE); | |
| /* Not Reached */ | |
| } | |
| nArgvSize += AVsz; | |
| } | |
| /* Reserve space for the converted strings. */ | |
| gMD->NCmdLine = (char *)AllocateZeroPool(nArgvSize+1); | |
| if(gMD->NCmdLine == NULL) { | |
| DEBUG((DEBUG_ERROR, "ABORTING: Insufficient memory.\n")); | |
| exit(EXIT_FAILURE); | |
| /* Not Reached */ | |
| } | |
| /* Convert Argument Strings. */ | |
| nArgv = gMD->NArgV; | |
| string = gMD->NCmdLine; | |
| for(count = 0; count < Argc; ++count) { | |
| nArgv[count] = string; | |
| AVsz = wcstombs(string, Argv[count], nArgvSize) + 1; | |
| DEBUG((DEBUG_INFO, "Cvt[%d] %d \"%s\" --> \"%a\"\n", (INT32)count, (INT32)AVsz, Argv[count], nArgv[count])); | |
| string += AVsz; | |
| nArgvSize -= AVsz; | |
| if(nArgvSize < 0) { | |
| DEBUG((DEBUG_ERROR, "ABORTING: Internal Argv[%d] conversion error.\n", count)); | |
| exit(EXIT_FAILURE); | |
| /* Not Reached */ | |
| } | |
| } | |
| return gMD->NArgV; | |
| } | |
| INTN | |
| EFIAPI | |
| ShellAppMain ( | |
| IN UINTN Argc, | |
| IN CHAR16 **Argv | |
| ) | |
| { | |
| struct __filedes *mfd; | |
| char **nArgv; | |
| INTN ExitVal; | |
| int i; | |
| ExitVal = (INTN)RETURN_SUCCESS; | |
| gMD = AllocateZeroPool(sizeof(struct __MainData)); | |
| if( gMD == NULL ) { | |
| ExitVal = (INTN)RETURN_OUT_OF_RESOURCES; | |
| } | |
| else { | |
| /* Initialize data */ | |
| __sse2_available = 0; | |
| _fltused = 1; | |
| errno = 0; | |
| EFIerrno = 0; | |
| gMD->ClocksPerSecond = 1; | |
| gMD->AppStartTime = (clock_t)((UINT32)time(NULL)); | |
| // Initialize file descriptors | |
| mfd = gMD->fdarray; | |
| for(i = 0; i < (FOPEN_MAX); ++i) { | |
| mfd[i].MyFD = (UINT16)i; | |
| } | |
| DEBUG((DEBUG_INIT, "StdLib: Open Standard IO.\n")); | |
| i = open("stdin:", (O_RDONLY | O_TTY_INIT), 0444); | |
| if(i == 0) { | |
| i = open("stdout:", (O_WRONLY | O_TTY_INIT), 0222); | |
| if(i == 1) { | |
| i = open("stderr:", O_WRONLY, 0222); | |
| } | |
| } | |
| if(i != 2) { | |
| Print(L"ERROR Initializing Standard IO: %a.\n %r\n", | |
| strerror(errno), EFIerrno); | |
| } | |
| /* Create mbcs versions of the Argv strings. */ | |
| nArgv = ArgvConvert(Argc, Argv); | |
| if(nArgv == NULL) { | |
| ExitVal = (INTN)RETURN_INVALID_PARAMETER; | |
| } | |
| else { | |
| if( setjmp(gMD->MainExit) == 0) { | |
| errno = 0; // Clean up any "scratch" values from startup. | |
| ExitVal = (INTN)main( (int)Argc, gMD->NArgV); | |
| exitCleanup(ExitVal); | |
| } | |
| /* You reach here if: | |
| * normal return from main() | |
| * call to _Exit(), either directly or through exit(). | |
| */ | |
| ExitVal = (INTN)gMD->ExitValue; | |
| } | |
| if( ExitVal == EXIT_FAILURE) { | |
| ExitVal = RETURN_ABORTED; | |
| } | |
| /* Close any open files */ | |
| for(i = OPEN_MAX - 1; i >= 0; --i) { | |
| (void)close(i); // Close properly handles closing a closed file. | |
| } | |
| /* Free the global MainData structure */ | |
| if(gMD != NULL) { | |
| if(gMD->NCmdLine != NULL) { | |
| FreePool( gMD->NCmdLine ); | |
| } | |
| FreePool( gMD ); | |
| } | |
| } | |
| return ExitVal; | |
| } |