1 /** @file 2 Establish the program environment and the "main" entry point. 3 4 All of the global data in the gMD structure is initialized to 0, NULL, or 5 SIG_DFL; as appropriate. 6 7 Copyright (c) 2010 - 2014, Intel Corporation. All rights reserved.<BR> 8 This program and the accompanying materials are licensed and made available under 9 the terms and conditions of the BSD License that accompanies this distribution. 10 The full text of the license may be found at 11 http://opensource.org/licenses/bsd-license. 12 13 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 14 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 15 **/ 16 #include <Uefi.h> 17 #include <Library/UefiLib.h> 18 #include <Library/DebugLib.h> 19 20 #include <Library/ShellCEntryLib.h> 21 #include <Library/MemoryAllocationLib.h> 22 #include <Library/TimerLib.h> 23 24 #include <LibConfig.h> 25 26 #include <errno.h> 27 #include <stdio.h> 28 #include <stdlib.h> 29 #include <string.h> 30 #include <time.h> 31 #include <MainData.h> 32 #include <unistd.h> 33 34 extern int main( int, char**); 35 extern int __sse2_available; 36 37 struct __MainData *gMD; 38 39 /* Worker function to keep GCC happy. */ 40 void __main() 41 { 42 ; 43 } 44 45 /** Clean up data as required by the exit() function. 46 47 **/ 48 void 49 exitCleanup(INTN ExitVal) 50 { 51 void (*CleanUp)(void); // Pointer to Cleanup Function 52 int i; 53 54 if(gMD != NULL) { 55 gMD->ExitValue = (int)ExitVal; 56 CleanUp = gMD->cleanup; // Preserve the pointer to the Cleanup Function 57 58 // Call all registered atexit functions in reverse order 59 i = gMD->num_atexit; 60 if( i > 0) { 61 do { 62 (gMD->atexit_handler[--i])(); 63 } while( i > 0); 64 } 65 66 if (CleanUp != NULL) { 67 CleanUp(); 68 } 69 } 70 } 71 72 /* Create mbcs versions of the Argv strings. */ 73 static 74 char ** 75 ArgvConvert(UINTN Argc, CHAR16 **Argv) 76 { 77 ssize_t AVsz; /* Size of a single nArgv string, or -1 */ 78 UINTN count; 79 char **nArgv; 80 char *string; 81 INTN nArgvSize; /* Cumulative size of narrow Argv[i] */ 82 83 DEBUG_CODE_BEGIN(); 84 DEBUG((DEBUG_INIT, "ArgvConvert called with %d arguments.\n", Argc)); 85 for(count = 0; count < ((Argc > 5)? 5: Argc); ++count) { 86 DEBUG((DEBUG_INIT, "Argument[%d] = \"%s\".\n", count, Argv[count])); 87 } 88 DEBUG_CODE_END(); 89 90 nArgvSize = Argc; 91 /* Determine space needed for narrow Argv strings. */ 92 for(count = 0; count < Argc; ++count) { 93 AVsz = (ssize_t)wcstombs(NULL, Argv[count], ARG_MAX); 94 if(AVsz < 0) { 95 DEBUG((DEBUG_ERROR, "ABORTING: Argv[%d] contains an unconvertable character.\n", count)); 96 exit(EXIT_FAILURE); 97 /* Not Reached */ 98 } 99 nArgvSize += AVsz; 100 } 101 102 /* Reserve space for the converted strings. */ 103 gMD->NCmdLine = (char *)AllocateZeroPool(nArgvSize+1); 104 if(gMD->NCmdLine == NULL) { 105 DEBUG((DEBUG_ERROR, "ABORTING: Insufficient memory.\n")); 106 exit(EXIT_FAILURE); 107 /* Not Reached */ 108 } 109 110 /* Convert Argument Strings. */ 111 nArgv = gMD->NArgV; 112 string = gMD->NCmdLine; 113 for(count = 0; count < Argc; ++count) { 114 nArgv[count] = string; 115 AVsz = wcstombs(string, Argv[count], nArgvSize) + 1; 116 DEBUG((DEBUG_INFO, "Cvt[%d] %d \"%s\" --> \"%a\"\n", (INT32)count, (INT32)AVsz, Argv[count], nArgv[count])); 117 string += AVsz; 118 nArgvSize -= AVsz; 119 if(nArgvSize < 0) { 120 DEBUG((DEBUG_ERROR, "ABORTING: Internal Argv[%d] conversion error.\n", count)); 121 exit(EXIT_FAILURE); 122 /* Not Reached */ 123 } 124 } 125 return gMD->NArgV; 126 } 127 128 INTN 129 EFIAPI 130 ShellAppMain ( 131 IN UINTN Argc, 132 IN CHAR16 **Argv 133 ) 134 { 135 struct __filedes *mfd; 136 char **nArgv; 137 INTN ExitVal; 138 int i; 139 140 ExitVal = (INTN)RETURN_SUCCESS; 141 gMD = AllocateZeroPool(sizeof(struct __MainData)); 142 if( gMD == NULL ) { 143 ExitVal = (INTN)RETURN_OUT_OF_RESOURCES; 144 } 145 else { 146 /* Initialize data */ 147 __sse2_available = 0; 148 _fltused = 1; 149 errno = 0; 150 EFIerrno = 0; 151 152 gMD->ClocksPerSecond = 1; 153 gMD->AppStartTime = (clock_t)((UINT32)time(NULL)); 154 155 // Initialize file descriptors 156 mfd = gMD->fdarray; 157 for(i = 0; i < (FOPEN_MAX); ++i) { 158 mfd[i].MyFD = (UINT16)i; 159 } 160 161 DEBUG((DEBUG_INIT, "StdLib: Open Standard IO.\n")); 162 i = open("stdin:", (O_RDONLY | O_TTY_INIT), 0444); 163 if(i == 0) { 164 i = open("stdout:", (O_WRONLY | O_TTY_INIT), 0222); 165 if(i == 1) { 166 i = open("stderr:", O_WRONLY, 0222); 167 } 168 } 169 if(i != 2) { 170 Print(L"ERROR Initializing Standard IO: %a.\n %r\n", 171 strerror(errno), EFIerrno); 172 } 173 174 /* Create mbcs versions of the Argv strings. */ 175 nArgv = ArgvConvert(Argc, Argv); 176 if(nArgv == NULL) { 177 ExitVal = (INTN)RETURN_INVALID_PARAMETER; 178 } 179 else { 180 if( setjmp(gMD->MainExit) == 0) { 181 errno = 0; // Clean up any "scratch" values from startup. 182 ExitVal = (INTN)main( (int)Argc, gMD->NArgV); 183 exitCleanup(ExitVal); 184 } 185 /* You reach here if: 186 * normal return from main() 187 * call to _Exit(), either directly or through exit(). 188 */ 189 ExitVal = (INTN)gMD->ExitValue; 190 } 191 192 if( ExitVal == EXIT_FAILURE) { 193 ExitVal = RETURN_ABORTED; 194 } 195 196 /* Close any open files */ 197 for(i = OPEN_MAX - 1; i >= 0; --i) { 198 (void)close(i); // Close properly handles closing a closed file. 199 } 200 201 /* Free the global MainData structure */ 202 if(gMD != NULL) { 203 if(gMD->NCmdLine != NULL) { 204 FreePool( gMD->NCmdLine ); 205 } 206 FreePool( gMD ); 207 } 208 } 209 return ExitVal; 210 } 211