summaryrefslogtreecommitdiffstats
path: root/main/common/start.c
blob: 18919a2517ed319420e9e99b04f1271ce2644b8a (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
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)
{
}