]> git.kernelconcepts.de Git - karo-tx-redboot.git/blob - packages/redboot/v2_0/src/main.c
Initial revision
[karo-tx-redboot.git] / packages / redboot / v2_0 / src / main.c
1 //==========================================================================
2 //
3 //      main.c
4 //
5 //      RedBoot main routine
6 //
7 //==========================================================================
8 //####ECOSGPLCOPYRIGHTBEGIN####
9 // -------------------------------------------
10 // This file is part of eCos, the Embedded Configurable Operating System.
11 // Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004 Red Hat, Inc.
12 // Copyright (C) 2002, 2003, 2004 Gary Thomas
13 //
14 // eCos is free software; you can redistribute it and/or modify it under
15 // the terms of the GNU General Public License as published by the Free
16 // Software Foundation; either version 2 or (at your option) any later version.
17 //
18 // eCos is distributed in the hope that it will be useful, but WITHOUT ANY
19 // WARRANTY; without even the implied warranty of MERCHANTABILITY or
20 // FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
21 // for more details.
22 //
23 // You should have received a copy of the GNU General Public License along
24 // with eCos; if not, write to the Free Software Foundation, Inc.,
25 // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
26 //
27 // As a special exception, if other files instantiate templates or use macros
28 // or inline functions from this file, or you compile this file and link it
29 // with other works to produce a work based on this file, this file does not
30 // by itself cause the resulting work to be covered by the GNU General Public
31 // License. However the source code for this file must still be made available
32 // in accordance with section (3) of the GNU General Public License.
33 //
34 // This exception does not invalidate any other reasons why a work based on
35 // this file might be covered by the GNU General Public License.
36 //
37 // Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
38 // at http://sources.redhat.com/ecos/ecos-license/
39 // -------------------------------------------
40 //####ECOSGPLCOPYRIGHTEND####
41 //==========================================================================
42 //#####DESCRIPTIONBEGIN####
43 //
44 // Author(s):    gthomas
45 // Contributors: gthomas, tkoeller
46 // Date:         2000-07-14
47 // Purpose:      
48 // Description:  
49 //              
50 // This code is part of RedBoot (tm).
51 //
52 //####DESCRIPTIONEND####
53 //
54 //==========================================================================
55
56 #define  DEFINE_VARS
57 #include <redboot.h>
58 #include <cyg/hal/hal_arch.h>
59 #include <cyg/hal/hal_intr.h>
60 #include <cyg/hal/hal_if.h>
61 #include <cyg/hal/hal_cache.h>
62 #include CYGHWR_MEMORY_LAYOUT_H
63
64 #ifdef CYGPKG_IO_ETH_DRIVERS
65 #include <cyg/io/eth/eth_drv.h>            // Logical driver interfaces
66 #endif
67
68 #include <cyg/hal/hal_tables.h>
69 #include <cyg/infra/cyg_ass.h>         // assertion macros
70 #include <cyg/infra/cyg_type.h>
71 #ifdef CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS
72 #ifdef CYGBLD_HAL_PLATFORM_STUB_H
73 #include CYGBLD_HAL_PLATFORM_STUB_H
74 #else
75 #include <cyg/hal/plf_stub.h>
76 #endif
77 // GDB interfaces
78 extern void breakpoint(void);
79 #endif
80
81 // Builtin Self Test (BIST)
82 externC void bist(void);
83
84 // Path to code run from a go command or to GDB stubs
85 static void trampoline(unsigned long entry);
86
87 // Return path for code run from a go command or for GDB stubs
88 static void return_to_redboot(int status);
89
90 // Address of area where current context is saved before executing
91 // trampoline procedure
92 static void * saved_context;
93
94 // Status returned after trampoline execution
95 static int return_status;
96  
97
98 // CLI command processing (defined in this file)
99 RedBoot_cmd("version", 
100             "Display RedBoot version information",
101             "",
102             do_version
103     );
104 RedBoot_cmd("help", 
105             "Help about help?", 
106             "[<topic>]",
107             do_help 
108     );
109
110 static char go_usage[] = "[-w <timeout>] [-c] "
111 #ifdef CYGPKG_IO_ETH_DRIVERS
112                       "[-n] "
113 #endif
114                       "[entry]";
115
116 RedBoot_cmd("go", 
117             "Execute code at a location", 
118             go_usage,
119             do_go 
120     );
121 #ifdef HAL_PLATFORM_RESET
122 RedBoot_cmd("reset", 
123             "Reset the system", 
124             "",
125             do_reset 
126     );
127 #endif
128 #ifdef CYGSEM_REDBOOT_VARIABLE_BAUD_RATE
129 RedBoot_cmd("baudrate", 
130             "Set/Query the system console baud rate", 
131             "[-b <rate>]",
132             do_baud_rate
133     );
134 #endif
135
136 // Define table boundaries
137 CYG_HAL_TABLE_BEGIN( __RedBoot_INIT_TAB__, RedBoot_inits );
138 CYG_HAL_TABLE_END( __RedBoot_INIT_TAB_END__, RedBoot_inits );
139 extern struct init_tab_entry __RedBoot_INIT_TAB__[], __RedBoot_INIT_TAB_END__;
140
141 CYG_HAL_TABLE_BEGIN( __RedBoot_CMD_TAB__, RedBoot_commands );
142 CYG_HAL_TABLE_END( __RedBoot_CMD_TAB_END__, RedBoot_commands );
143 extern struct cmd __RedBoot_CMD_TAB__[], __RedBoot_CMD_TAB_END__;
144
145 CYG_HAL_TABLE_BEGIN( __RedBoot_IDLE_TAB__, RedBoot_idle );
146 CYG_HAL_TABLE_END( __RedBoot_IDLE_TAB_END__, RedBoot_idle );
147 extern struct idle_tab_entry __RedBoot_IDLE_TAB__[], __RedBoot_IDLE_TAB_END__;
148
149 #ifdef HAL_ARCH_PROGRAM_NEW_STACK
150 extern void HAL_ARCH_PROGRAM_NEW_STACK(void *fun);
151 #endif
152
153 // 
154 // [Null] Builtin [Power On] Self Test
155 //
156 void bist(void) CYGBLD_ATTRIB_WEAK;
157
158 void
159 bist(void) 
160 {
161 }
162
163 //
164 // 'version' command
165 //
166 void
167 do_version(int argc, char *argv[])
168 {
169 #if CYGBLD_REDBOOT_MAX_MEM_SEGMENTS > 1
170     int seg;
171 #endif
172 #ifdef CYGPKG_REDBOOT_FLASH
173     externC void _flash_info(void);
174 #endif
175     char *version = CYGACC_CALL_IF_MONITOR_VERSION();
176
177     diag_printf(version);
178 #ifdef HAL_PLATFORM_CPU
179     diag_printf("Platform: %s (%s) %s\n", HAL_PLATFORM_BOARD, HAL_PLATFORM_CPU, HAL_PLATFORM_EXTRA);
180 #endif
181     diag_printf("Copyright (C) 2000, 2001, 2002, 2003, 2004 Red Hat, Inc.\n\n");
182     diag_printf("RAM: %p-%p, ", (void*)ram_start, (void*)ram_end);
183     diag_printf("[%p-%p]", mem_segments[0].start, mem_segments[0].end);
184     diag_printf(" available\n");
185 #if CYGBLD_REDBOOT_MAX_MEM_SEGMENTS > 1
186     for (seg = 1;  seg < CYGBLD_REDBOOT_MAX_MEM_SEGMENTS;  seg++) {
187         if (mem_segments[seg].start != NO_MEMORY) {
188             diag_printf("     %p-%p, ", mem_segments[seg].start, mem_segments[seg].end);
189             diag_printf("[%p-%p]", mem_segments[seg].start, mem_segments[seg].end);
190             diag_printf(" available\n");
191         }
192     }
193 #endif
194 #ifdef CYGPKG_REDBOOT_FLASH
195     _flash_info();
196 #endif
197 }
198
199 //
200 // This function is called when RedBoot is idle (waiting for user
201 // input).  It will call any registered "idle" routines, e.g. scan
202 // for incoming network connections, blank an LCD screen, etc.
203 //
204 void
205 do_idle(bool is_idle)
206 {
207     struct idle_tab_entry *idle_entry;
208
209     for (idle_entry = __RedBoot_IDLE_TAB__; 
210          idle_entry != &__RedBoot_IDLE_TAB_END__;  idle_entry++) {
211         (*idle_entry->fun)(is_idle);
212     }
213 }
214
215 // Wrapper used by diag_printf()
216 static void
217 _mon_write_char(char c, void *param)
218 {
219     if (c == '\n') {
220         mon_write_char('\r');
221     }
222     mon_write_char(c);
223 }
224
225 //
226 // Handle illegal memory accesses (and other abort conditions)
227 //
228 static hal_jmp_buf error_jmpbuf;
229 #ifdef CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS
230 externC 
231 #endif
232   void* volatile __mem_fault_handler;
233
234 static void error_handler(void)
235 {
236     hal_longjmp(error_jmpbuf, 1);
237 }
238
239
240 //
241 // This is the main entry point for RedBoot
242 //
243
244 void
245 cyg_start(void)
246 {
247     int res = 0;
248     bool prompt = true;
249     static char line[CYGPKG_REDBOOT_MAX_CMD_LINE];
250     char *command;
251     struct cmd *cmd;
252     int cur;
253     struct init_tab_entry *init_entry;
254     extern char RedBoot_version[];
255 #if CYGBLD_REDBOOT_MAX_MEM_SEGMENTS > 1
256     int seg;
257 #endif
258
259     // Export version information
260     CYGACC_CALL_IF_MONITOR_VERSION_SET(RedBoot_version);
261
262     CYGACC_CALL_IF_MONITOR_RETURN_SET(return_to_redboot);
263
264     // Make sure the channels are properly initialized.
265     diag_init_putc(_mon_write_char);
266     hal_if_diag_init();
267
268     // Force console to output raw text - but remember the old setting
269     // so it can be restored if interaction with a debugger is
270     // required.
271     cur = CYGACC_CALL_IF_SET_CONSOLE_COMM(CYGNUM_CALL_IF_SET_COMM_ID_QUERY_CURRENT);
272     CYGACC_CALL_IF_SET_CONSOLE_COMM(CYGNUM_HAL_VIRTUAL_VECTOR_DEBUG_CHANNEL);
273 #ifdef CYGPKG_REDBOOT_ANY_CONSOLE
274     console_selected = false;
275 #endif
276     console_echo = true;
277     CYGACC_CALL_IF_DELAY_US((cyg_int32)2*100000);
278
279     ram_start = (unsigned char *)CYGMEM_REGION_ram;
280     ram_end = (unsigned char *)(CYGMEM_REGION_ram+CYGMEM_REGION_ram_SIZE);
281 #ifdef HAL_MEM_REAL_REGION_TOP
282     {
283         unsigned char *ram_end_tmp = ram_end;
284         ram_end = HAL_MEM_REAL_REGION_TOP( ram_end_tmp );
285     }
286 #endif
287 #ifdef CYGMEM_SECTION_heap1
288     workspace_start = (unsigned char *)CYGMEM_SECTION_heap1;
289     workspace_end = (unsigned char *)(CYGMEM_SECTION_heap1+CYGMEM_SECTION_heap1_SIZE);
290 #else
291     workspace_start = (unsigned char *)CYGMEM_REGION_ram;
292     workspace_end = (unsigned char *)(CYGMEM_REGION_ram+CYGMEM_REGION_ram_SIZE);
293 #endif
294
295     if ( ram_end < workspace_end ) {
296         // when *less* SDRAM is installed than the possible maximum,
297         // but the heap1 region remains greater...
298         workspace_end = ram_end;
299     }
300
301     // Nothing has ever been loaded into memory
302     entry_address = (unsigned long)NO_MEMORY;
303
304     bist();
305
306 #if defined(CYGPRI_REDBOOT_ZLIB_FLASH) && defined(CYGOPT_REDBOOT_FIS_ZLIB_COMMON_BUFFER)
307     fis_zlib_common_buffer =
308     workspace_end -= CYGNUM_REDBOOT_FIS_ZLIB_COMMON_BUFFER_SIZE;
309 #endif
310
311 #ifdef CYGFUN_REDBOOT_BOOT_SCRIPT
312     script_timeout = CYGNUM_REDBOOT_BOOT_SCRIPT_DEFAULT_TIMEOUT;
313 #endif
314
315     for (init_entry = __RedBoot_INIT_TAB__; init_entry != &__RedBoot_INIT_TAB_END__;  init_entry++) {
316         (*init_entry->fun)();
317     }
318
319     mem_segments[0].start = workspace_start;
320     mem_segments[0].end = workspace_end;
321 #if CYGBLD_REDBOOT_MAX_MEM_SEGMENTS > 1
322     for (seg = 1;  seg < CYGBLD_REDBOOT_MAX_MEM_SEGMENTS;  seg++) {
323         cyg_plf_memory_segment(seg, &mem_segments[seg].start, &mem_segments[seg].end);
324     }
325 #endif
326
327 #ifdef CYGSEM_REDBOOT_PLF_STARTUP
328
329     cyg_plf_redboot_startup();
330 #endif
331     do_version(0,0);
332
333 #ifdef CYGFUN_REDBOOT_BOOT_SCRIPT
334 # ifdef CYGDAT_REDBOOT_DEFAULT_BOOT_SCRIPT
335     if (!script) {
336       script = CYGDAT_REDBOOT_DEFAULT_BOOT_SCRIPT;
337     }
338 # endif
339     if (script) {
340         // Give the guy a chance to abort any boot script
341         unsigned char *hold_script = script;
342         int script_timeout_ms = script_timeout * CYGNUM_REDBOOT_BOOT_SCRIPT_TIMEOUT_RESOLUTION;
343         diag_printf("== Executing boot script in %d.%03d seconds - enter ^C to abort\n", 
344                     script_timeout_ms/1000, script_timeout_ms%1000);
345         script = (unsigned char *)0;
346         res = _GETS_CTRLC;  // Treat 0 timeout as ^C
347         while (script_timeout_ms >= CYGNUM_REDBOOT_CLI_IDLE_TIMEOUT) {
348             res = _rb_gets(line, sizeof(line), CYGNUM_REDBOOT_CLI_IDLE_TIMEOUT);
349             if (res >= _GETS_OK) {
350                 diag_printf("== Executing boot script in %d.%03d seconds - enter ^C to abort\n", 
351                             script_timeout_ms/1000, script_timeout_ms%1000);
352                 continue;  // Ignore anything but ^C
353             }
354             if (res != _GETS_TIMEOUT) break;
355             script_timeout_ms -= CYGNUM_REDBOOT_CLI_IDLE_TIMEOUT;
356         }
357         if (res == _GETS_CTRLC) {
358             script = (unsigned char *)0;  // Disable script
359         } else {
360             script = hold_script;  // Re-enable script
361         }
362     }
363 #endif
364
365     while (true) {
366         if (prompt) {
367             diag_printf("RedBoot> ");
368             prompt = false;
369         }
370 #if CYGNUM_REDBOOT_CMD_LINE_EDITING != 0
371         cmd_history = true;  // Enable history collection
372 #endif
373         res = _rb_gets(line, sizeof(line), CYGNUM_REDBOOT_CLI_IDLE_TIMEOUT);
374 #if CYGNUM_REDBOOT_CMD_LINE_EDITING != 0
375         cmd_history = false;  // Enable history collection
376 #endif
377         if (res == _GETS_TIMEOUT) {
378             // No input arrived
379         } else {
380 #ifdef CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS
381             if (res == _GETS_GDB) {
382                 int dbgchan;
383                 hal_virtual_comm_table_t *__chan;
384                 int i;
385                 // Special case of '$' - need to start GDB protocol
386                 gdb_active = true;
387                 // Mask interrupts on all channels
388                 for (i = 0;  i < CYGNUM_HAL_VIRTUAL_VECTOR_NUM_CHANNELS;  i++) {
389                     CYGACC_CALL_IF_SET_CONSOLE_COMM(i);
390                     __chan = CYGACC_CALL_IF_CONSOLE_PROCS();
391                     CYGACC_COMM_IF_CONTROL( *__chan, __COMMCTL_IRQ_DISABLE );
392                 }
393     
394                 CYGACC_CALL_IF_SET_CONSOLE_COMM(cur);
395
396                 // set up a temporary context that will take us to the trampoline
397                 HAL_THREAD_INIT_CONTEXT((CYG_ADDRWORD)workspace_end,
398                                         breakpoint, trampoline,0);
399
400                 // switch context to trampoline (get GDB stubs started)
401                 HAL_THREAD_SWITCH_CONTEXT(&saved_context, &workspace_end);
402
403                 gdb_active = false;
404
405                 dbgchan = CYGACC_CALL_IF_SET_DEBUG_COMM(CYGNUM_CALL_IF_SET_COMM_ID_QUERY_CURRENT);
406                 CYGACC_CALL_IF_SET_CONSOLE_COMM(dbgchan);
407             } else 
408 #endif // CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS
409             {
410                 expand_aliases(line, sizeof(line));
411                 command = (char *)&line;
412                 if ((*command == '#') || (*command == '=')) {
413                     // Special cases
414                     if (*command == '=') {
415                         // Print line on console
416                         diag_printf("%s\n", &line[2]);
417                     }
418                 } else {
419                     while (strlen(command) > 0) {                    
420                         if ((cmd = parse(&command, &argc, &argv[0])) != (struct cmd *)0) {
421                             // Try to handle aborts - messy because of the stack unwinding...
422                             __mem_fault_handler = error_handler;
423                             if (hal_setjmp(error_jmpbuf)) {
424                                 diag_printf("** command abort - illegal memory access?\n");
425                             } else {
426                                 (cmd->fun)(argc, argv);
427                             }
428                             __mem_fault_handler = 0;
429                         } else {
430                             diag_printf("** Error: Illegal command: \"%s\"\n", argv[0]);
431                         }
432                     }
433                 }
434                 prompt = true;
435             }
436         }
437     }
438 }
439
440 void
441 show_help(struct cmd *cmd, struct cmd *cmd_end, char *which, char *pre)
442 {
443     bool show;
444     int len = 0;
445
446     if (which) {
447         len = strlen(which);
448     }
449     while (cmd != cmd_end) {
450         show = true;
451         if (which && (strncasecmp(which, cmd->str, len) != 0)) {
452             show = false;
453         }
454         if (show) {
455             diag_printf("%s\n  %s %s %s\n", cmd->help, pre, cmd->str, cmd->usage);
456             if ((cmd->sub_cmds != (struct cmd *)0) && (which != (char *)0)) {
457                 show_help(cmd->sub_cmds, cmd->sub_cmds_end, 0, cmd->str);
458             }
459         }
460         cmd++;
461     }
462 }
463
464 void
465 do_help(int argc, char *argv[])
466 {
467     struct cmd *cmd;
468     char *which = (char *)0;
469
470     if (!scan_opts(argc, argv, 1, 0, 0, (void *)&which, OPTION_ARG_TYPE_STR, "<topic>")) {
471         diag_printf("Invalid argument\n");
472         return;
473     }
474     cmd = __RedBoot_CMD_TAB__;
475     show_help(cmd, &__RedBoot_CMD_TAB_END__, which, "");
476     return;
477 }
478
479 static void
480 trampoline(unsigned long entry)
481 {
482     typedef void code_fun(void);
483     code_fun *fun = (code_fun *)entry;
484     unsigned long oldints;
485
486     HAL_DISABLE_INTERRUPTS(oldints);
487
488 #ifdef HAL_ARCH_PROGRAM_NEW_STACK
489     HAL_ARCH_PROGRAM_NEW_STACK(fun);
490 #else
491     (*fun)();
492 #endif
493
494     HAL_THREAD_LOAD_CONTEXT(&saved_context);
495 }
496
497 static void
498 return_to_redboot(int status)
499 {
500     CYGARC_HAL_SAVE_GP();
501
502     return_status = status;
503     HAL_THREAD_LOAD_CONTEXT(&saved_context);
504     // never returns
505
506     // need this to balance above CYGARC_HAL_SAVE_GP on
507     // some platforms. It will never run, though.
508     CYGARC_HAL_RESTORE_GP();
509 }
510
511 void
512 do_go(int argc, char *argv[])
513 {
514     int i, cur, num_options;
515     unsigned long entry;
516     unsigned long oldints;
517     bool wait_time_set;
518     int  wait_time, res;
519     bool cache_enabled = false;
520 #ifdef CYGPKG_IO_ETH_DRIVERS
521     bool stop_net = false;
522 #endif
523     struct option_info opts[3];
524     char line[8];
525     hal_virtual_comm_table_t *__chan;
526
527     __mem_fault_handler = 0; // Let GDB handle any faults directly
528     entry = entry_address;  // Default from last 'load' operation
529     init_opts(&opts[0], 'w', true, OPTION_ARG_TYPE_NUM, 
530               (void *)&wait_time, (bool *)&wait_time_set, "wait timeout");
531     init_opts(&opts[1], 'c', false, OPTION_ARG_TYPE_FLG, 
532               (void *)&cache_enabled, (bool *)0, "go with caches enabled");
533     num_options = 2;
534 #ifdef CYGPKG_IO_ETH_DRIVERS
535     init_opts(&opts[2], 'n', false, OPTION_ARG_TYPE_FLG, 
536               (void *)&stop_net, (bool *)0, "go with network driver stopped");
537     num_options++;
538 #endif
539
540     CYG_ASSERT(num_options <= NUM_ELEMS(opts), "Too many options");
541
542     if (!scan_opts(argc, argv, 1, opts, num_options, (void *)&entry, OPTION_ARG_TYPE_NUM, "starting address"))
543     {
544         return;
545     }
546     if (entry == (unsigned long)NO_MEMORY) {
547         diag_printf("No entry point known - aborted\n");
548         return;
549     }
550     if (wait_time_set) {
551         int script_timeout_ms = wait_time * 1000;
552 #ifdef CYGSEM_REDBOOT_FLASH_CONFIG
553         unsigned char *hold_script = script;
554         script = (unsigned char *)0;
555 #endif
556         diag_printf("About to start execution at %p - abort with ^C within %d seconds\n",
557                     (void *)entry, wait_time);
558         while (script_timeout_ms >= CYGNUM_REDBOOT_CLI_IDLE_TIMEOUT) {
559             res = _rb_gets(line, sizeof(line), CYGNUM_REDBOOT_CLI_IDLE_TIMEOUT);
560             if (res == _GETS_CTRLC) {
561 #ifdef CYGSEM_REDBOOT_FLASH_CONFIG
562                 script = hold_script;  // Re-enable script
563 #endif
564                 return;
565             }
566             script_timeout_ms -= CYGNUM_REDBOOT_CLI_IDLE_TIMEOUT;
567         }
568     }
569
570     // Mask interrupts on all channels
571     cur = CYGACC_CALL_IF_SET_CONSOLE_COMM(CYGNUM_CALL_IF_SET_COMM_ID_QUERY_CURRENT);
572     for (i = 0;  i < CYGNUM_HAL_VIRTUAL_VECTOR_NUM_CHANNELS;  i++) {
573         CYGACC_CALL_IF_SET_CONSOLE_COMM(i);
574         __chan = CYGACC_CALL_IF_CONSOLE_PROCS();
575         CYGACC_COMM_IF_CONTROL( *__chan, __COMMCTL_IRQ_DISABLE );
576     }
577     CYGACC_CALL_IF_SET_CONSOLE_COMM(cur);
578
579     __chan = CYGACC_CALL_IF_CONSOLE_PROCS();
580     CYGACC_COMM_IF_CONTROL(*__chan, __COMMCTL_ENABLE_LINE_FLUSH);
581
582 #ifdef CYGPKG_IO_ETH_DRIVERS
583     if (stop_net)
584         eth_drv_stop();
585 #endif
586         
587     HAL_DISABLE_INTERRUPTS(oldints);
588     HAL_DCACHE_SYNC();
589     if (!cache_enabled) {
590         HAL_ICACHE_DISABLE();
591         HAL_DCACHE_DISABLE();
592         HAL_DCACHE_SYNC();
593     }
594     HAL_ICACHE_INVALIDATE_ALL();
595     HAL_DCACHE_INVALIDATE_ALL();
596     // set up a temporary context that will take us to the trampoline
597     HAL_THREAD_INIT_CONTEXT((CYG_ADDRWORD)workspace_end, 
598                             entry, trampoline, 0);
599
600     // switch context to trampoline
601     HAL_THREAD_SWITCH_CONTEXT(&saved_context, &workspace_end);
602
603     // we get back here by way of return_to_redboot()
604
605     // undo the changes we made before switching context
606     if (!cache_enabled) {
607         HAL_ICACHE_ENABLE();
608         HAL_DCACHE_ENABLE();
609     }
610
611     CYGACC_COMM_IF_CONTROL(*__chan, __COMMCTL_DISABLE_LINE_FLUSH);
612
613     HAL_RESTORE_INTERRUPTS(oldints);
614
615     diag_printf("\nProgram completed with status %d\n", return_status);
616 }
617
618 #ifdef HAL_PLATFORM_RESET
619 void
620 do_reset(int argc, char *argv[])
621 {
622     diag_printf("... Resetting.");
623     CYGACC_CALL_IF_DELAY_US(2*100000);
624     diag_printf("\n");
625     CYGACC_CALL_IF_RESET();
626     diag_printf("!! oops, RESET not working on this platform\n");
627 }
628 #endif
629
630 #ifdef CYGSEM_REDBOOT_VARIABLE_BAUD_RATE
631 #ifdef CYGSEM_REDBOOT_FLASH_CONFIG
632 #include <flash_config.h>
633 #endif
634
635 static int
636 set_comm_baud_rate(hal_virtual_comm_table_t *chan, int rate)
637 {
638     int current_rate;
639
640     current_rate = CYGACC_COMM_IF_CONTROL(*chan, __COMMCTL_GETBAUD);
641     if (rate != current_rate)
642         return CYGACC_COMM_IF_CONTROL(*chan, __COMMCTL_SETBAUD, rate);
643
644     return 0;
645 }
646
647 int
648 set_console_baud_rate(int rate)
649 {
650     int ret = -1;
651 #ifdef CYGPKG_REDBOOT_ANY_CONSOLE
652     if (!console_selected) {
653         int cur = CYGACC_CALL_IF_SET_CONSOLE_COMM(CYGNUM_CALL_IF_SET_COMM_ID_QUERY_CURRENT);
654         int i;
655         // Set baud for all channels
656         for (i = 0;  i < CYGNUM_HAL_VIRTUAL_VECTOR_COMM_CHANNELS;  i++) {
657             CYGACC_CALL_IF_SET_CONSOLE_COMM(i);
658             ret = set_comm_baud_rate(CYGACC_CALL_IF_CONSOLE_PROCS(), rate);
659             if (ret < 0)
660                 break;
661         }
662         CYGACC_CALL_IF_SET_CONSOLE_COMM(cur);
663     } else
664 #endif
665     ret = set_comm_baud_rate(CYGACC_CALL_IF_CONSOLE_PROCS(), rate);
666
667     if (ret < 0)
668         diag_printf("Setting console baud rate to %d failed\n", rate);
669
670     return ret;
671 }
672
673 static void
674 _sleep(int ms)
675 {
676     int i;
677     for (i = 0;  i < ms;  i++) {
678         CYGACC_CALL_IF_DELAY_US((cyg_int32)1000);
679     }
680 }
681
682 void
683 do_baud_rate(int argc, char *argv[])
684 {
685     int new_rate, ret, old_rate;
686     bool new_rate_set;
687     hal_virtual_comm_table_t *__chan;
688     struct option_info opts[1];
689 #ifdef CYGSEM_REDBOOT_FLASH_CONFIG
690     struct config_option opt;
691 #endif
692
693     init_opts(&opts[0], 'b', true, OPTION_ARG_TYPE_NUM, 
694               (void *)&new_rate, (bool *)&new_rate_set, "new baud rate");
695     if (!scan_opts(argc, argv, 1, opts, 1, 0, 0, "")) {
696         return;
697     }
698     __chan = CYGACC_CALL_IF_CONSOLE_PROCS();
699     if (new_rate_set) {
700         diag_printf("Baud rate will be changed to %d - update your settings\n", new_rate);
701         _sleep(500);  // Give serial time to flush
702         old_rate = CYGACC_COMM_IF_CONTROL(*__chan, __COMMCTL_GETBAUD);
703         ret = set_console_baud_rate(new_rate);
704         if (ret < 0) {
705             if (old_rate > 0) {
706                 // Try to restore
707                 set_console_baud_rate(old_rate);
708                 _sleep(500);  // Give serial time to flush
709                 diag_printf("\nret = %d\n", ret);
710             }
711             return;  // Couldn't set the desired rate
712         }
713         // Make sure this new rate works or back off to previous value
714         // Sleep for a few seconds, then prompt to see if it works
715         _sleep(3000);  // Give serial time to flush
716         if (!verify_action_with_timeout(5000, "Baud rate changed to %d", new_rate)) {
717             _sleep(500);  // Give serial time to flush
718             set_console_baud_rate(old_rate);
719             _sleep(500);  // Give serial time to flush
720             return;
721         }
722 #ifdef CYGSEM_REDBOOT_FLASH_CONFIG
723         opt.type = CONFIG_INT;
724         opt.enable = (char *)0;
725         opt.enable_sense = 1;
726         opt.key = "console_baud_rate";
727         opt.dflt = new_rate;
728         flash_add_config(&opt, true);
729 #endif
730     } else {
731         ret = CYGACC_COMM_IF_CONTROL(*__chan, __COMMCTL_GETBAUD);
732         diag_printf("Baud rate = ");
733         if (ret <= 0) {
734             diag_printf("unknown\n");
735         } else {
736             diag_printf("%d\n", ret);
737         }
738     }
739 }
740 #endif
741
742 //
743 // Validate an address to see if it is within any known RAM area
744 //
745 bool
746 valid_address(unsigned char *addr)
747 {
748     int seg;
749
750     for (seg = 0;  seg < CYGBLD_REDBOOT_MAX_MEM_SEGMENTS;  seg++) {
751         if (mem_segments[seg].start != NO_MEMORY) {
752             if ((addr >= mem_segments[seg].start) && (addr < mem_segments[seg].end)) {
753                 return true;
754             }
755         }
756     }
757     return false;
758 }