Home | History | Annotate | Download | only in Main
      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