diff options
Diffstat (limited to 'main/common/start.c')
-rw-r--r-- | main/common/start.c | 496 |
1 files changed, 496 insertions, 0 deletions
diff --git a/main/common/start.c b/main/common/start.c new file mode 100644 index 0000000..18919a2 --- /dev/null +++ b/main/common/start.c @@ -0,0 +1,496 @@ +/************************************************************************** + * + * 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. + * + ************************************************************************** + * + * start.c: + * + * This is typically the first 'C' code executed by the processor after a + * reset. + * + * Original author: Ed Sutter (ed.sutter@alcatel-lucent.com) + * + */ +#include "config.h" +#include "cpu.h" +#include "cpuio.h" +#include "stddefs.h" +#include "genlib.h" +#include "devices.h" +#include "ether.h" +#include "warmstart.h" +#include "monlib.h" +#include "monflags.h" +#include "boardinfo.h" +#include "cli.h" +#include "tfsprivate.h" +#include "fbi.h" + +#ifdef PRE_COMMANDLOOP_HOOK +extern void PRE_COMMANDLOOP_HOOK(); +#endif + +#ifndef EXCEPTION_HEADING +#define EXCEPTION_HEADING "EXCEPTION" +#endif + +extern void vinit(void); +extern int addcommand(struct monCommand *cmdlist, char *cmdlvl); + +/* StateOfMonitor: + * The StateOfMonitor variable is used throughout the code to determine + * how the monitor started up. In general, the three most common + * startup types are: INITIALIZE, APP_EXIT and EXCEPTION. + */ +int StateOfMonitor; + +/* MonStack: + * The monitor's stack is declared within the monitor's own .bss space. + * This keeps the memory map simple, the only thing that needs to be + * accounted for is that in the bss init loop, this section should not + * be initialized. MONSTACKSIZE must be defined in config.h. + */ +ulong MonStack[MONSTACKSIZE/4]; + +/* APPLICATION_RAMSTART: + * Loaded with the address after which the application can be loaded. + */ +ulong APPLICATION_RAMSTART; + +/* BOOTROM_BASE: + * Loaded with the address considered to be the base address at which + * the monitor is burned into flash. + */ +ulong BOOTROM_BASE; + +/* LoopsPerMillisecond: + * Loaded with a count (established in config.h) that is an estimation of + * one second of elapsed time. It is NOT an accurate value, but serves the + * purpose of providing a hardware-independent mechanism for establishing + * a reasonable estimation of one second's worth of elapsed time. + */ +ulong LoopsPerMillisecond; + +/* init0(): + * The code in this function was originally part of start(). It has been + * moved out so that this portion of the initialization can be re-used by + * AppWarmStart(). See notes in AppWarmStart() for more details on this. + */ +void +init0(void) +{ + /* Store the base address of memory that is used by application. + * Start it off on the next 4K boundary after the end of monitor ram. + * Usually APPRAMBASE and BOOTROMBASE can be retrieved from bss_end and + * boot_base; but they can be overridden with values specified in the + * target-specific config.h file. + */ +#ifdef APPRAMBASE_OVERRIDE + APPLICATION_RAMSTART = APPRAMBASE_OVERRIDE; +#else + APPLICATION_RAMSTART = (((ulong)&bss_end) | 0xfff) + 1; +#endif + +#ifdef BOOTROMBASE_OVERRIDE + BOOTROM_BASE = BOOTROMBASE_OVERRIDE; +#else + BOOTROM_BASE = (ulong)&boot_base; +#endif + + /* Load bottom of stack with 0xdeaddead to be used by stkchk(). + */ + MonStack[0] = 0xdeaddead; + + /* Set up default loops-per-millisecond count. + */ + LoopsPerMillisecond = LOOPS_PER_SECOND/1000; + + /* Clear any user-installed command list. + */ + addcommand(0,0); +} + +/* init1(): + * This is the first level of initialization (aside from the most fundamental + * stuff that must be done in reset.s) that is done after the system resets. + */ +void +init1(void) +{ + initCPUio(); /* Configure all chip-selects, parallel IO + * direction registers, etc... This may have + * been done already in reset.s + */ + vinit(); /* Initialize the CPU's vector table. */ + InitRemoteIO(); /* Initialize all application-settable IO functions */ + + if (ConsoleBaudRate == 0) + ConsoleBaudRate = DEFAULT_BAUD_RATE; + + devInit(ConsoleBaudRate); + +} + +/* init2(): + */ +void +init2(void) +{ +#if INCLUDE_FLASH | INCLUDE_TFS + int rc = 0; +#endif + +#if INCLUDE_FBI + if (StateOfMonitor == INITIALIZE) + fbdev_init(); /* Initialize the frame-buffer device */ +#endif + +#if INCLUDE_FLASH + if (StateOfMonitor == INITIALIZE) + rc = FlashInit(); /* Init flashop data structures and (possibly) */ + /* the relocatable functions. This MUST be */ +#endif /* done prior to turning on cache!!! */ + + cacheInit(); /* Initialize cache. */ + +#if INCLUDE_ETHERNET + enreset(); /* Clear the ethernet interface. */ +#endif + +#if INCLUDE_TFS + if (rc != -1) /* Start up TFS as long as flash */ + tfsstartup(); /* initialization didn't fail. */ +#endif +} + +/* init3(): + * As each target boots up, it calls init1() and init2() to do multiple + * phases of hardware initialization. This third initialization phase + * is always common to all targets... + * It is possible that this is being called by AppWarmStart(). In this + * case, the user can specify which portions of the monitor code are + * to be initialized by specifying them in the startmode mask. + */ +static void +_init3(ulong startmode) +{ + char *baud; + +#if INCLUDE_LINEEDIT + /* Initialize command line history table. */ + historyinit(); +#endif + +#if INCLUDE_SHELLVARS + /* Init shell variable table. */ + ShellVarInit(); +#endif + +#if INCLUDE_USRLVL + /* Set user level to its max, then allow monrc file to adjust it. */ + initUsrLvl(MAXUSRLEVEL); +#endif + +#if INCLUDE_BOARDINFO + /* Check for board-specific-information in some otherwise unused + * sector. Also, establish shell variables from this information + * based on the content of the boardinfo structure. + * Note that the second half of the board-specific information setup + * (the call to BoardInfoEnvInit()) must be done AFTER ShellVarInit() + * because shell variables are established here. + */ + if (startmode & WARMSTART_BOARDINFO) { + BoardInfoInit(); + BoardInfoEnvInit(); + } +#endif + +#ifdef MONCOMPTR + /* If MONCOMPTR is defined, then verify that the definition matches + * the location of the actual moncomptr value. The definition in + * config.h is provided so that outside applications can include that + * header file so that the value passed into monConnect() is defined + * formally. The REAL value of moncomptr is based on the location of + * the pointer in monitor memory space, determined only after the final + * link has been done. As a result, this check is used to simply verify + * that the definition matches the actual value. + */ + { + if (MONCOMPTR != (ulong)&moncomptr) + printf("\nMONCOMPTR WARNING: runtime != definition\n"); + } +#endif + +#if INCLUDE_TFS + /* After basic initialization, if the monitor's run-control file + * exists, run it prior to EthernetStartup() so that the + * MAC/IP addresses can be configured based on shell variables + * that would be loaded by the rc file. + */ + if (startmode & WARMSTART_RUNMONRC) + tfsrunrcfile(); +#endif + + /* After MONRC is run, establish monitor flags... + */ + InitMonitorFlags(); + + /* We've run the monrc file at this point, so check for the + * presence of the CONSOLEBAUD shell variable. If it's set, + * then use the value to re-establish the console baud rate. + * If it isn't set, then establish the CONSOLEBAUD shell variable + * using the default, pre-configured baud rate. + */ + baud = getenv("CONSOLEBAUD"); + if (baud) + ChangeConsoleBaudrate(atoi(baud)); + ConsoleBaudEnvSet(); + +#if INCLUDE_ETHERNET +#if INCLUDE_STOREMAC + storeMac(0); +#endif + if (startmode & WARMSTART_IOINIT) + EthernetStartup(0,1); +#endif + + /* Now that all has been initialized, display the monitor header. */ +#ifndef NO_UMON_STARTUP_HDR + if (startmode & WARMSTART_MONHEADER) { + if (!MFLAGS_NOMONHEADER()) + monHeader(1); + } +#endif + +#if INCLUDE_FBI + if (StateOfMonitor == INITIALIZE) + fbi_splash(); +#endif + +#if INCLUDE_TFS + if (startmode & WARMSTART_TFSAUTOBOOT) + tfsrunboot(); +#endif +} + +void +init3(void) +{ + _init3(WARMSTART_ALL); +} + +/* umonBssInit(): + * All of the monitor-owned ram is within it's bss space as defined + * by the locations of bss_start and bss_end in the memory map + * definition file. This includes the the monitor's stack and + * heap. To support a generic, C-based BSS initialzation loop, + * this loop must skip over the space allocated to the stack because + * the stack is likely to be in use during this loop... + */ +void +umonBssInit(void) +{ + int *tmp; + volatile ulong *bssptr; + + tmp = &bss_start; + bssptr = (ulong *)tmp; + while(bssptr < MonStack) + *bssptr++ = 0; + bssptr = (ulong *)MonStack+(MONSTACKSIZE/4); + tmp = &bss_end; + while(bssptr < (ulong *)tmp) + *bssptr++ = 0; +} + +/* AppWarmStart(): + * This function is provided to allow the application to partially + * restart the monitor. It supports the situation where an application + * run but the monitor has not already been initialized. This would be + * the case if some type of debugger (JTAG or BDM probably) was attached + * to the target and it was used to download and run the application. + * If this type of debug connection does not support the ability to run + * after the monitor runs, then the application must be able to somehow + * get the monitor initialized without having it go through a complete + * warmstart. + * This will only run through the stack space provided by the application. + */ +void +AppWarmStart(ulong mask) +{ + /* First initialize monitor bss space (skipping over MonStack[]): */ + if (mask & WARMSTART_BSSINIT) + umonBssInit(); + + StateOfMonitor = INITIALIZE; + + /* Initialize some of the real fundamental stuff regardless of + * the incoming mask. + */ + init0(); + + /* Subset of init1(): */ + if (mask & WARMSTART_IOINIT) { + initCPUio(); + InitRemoteIO(); + if (ConsoleBaudRate == 0) + ConsoleBaudRate = DEFAULT_BAUD_RATE; + devInit(ConsoleBaudRate); + } + init2(); + _init3(mask); +} + +/* start(): + * Called at the end of reset.s as the first C function after processor + * bootup. It is passed a state that is used to determine whether or not + * the CPU is restarting as a result of a warmstart or a coldstart. If + * the restart is a coldstart, then state will be INITIALIZE. if the + * restart is a warmstart, then there are a few typical values of state, + * the most common of which are APP_EXIT and EXCEPTION. + * + * The bss_start and bss_end variables are usually defined in the + * target-specific linker memory-map definition file. They symbolically + * identify the beginning and end of the .bss section. Many compilers + * support intrinsic tags for this; however, since it is apparently not + * consistent from one toolset to the next; I chose to make up my own + * tags so that this file never changes from one toolset to the next. + * + * The FORCE_BSS_INIT definition can be established in the target-specific + * config.h file to force .bss space initialization regardless of warm/cold + * start. + */ +void +start(int state) +{ + char buf[48]; + +#ifdef FORCE_BSS_INIT + state = INITIALIZE; +#endif + + /* Based on the incoming value of 'state' we may or may not initialize + * monitor-owned ram. Ideally, we only want to initialize + * monitor-owned ram when 'state' is INITIALIZE (power-up or reset); + * however, to support the case where the incoming state variable may + * be corrupted, we also initialize monitor-owned ram when 'state' + * is anything unexpected... + */ + switch(state) { + case EXCEPTION: + case APP_EXIT: + break; + case INITIALIZE: + default: + umonBssInit(); + break; + } + + /* Now that the BSS clear loop has been done, we can copy the + * value of state (either a register or on stack) to the global + * variable (in BSS) StateOfMonitor... + */ + StateOfMonitor = state; + + /* Step through different phases of startup... + */ + init0(); + init1(); + init2(); + + /* Depending on the type of startup, alert the console and do + * further initialization as needed... + */ + switch(StateOfMonitor) { + case INITIALIZE: + reginit(); + init3(); + break; + case APP_EXIT: + EthernetStartup(0,0); + if (!MFLAGS_NOEXITSTATUS()) { + printf("\nApplication Exit Status: %d (0x%x)\n", + AppExitStatus,AppExitStatus); + } + break; + case EXCEPTION: + EthernetStartup(0,0); + printf("\n%s: '%s'\n",EXCEPTION_HEADING, + ExceptionType2String(ExceptionType)); + printf(" Occurred near 0x%lx",ExceptionAddr); + if (AddrToSym(-1,ExceptionAddr,buf,0)) + printf(" (within %s)",buf); + printf("\n\n"); + exceptionAutoRestart(INITIALIZE); + break; + default: + printf("Unexpected monitor state: 0x%x (sp @ 0x%x)\n", + StateOfMonitor, buf); + /* To attempt to recover from the bad state, just do + * what INITIALIZE would do... + */ + reginit(); + init3(); + break; + } + +#ifdef LOCK_FLASH_PROTECT_RANGE + /* Issue the command that will cause the range of sectors + * designated by FLASH_PROTECT_RANGE to be locked. This only + * works if the flash device is capable of being locked. + */ + sprintf(buf,"flash lock %s",FLASH_PROTECT_RANGE); + docommand(buf,0); +#endif + +#ifdef PRE_COMMANDLOOP_HOOK + PRE_COMMANDLOOP_HOOK(); +#endif + + /* Enter the endless loop of command processing: */ + CommandLoop(); + + printf("ERROR: CommandLoop() returned\n"); + monrestart(INITIALIZE); +} + +/* __eabi(): + * Called intrinsically by main for some PowerPc builds. + * I'm not sure what the purpose of it is, but EABI is Embedded Application + * Binary Interface, and is documented on Motorola's web site at + * http://www.mcu.motsps.com/lit/manuals/eabispec.html#536421 + */ +void +__eabi(void) +{ +} + +/* __main() or __gccmain(): called intrinsically by main. One or the other + * is typically used to run constructors and destructors for C++. If this + * function is not created here, then the compiler will automatically create + * one and with it, will come other unnecessary baggage. + */ +void +__main(void) +{ +} + +void +__gccmain(void) +{ +} |