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