summaryrefslogblamecommitdiffstats
path: root/main/common/misc.c
blob: 3003a61eb859b071f523286af5877460c9f104c8 (plain) (tree)
1
2
3
4


                                                                           
  

























































                                                                           
                  



                
                        
 



                                                         
 
                


                 
                                                           



                 




                                                                          


               


                                                                    



                     

                              
 


                                                                       
                            
               

      





                        
 


                                                                           
                  
                              

                  
                              

                  
                              

                  
                              

      













                                                                 

                      
                            


                       
                     



            




                                                                           



                 







                                                                  




              




























                                                                           










                                                                     







                                    


                 


                                                                         



                 
                    
 





                                           
 
                   


                 


                                                                  



                 









                                                                        
                 
                                  
      
     

 
                 

                               






                                                                            


                      




                                                                         



                      
































                                            


                          






                                                                      



                                      
















                                                                          


                    


                                                                



                    









                                        










                                                                     
               




               



















                                                                         


                   

                                                             



                                     















                                                                           




                   



                                            





                   

                         














                                                                      

                   
     
               










                                                                   
                            






                                                           
                              



                                

























                                                            




                               











                              


      
/**************************************************************************
 *
 * Copyright (c) 2013 Alcatel-Lucent
 *
 * Alcatel Lucent licenses this file to You under the Apache License,
 * Version 2.0 (the "License"); you may not use this file except in
 * compliance with the License.  A copy of the License is contained the
 * file LICENSE at the top level of this repository.
 * You may also obtain a copy of the License at:
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 **************************************************************************
 *
 * misc.c:
 *
 * This file contains miscellaneous functions that are used by all target
 * versions of the monitor.
 *
 * Original author:     Ed Sutter (ed.sutter@alcatel-lucent.com)
 *
 */

#include "config.h"
#include "stddefs.h"
#include "cli.h"
#include "monflags.h"
#include "monlib.h"
#include "genlib.h"
#include "devices.h"
#include "cpuio.h"
#include <ctype.h>
#include "ether.h"
#include "tfs.h"
#include "tfsprivate.h"
#include "warmstart.h"
#include "timer.h"
#include "version.h"
#include "target_version.h"

#ifdef USR_HEADER_FUNC
extern void USR_HEADER_FUNC(int center);
#endif

/* extWatchDog():
 * This function pointer is used by the application to override the
 * monitor's configured watchdog functionality.  Refer to config.h
 * in umon_ports/template for more information on the WATCHDOG macro.
 */
#ifdef WATCHDOG_ENABLED
int (*extWatchDog)(void);
#endif

/* AppExitStatus:
 * Global copy of the application's exit status.
 */
int AppExitStatus;

char *
monVersion(void)
{
    static char buf[16];

    /* Build the version string as "X.Y.Z"
     */
    snprintf(buf,sizeof(buf),"%d.%d.%d",
             MAJOR_VERSION,MINOR_VERSION,TARGET_VERSION);

    return(buf);
}

/* ShowVersion():
 *  Display the build time and date of the running monitor.
 */
void
ShowVersion(void)
{
    printf("Monitor core release: %d.%d, target version %d (built: %s)\n",
           MAJOR_VERSION,MINOR_VERSION,TARGET_VERSION,monBuilt());
    if(ApplicationInfo[0]) {
        printf("%s\n",ApplicationInfo);
    }
}

/* monHeader():
 *  Dump the common stuff that is displayed at the console port when
 *  the monitor first starts up.  If called with 'center' set, then
 *  the printed output is centered on an 80-character screen width.
 */
void
monHeader(int center)
{
    char    *ip, *mac;
    int (*pfunc)(char *, ...);

    /* Some folks just don't like the opening banner to be centered, so
     * force center to 0 if DONT_CENTER_MONHEADER is defined...
     */
#ifdef DONT_CENTER_MONHEADER
    center = 0;
#endif

    if(center) {
        printf("\n\n");
        pfunc = cprintf;
    } else {
        pfunc = printf;
    }

    /* Optionally support (via config.h) up to four lines of user-specified
     * header text...
     */
#ifdef USR_HEADER1
    pfunc("%s\n",USR_HEADER1);
#endif
#ifdef USR_HEADER2
    pfunc("%s\n",USR_HEADER2);
#endif
#ifdef USR_HEADER3
    pfunc("%s\n",USR_HEADER3);
#endif
#ifdef USR_HEADER4
    pfunc("%s\n",USR_HEADER4);
#endif

    pfunc("MICRO MONITOR %s\n",monVersion());
    pfunc("Platform: %s\n",PLATFORM_NAME);
    pfunc("CPU: %s\n",CPU_NAME);
    pfunc("Built: %s\n",monBuilt());
    pfunc("Monitor RAM: 0x%06x-0x%06x\n",&bss_start,&bss_end);
    pfunc("Application RAM Base: 0x%06x\n",APPLICATION_RAMSTART);
    mac = getenv("ETHERADD");
    if(mac) {
        pfunc("MAC: %s\n",mac);
    }
    ip = getenv("IPADD");
    if(ip) {
        pfunc("IP: %s\n",ip);
    }

#ifdef USR_HEADER_FUNC
    USR_HEADER_FUNC(center);
#endif

#ifdef TOD_IN_MONHEADER
    showDate(center);
#endif
}

/* stkchk():
 *  The monitor's stack is a statically allocated array (MonStack).
 *  At initialization the stack pointer is set to the top of this stack
 *  and the bottom is loaded with 0xdeaddead.  This function simply
 *  verifies that the bottom of the stack is sane (still reads 0xdeaddead).
 *  If not, an error is printed.
 */
int
stkchk(char *msg)
{
    extern ulong    MonStack[];

    if(MonStack[0] != 0xdeaddead) {
        printf("\n***** Monitor stack overflow (%s) *****\n",msg);
        MonStack[0] = 0xdeaddead;
        return(-1);
    }
    return(0);
}

void
stkusage(void)
{
    int     i;
    ulong   *sp, stackval;
    extern ulong    MonStack[];

    printf("Stack: bottom=0x%lx, size=%d",(long)MonStack,MONSTACKSIZE);

    sp = MonStack;
    sp++;   /* Increment past 0xdeaddead */

    /* If the very first entry in stack space is not set to
     * STACK_PREINIT_VAL, then we assume that stkinit() was not called
     * at startup so don't print any stack usage information...
     */
    if(*sp == STACK_PREINIT_VAL) {
        for(i=0; i<MONSTACKSIZE; i+=4) {
            if(*sp++ != STACK_PREINIT_VAL) {
                break;
            }
        }
        printf(" (%d%% used)",((MONSTACKSIZE-i)*100)/MONSTACKSIZE);
    }
    printf("\n");

    /* Finally, check to make sure that the current stack pointer
     * resides within the MonStack[] array...
     */
    if((&stackval < MonStack) || (&stackval > &MonStack[MONSTACKSIZE/4])) {
        printf("WARNING: SP outside MonStack[]\n");
    }
}

/* stkinit():
 * This function should be called very early in uMon startup prior to
 * the stack pointer being set to the end of MonStack[].  It
 * simply initializes the MonStack[] array to a defined value so
 * that the stack can be observed for fullness during runtime.
 */
void
stkinit(void)
{
    extern ulong    MonStack[];
    volatile ulong *sp, *spend;

    sp = (ulong *)MonStack;
    spend = MonStack+MONSTACKSIZE/4;
    while(sp < spend) {
        *sp++ = STACK_PREINIT_VAL;
    }
}

/* writeprompt():
 *  Called to print out the monitor prompt.  If the shell variable PROMPT
 *  exists, then use the content of that variable as a prompt; otherwise,
 *  just print uMON>.
 */
void
writeprompt(void)
{
    char    *prompt;

    prompt = getenv("PROMPT");
    if(!prompt) {
        prompt = "uMON>";
    } else if(strcmp(prompt,"NULL") == 0) {
        return;
    }

    putstr(prompt);
}

/* CommandLoop():
 *  This function is called at the end of monitor initialization.
 *  The monitor spends most of its time here, waiting for incoming
 *  characters on the console interface.
 */
void
CommandLoop(void)
{
    static  char cmdline[CMDLINESIZE];

    while(1) {
        stkchk("Cmdloop");              /* Verify valid monitor stack */
        writeprompt();                  /* Issue prompt */
        memset(cmdline,0,CMDLINESIZE);  /* Clear command line buffer */
        if(getline(cmdline,CMDLINESIZE,INCLUDE_LINEEDIT) == 0) {
            continue;
        }
        docommand(cmdline,0);
#if INCLUDE_FLASH
        LowerFlashProtectWindow();
#endif
    }
}

int monitorFlags;

struct monflag monflagtbl[] = {
    { NOMONHEADER,  "nophdr" },     /* Don't print header at startup      */
    { NODEFRAGPRN,  "nopdf" },      /* Don't print defrag msg in tfsclean */
    { NOTFTPPRN,    "noptftp" },    /* Don't print for tftp RRQ or WRQ    */
    { NOMONCMDPRN,  "nopmcmd" },    /* Don't print for incoming moncmd    */
    { NOTFTPOVW,    "notftpovw" },  /* Don't allow TFTP srvr to overwrite */
    { NOEXITSTATUS, "noexitstat" }, /* Don't ptint app exit status */
    { 0,0 }
};

/* InitMonitorFlags():
 *  If the shell variable MONFLAGS exists, then use the content of that
 *  variable to populate the value monitorFlags.  The syntax of the shell
 *  variable is "xxx:yyyy:zzzz:abcd" where xxx,yyyy,zzzz and abcd are
 *  strings from the monflagtbl that represent some bit in the long that
 *  is to be set.
 */
void
InitMonitorFlags(void)
{
    char    *mf, *colon;
    struct monflag *mfp;

    monitorFlags = 0;

    mf = getenv("MONFLAGS");
    if(!mf) {
        return;
    }

    while(1) {
        colon = strchr(mf,':');
        if(colon) {
            *colon = 0;
        }
        mfp = monflagtbl;
        while(mfp->flagname) {
            if(!strcmp(mf,mfp->flagname)) {
                monitorFlags |= mfp->bit;
                break;
            }
            mfp++;
        }
        if(!mfp->flagname) {
            printf("MONFLAGS err: %s\n",mf);
        }
        if(colon) {
            *colon = ':';
        } else {
            break;
        }
        mf = colon+1;
    }
}

/* exceptionAutoRestart():
 *  Serves three purposes:
 *  1. Copies the verbose description of the exception to the
 *     shell variable EXCEPTION_TYPE.
 *  2. If there is an EXCEPTION_SCRIPT shell variable, then see if the
 *      user wants it to be executed.
 *  3. If there is no NO_EXCEPTION_RESTART variable, then
 *      call monrestart with the incoming value (usually INITIALIZE).
 */
void
exceptionAutoRestart(int restartvalue)
{
    char *script;
    char *arglist[2];

    setenv("EXCEPTION_TYPE",ExceptionType2String(ExceptionType));
    script = getenv("EXCEPTION_SCRIPT");
    if((script) &&
            (!pollConsole("Press any key to stop exception script.\n"))) {
        arglist[0] = script;
        arglist[1] = (char *)0;
        tfsrun(arglist,0);
    }

    if(!getenv("NO_EXCEPTION_RESTART")) {
        if(!pollConsole("Press any key to stop auto restart.\n")) {
            monrestart(restartvalue);
        }
    }
}

/* getAppRamStart():
 *  First looks for the content of APPRAMBASE shell variable;
 *  if present, that string is converted to a long and returned,
 *  else the value of APPLICATION_RAMSTART is returned.
 */
ulong
getAppRamStart(void)
{
    char    *apprambase;
    ulong   value;

    apprambase = getenv("APPRAMBASE");
    if(apprambase) {
        value = strtoul(apprambase,0,0);
    } else {
        value = APPLICATION_RAMSTART;
    }
    return(value);
}

/* uMonInRam():
 * This function returns 1 if the image of the running monitor is
 * in RAM; else 0.  The function ramtstfunc() should NEVER be called.
 * It is used as a test to determine if text space is writeable.
 * If it is, then we assume that uMon is running from RAM.
 */
static int
ramtstfunc(void)
{
    return(99);
}

int
uMonInRam(void)
{
    int rc;
    volatile unsigned char origvalue;
    volatile unsigned char *testmem = (unsigned char *)&ramtstfunc;

    origvalue = *testmem;
    *testmem = ~origvalue;

    /* Flush d-cache here to make sure that the write & readback actually
     * interact with external memory and not just d-cache...
     */
    flushDcache((char *)testmem,1);

    if(*testmem == (unsigned char)~origvalue) {
        rc = 1;
    } else {
        rc = 0;
    }

    *testmem = origvalue;
    return(rc);
}

/* inUmonBssSpace()
 *  Return 1 if the address range falls within MicroMonitor's
 *  own RAM space.
 */
int
inUmonBssSpace(char *start,char *end)
{
    static int nowarn;

    if(nowarn || getenv("NO_UMONBSS_WARNING")) {
        nowarn = 1;
        return(0);
    }

    if(((start >= (char *)&bss_start) && (start < (char *)&bss_end)) ||
            ((end >= (char *)&bss_start) && (end < (char *)&bss_end)) ||
            ((start <= (char *)&bss_start) && (end >= (char *)&bss_end))) {
        printf("\nError: addr range 0x%lx <-> 0x%lx violates uMon ram.\n",
               (long)start,(long)end);
        return(1);
    }

    return(0);
}

void
monrestart(int val)
{
    /* Allow UART0 transmit FIFO to empty...
     */
    flush_console_out();
    intsoff();
    warmstart(val);
}

void
appexit(int val)
{
    AppExitStatus = val;
    monrestart(APP_EXIT);
}

/* monWatchDog():
 * This function is hooked to the monitor API so that the application
 * can use the same function used by monitor code for exciting the
 * watchdog hardware.
 * Note that if there is no defined WATCHDOG_MACRO, then this function
 * returns -1; else it executes the macro and returns 0.  This
 * return value can be used by the application to decide whether or
 * not the call to mon_watchdog() even needs to occur.
 */
int
monWatchDog(void)
{
#ifdef WATCHDOG_ENABLED
    WATCHDOG_MACRO;
    return(0);
#else
    return(-1);
#endif
}

#if INCLUDE_SHELLVARS

/* putargv() & getargv():
 * The getargv() function provides a hook allowing the downloaded
 * application code to handle main(argc,argv) in a painless way.
 * The Argv[] array location is returned by mon_getargv() and is
 * assumed to contain the NULL terminated list of argv pointers...
 * Immediately after the NULL termination is the data that the argv
 * pointers are referencing.
 *
 * MONLIB NOTICE: getargv() is accessible through monlib.c.
 */

/* ArgvList:
 * Used by the code that is behind the mon_getargv() API.
 */
static char     *ArgvList[32];

int
putargv(int argnum,char *argptr)
{
    int i;
    char buf[8];

    if(argnum >= (sizeof(ArgvList)/sizeof(char *))) {
        return(-1);
    }

    if(argnum == 0) {
        for(i=0; i<(sizeof(ArgvList)/sizeof(char *)); i++) {
            sprintf(buf,"ARG%d",i);
            setenv(buf,0);
        }
        setenv("ARGC",0);
        ArgvList[0] = (char *)0;
    }

    ArgvList[argnum] = argptr;

    if(argptr) {
        sprintf(buf,"ARG%d",argnum);
        setenv(buf,ArgvList[argnum]);
    } else {
        shell_sprintf("ARGC","%d",argnum);
    }

    return(0);
}

void
getargv(int *argc,char ***argv)
{
    int i;

    if(argv) {
        *argv = &ArgvList[0];
    }
    for(i=0;; i++)
        if(ArgvList[i] == 0) {
            break;
        }
    if(argc) {
        *argc = i;
    }
}

#endif