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. */
__main()40 void __main()
41 {
42   ;
43 }
44 
45 /** Clean up data as required by the exit() function.
46 
47 **/
48 void
exitCleanup(INTN ExitVal)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 **
ArgvConvert(UINTN Argc,CHAR16 ** Argv)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
ShellAppMain(IN UINTN Argc,IN CHAR16 ** Argv)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