]> git.kernelconcepts.de Git - karo-tx-redboot.git/blob - packages/redboot/v2_0/src/main.c
Merge branch 'master' of git+ssh://git.kernelconcepts.de/karo-tx-redboot
[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 #include <stdlib.h>
55 #define  DEFINE_VARS
56 #include <redboot.h>
57 #include <cyg/hal/hal_arch.h>
58 #include <cyg/hal/hal_intr.h>
59 #include <cyg/hal/hal_if.h>
60 #include <cyg/hal/hal_cache.h>
61 #include CYGHWR_MEMORY_LAYOUT_H
62
63 #ifdef CYGPKG_IO_ETH_DRIVERS
64 #include <cyg/io/eth/eth_drv.h>                    // Logical driver interfaces
65 #endif
66
67 #include <cyg/hal/hal_tables.h>
68 #include <cyg/infra/cyg_ass.h>             // assertion macros
69 #include <cyg/infra/cyg_type.h>
70 #ifdef CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS
71 #ifdef CYGBLD_HAL_PLATFORM_STUB_H
72 #include CYGBLD_HAL_PLATFORM_STUB_H
73 #else
74 #include <cyg/hal/plf_stub.h>
75 #endif
76 // GDB interfaces
77 extern void breakpoint(void);
78 #endif
79
80 // Builtin Self Test (BIST)
81 externC void bist(void);
82
83 // Path to code run from a go command or to GDB stubs
84 static void trampoline(unsigned long entry);
85
86 // Return path for code run from a go command or for GDB stubs
87 static void return_to_redboot(int status);
88
89 // Address of area where current context is saved before executing
90 // trampoline procedure
91 static void *saved_context;
92
93 // Status returned after trampoline execution
94 static int return_status;
95
96
97 // CLI command processing (defined in this file)
98 RedBoot_cmd("version",
99                         "Display RedBoot version information",
100                         "",
101                         do_version
102         );
103 RedBoot_cmd("help",
104                         "Help about help?",
105                         "[<topic>]",
106                         do_help
107         );
108
109 static char go_usage[] = "[-w <timeout>] [-c] "
110 #ifdef CYGPKG_IO_ETH_DRIVERS
111         "[-n] "
112 #endif
113         "[entry]";
114
115 RedBoot_cmd("go",
116                         "Execute code at a location",
117                         go_usage,
118                         do_go
119         );
120 #ifdef HAL_PLATFORM_RESET
121 RedBoot_cmd("reset",
122                         "Reset the system",
123                         "",
124                         do_reset
125         );
126 #endif
127 #ifdef CYGSEM_REDBOOT_VARIABLE_BAUD_RATE
128 RedBoot_cmd("baudrate",
129                         "Set/Query the system console baud rate",
130                         "[-b <rate>]",
131                         do_baud_rate
132         );
133 #endif
134
135 // Define table boundaries
136 CYG_HAL_TABLE_BEGIN( __RedBoot_INIT_TAB__, RedBoot_inits );
137 CYG_HAL_TABLE_END( __RedBoot_INIT_TAB_END__, RedBoot_inits );
138 extern struct init_tab_entry __RedBoot_INIT_TAB__[], __RedBoot_INIT_TAB_END__;
139
140 CYG_HAL_TABLE_BEGIN( __RedBoot_CMD_TAB__, RedBoot_commands );
141 CYG_HAL_TABLE_END( __RedBoot_CMD_TAB_END__, RedBoot_commands );
142 extern struct cmd __RedBoot_CMD_TAB__[], __RedBoot_CMD_TAB_END__;
143
144 CYG_HAL_TABLE_BEGIN( __RedBoot_IDLE_TAB__, RedBoot_idle );
145 CYG_HAL_TABLE_END( __RedBoot_IDLE_TAB_END__, RedBoot_idle );
146 extern struct idle_tab_entry __RedBoot_IDLE_TAB__[], __RedBoot_IDLE_TAB_END__;
147
148 #ifdef HAL_ARCH_PROGRAM_NEW_STACK
149 extern void HAL_ARCH_PROGRAM_NEW_STACK(void *fun);
150 #endif
151
152 //
153 // [Null] Builtin [Power On] Self Test
154 //
155 void bist(void) CYGBLD_ATTRIB_WEAK;
156
157 void
158 bist(void)
159 {
160 }
161
162 //
163 // 'version' command
164 //
165 void
166 do_version(int argc, char *argv[])
167 {
168 #if CYGBLD_REDBOOT_MAX_MEM_SEGMENTS > 1
169         int seg;
170 #endif
171 #ifdef CYGPKG_REDBOOT_FLASH
172         externC void _flash_info(void);
173 #endif
174         char *version = CYGACC_CALL_IF_MONITOR_VERSION();
175
176         diag_printf(version);
177 #ifdef HAL_PLATFORM_CPU
178         diag_printf("Platform: %s (%s) %s\n", HAL_PLATFORM_BOARD, HAL_PLATFORM_CPU, HAL_PLATFORM_EXTRA);
179 #endif
180         diag_printf("Copyright (C) 2000, 2001, 2002, 2003, 2004 Red Hat, Inc.\n");
181         diag_printf("Copyright (C) 2003, 2004, 2005, 2006 eCosCentric Limited\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 void *volatile __mem_fault_handler;
231
232 static void error_handler(void)
233 {
234         hal_longjmp(error_jmpbuf, 1);
235 }
236 #endif
237
238
239 //
240 // This is the main entry point for RedBoot
241 //
242
243 void
244 cyg_start(void)
245 {
246         int res = 0;
247         bool prompt = true;
248         static char line[CYGPKG_REDBOOT_MAX_CMD_LINE];
249         char *command;
250         struct cmd *cmd;
251         int cur;
252         struct init_tab_entry *init_entry;
253         extern char RedBoot_version[];
254 #if CYGBLD_REDBOOT_MAX_MEM_SEGMENTS > 1
255         int seg;
256 #endif
257
258         // Export version information
259         CYGACC_CALL_IF_MONITOR_VERSION_SET(RedBoot_version);
260
261         CYGACC_CALL_IF_MONITOR_RETURN_SET(return_to_redboot);
262
263         // Make sure the channels are properly initialized.
264         diag_init_putc(_mon_write_char);
265         hal_if_diag_init();
266
267         // Force console to output raw text - but remember the old setting
268         // so it can be restored if interaction with a debugger is
269         // required.
270         cur = CYGACC_CALL_IF_SET_CONSOLE_COMM(CYGNUM_CALL_IF_SET_COMM_ID_QUERY_CURRENT);
271         CYGACC_CALL_IF_SET_CONSOLE_COMM(CYGNUM_HAL_VIRTUAL_VECTOR_DEBUG_CHANNEL);
272 #ifdef CYGPKG_REDBOOT_ANY_CONSOLE
273         console_selected = false;
274 #endif
275         console_echo = true;
276
277         ram_start = (unsigned char *)CYGMEM_REGION_ram;
278         ram_end = (unsigned char *)(CYGMEM_REGION_ram+CYGMEM_REGION_ram_SIZE);
279 #ifdef HAL_MEM_REAL_REGION_TOP
280         {
281                 unsigned char *ram_end_tmp = ram_end;
282                 ram_end = HAL_MEM_REAL_REGION_TOP( ram_end_tmp );
283         }
284 #endif
285 #ifdef CYGMEM_SECTION_heap1
286         workspace_start = (unsigned char *)CYGMEM_SECTION_heap1;
287         workspace_end = (unsigned char *)(CYGMEM_SECTION_heap1+CYGMEM_SECTION_heap1_SIZE);
288 #else
289         workspace_start = (unsigned char *)CYGMEM_REGION_ram;
290         workspace_end = (unsigned char *)(CYGMEM_REGION_ram+CYGMEM_REGION_ram_SIZE);
291 #endif
292
293         if (ram_end < workspace_end) {
294                 // when *less* SDRAM is installed than the possible maximum,
295                 // but the heap1 region remains greater...
296                 workspace_end = ram_end;
297         }
298
299         workspace_end_init = workspace_end;
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 = NULL;
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                         } else if (res != _GETS_TIMEOUT) {
353                                 break;
354                         }
355                         script_timeout_ms -= CYGNUM_REDBOOT_CLI_IDLE_TIMEOUT;
356                 }
357                 if (res == _GETS_CTRLC) {
358                         script = NULL;  // Disable script
359                 } else {
360                         script = hold_script;  // Re-enable script
361                 }
362         }
363 #endif
364         CYG_ASSERT(workspace_start < workspace_end,
365                         "negative workspace size");
366         while (true) {
367                 if (prompt) {
368                         diag_printf("RedBoot> ");
369                         prompt = false;
370                 }
371 #if CYGNUM_REDBOOT_CMD_LINE_EDITING != 0
372                 cmd_history = true;  // Enable history collection
373 #endif
374                 res = _rb_gets(line, sizeof(line), CYGNUM_REDBOOT_CLI_IDLE_TIMEOUT);
375 #if CYGNUM_REDBOOT_CMD_LINE_EDITING != 0
376                 cmd_history = false;  // Enable history collection
377 #endif
378                 if (res == _GETS_TIMEOUT) {
379                         // No input arrived
380                 } else {
381 #ifdef CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS
382                         if (res == _GETS_GDB) {
383                                 int dbgchan;
384                                 hal_virtual_comm_table_t *__chan;
385                                 int i;
386                                 // Special case of '$' - need to start GDB protocol
387                                 gdb_active = true;
388                                 // Mask interrupts on all channels
389                                 for (i = 0;  i < CYGNUM_HAL_VIRTUAL_VECTOR_NUM_CHANNELS;  i++) {
390                                         CYGACC_CALL_IF_SET_CONSOLE_COMM(i);
391                                         __chan = CYGACC_CALL_IF_CONSOLE_PROCS();
392                                         CYGACC_COMM_IF_CONTROL( *__chan, __COMMCTL_IRQ_DISABLE );
393                                 }
394
395                                 CYGACC_CALL_IF_SET_CONSOLE_COMM(cur);
396
397                                 // set up a temporary context that will take us to the trampoline
398                                 HAL_THREAD_INIT_CONTEXT(workspace_end,
399                                                                                 breakpoint, trampoline,0);
400
401                                 // switch context to trampoline (get GDB stubs started)
402                                 HAL_THREAD_SWITCH_CONTEXT(&saved_context, &workspace_end);
403
404                                 gdb_active = false;
405
406                                 dbgchan = CYGACC_CALL_IF_SET_DEBUG_COMM(CYGNUM_CALL_IF_SET_COMM_ID_QUERY_CURRENT);
407                                 CYGACC_CALL_IF_SET_CONSOLE_COMM(dbgchan);
408                         } else
409 #endif // CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS
410                         {
411                                 expand_aliases(line, sizeof(line));
412                                 command = line;
413                                 if ((*command == '#') || (*command == '=')) {
414                                         // Special cases
415                                         if (*command == '=') {
416                                                 // Print line on console
417                                                 diag_printf("%s\n", &line[2]);
418                                         }
419                                 } else {
420                                         while (strlen(command) > 0) {
421                                                 if ((cmd = parse(&command, &argc, &argv[0])) != NULL) {
422                                                         // Try to handle aborts - messy because of the stack unwinding...
423 #ifdef CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS
424                                                         __mem_fault_handler = error_handler;
425 #endif
426                                                         if (hal_setjmp(error_jmpbuf)) {
427                                                                 diag_printf("** command abort - illegal memory access?\n");
428                                                         } else {
429                                                                 (cmd->fun)(argc, argv);
430                                                         }
431 #ifdef CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS
432                                                         __mem_fault_handler = 0;
433 #endif
434                                                 } else {
435                                                         diag_printf("** Error: Illegal command: \"%s\"\n", argv[0]);
436                                                 }
437                                         }
438                                 }
439                                 prompt = true;
440                         }
441                 }
442         }
443 }
444
445 void
446 show_help(struct cmd *cmd, struct cmd *cmd_end, char *which, char *pre)
447 {
448         bool show;
449         int len = 0;
450
451         if (which) {
452                 len = strlen(which);
453         }
454         while (cmd != cmd_end) {
455                 show = true;
456                 if (which && (strncasecmp(which, cmd->str, len) != 0)) {
457                         show = false;
458                 }
459                 if (show) {
460                         diag_printf("%s\n  %s %s %s\n", cmd->help, pre, cmd->str, cmd->usage);
461                         if ((cmd->sub_cmds != NULL) && (which != NULL)) {
462                                 show_help(cmd->sub_cmds, cmd->sub_cmds_end, 0, cmd->str);
463                         }
464                 }
465                 cmd++;
466         }
467 }
468
469 void
470 do_help(int argc, char *argv[])
471 {
472         struct cmd *cmd;
473         char *which = NULL;
474
475         if (!scan_opts(argc, argv, 1, NULL, 0, &which, OPTION_ARG_TYPE_STR, "<topic>")) {
476                 diag_printf("Invalid argument\n");
477                 return;
478         }
479         cmd = __RedBoot_CMD_TAB__;
480         show_help(cmd, &__RedBoot_CMD_TAB_END__, which, "");
481         return;
482 }
483
484 static void
485 trampoline(unsigned long entry)
486 {
487         typedef void code_fun(void);
488         code_fun *fun = (code_fun *)entry;
489         unsigned long oldints;
490
491         HAL_DISABLE_INTERRUPTS(oldints);
492
493 #ifdef HAL_ARCH_PROGRAM_NEW_STACK
494         HAL_ARCH_PROGRAM_NEW_STACK(fun);
495 #else
496         (*fun)();
497 #endif
498
499         HAL_THREAD_LOAD_CONTEXT(&saved_context);
500 }
501
502 static void
503 return_to_redboot(int status)
504 {
505         CYGARC_HAL_SAVE_GP();
506
507         return_status = status;
508         HAL_THREAD_LOAD_CONTEXT(&saved_context);
509         // never returns
510
511         // need this to balance above CYGARC_HAL_SAVE_GP on
512         // some platforms. It will never run, though.
513         CYGARC_HAL_RESTORE_GP();
514 }
515
516 void
517 do_go(int argc, char *argv[])
518 {
519         int i, cur, num_options = 0;
520         unsigned long entry;
521         unsigned long oldints;
522         bool wait_time_set;
523         int  wait_time, res;
524         bool cache_enabled = false;
525 #ifdef CYGPKG_IO_ETH_DRIVERS
526         bool stop_net = false;
527 #endif
528         struct option_info opts[3];
529         char line[8];
530         hal_virtual_comm_table_t *__chan;
531
532 #ifdef CYGDBG_HAL_DEBUG_GDB_INCLUDE_STUBS
533         __mem_fault_handler = 0; // Let GDB handle any faults directly
534 #endif
535         entry = entry_address;  // Default from last 'load' operation
536         init_opts(&opts[num_options++], 'w', true, OPTION_ARG_TYPE_NUM,
537                         &wait_time, &wait_time_set, "wait timeout");
538         init_opts(&opts[num_options++], 'c', false, OPTION_ARG_TYPE_FLG,
539                         &cache_enabled, NULL, "go with caches enabled");
540 #ifdef CYGPKG_IO_ETH_DRIVERS
541         init_opts(&opts[num_options++], 'n', false, OPTION_ARG_TYPE_FLG,
542                         &stop_net, NULL, "go with network driver stopped");
543 #endif
544
545         CYG_ASSERT(num_options <= NUM_ELEMS(opts), "Too many options");
546
547         if (!scan_opts(argc, argv, 1, opts, num_options, &entry,
548                                         OPTION_ARG_TYPE_NUM, "starting address")) {
549                 return;
550         }
551         if (entry == (unsigned long)NO_MEMORY) {
552                 err_printf("No entry point known - aborted\n");
553                 return;
554         }
555         if (wait_time_set) {
556                 int script_timeout_ms = wait_time * 1000;
557 #ifdef CYGSEM_REDBOOT_FLASH_CONFIG
558                 unsigned char *hold_script = script;
559                 script = NULL;
560 #endif
561                 diag_printf("About to start execution at %p - abort with ^C within %d seconds\n",
562                                         (void *)entry, wait_time);
563                 while (script_timeout_ms >= CYGNUM_REDBOOT_CLI_IDLE_TIMEOUT) {
564                         res = _rb_gets(line, sizeof(line), CYGNUM_REDBOOT_CLI_IDLE_TIMEOUT);
565                         if (res == _GETS_CTRLC) {
566 #ifdef CYGSEM_REDBOOT_FLASH_CONFIG
567                                 script = hold_script;  // Re-enable script
568 #endif
569                                 return;
570                         }
571                         script_timeout_ms -= CYGNUM_REDBOOT_CLI_IDLE_TIMEOUT;
572                 }
573         }
574
575         // Mask interrupts on all channels
576         cur = CYGACC_CALL_IF_SET_CONSOLE_COMM(CYGNUM_CALL_IF_SET_COMM_ID_QUERY_CURRENT);
577         for (i = 0;  i < CYGNUM_HAL_VIRTUAL_VECTOR_NUM_CHANNELS;  i++) {
578                 CYGACC_CALL_IF_SET_CONSOLE_COMM(i);
579                 __chan = CYGACC_CALL_IF_CONSOLE_PROCS();
580                 CYGACC_COMM_IF_CONTROL( *__chan, __COMMCTL_IRQ_DISABLE );
581         }
582         CYGACC_CALL_IF_SET_CONSOLE_COMM(cur);
583
584         __chan = CYGACC_CALL_IF_CONSOLE_PROCS();
585         CYGACC_COMM_IF_CONTROL(*__chan, __COMMCTL_ENABLE_LINE_FLUSH);
586
587 #ifdef CYGPKG_IO_ETH_DRIVERS
588         if (stop_net)
589                 eth_drv_stop();
590 #endif
591
592         HAL_DISABLE_INTERRUPTS(oldints);
593         HAL_DCACHE_SYNC();
594         if (!cache_enabled) {
595                 HAL_ICACHE_DISABLE();
596                 HAL_DCACHE_DISABLE();
597                 HAL_DCACHE_SYNC();
598         }
599         HAL_ICACHE_INVALIDATE_ALL();
600         HAL_DCACHE_INVALIDATE_ALL();
601         // set up a temporary context that will take us to the trampoline
602         HAL_THREAD_INIT_CONTEXT(workspace_end,
603                                                         entry, trampoline, 0);
604
605         // switch context to trampoline
606         HAL_THREAD_SWITCH_CONTEXT(&saved_context, &workspace_end);
607
608         // we get back here by way of return_to_redboot()
609
610         // undo the changes we made before switching context
611         if (!cache_enabled) {
612                 HAL_ICACHE_ENABLE();
613                 HAL_DCACHE_ENABLE();
614         }
615
616         CYGACC_COMM_IF_CONTROL(*__chan, __COMMCTL_DISABLE_LINE_FLUSH);
617
618         HAL_RESTORE_INTERRUPTS(oldints);
619
620         diag_printf("\nProgram completed with status %d\n", return_status);
621 }
622
623 #ifdef HAL_PLATFORM_RESET
624 void
625 do_reset(int argc, char *argv[])
626 {
627         diag_printf("... Resetting.");
628         CYGACC_CALL_IF_DELAY_US(2 * 100000);
629         diag_printf("\n");
630         CYGACC_CALL_IF_RESET();
631         diag_printf("!! oops, RESET not working on this platform\n");
632 }
633 #endif
634
635 #ifdef CYGSEM_REDBOOT_VARIABLE_BAUD_RATE
636 #ifdef CYGSEM_REDBOOT_FLASH_CONFIG
637 #include <flash_config.h>
638 #endif
639
640 static int
641 set_comm_baud_rate(hal_virtual_comm_table_t *chan, int rate)
642 {
643         int current_rate;
644
645         current_rate = CYGACC_COMM_IF_CONTROL(*chan, __COMMCTL_GETBAUD);
646         if (rate != current_rate)
647                 return CYGACC_COMM_IF_CONTROL(*chan, __COMMCTL_SETBAUD, rate);
648
649         return 0;
650 }
651
652 int
653 set_console_baud_rate(int rate)
654 {
655         int ret = -1;
656 #ifdef CYGPKG_REDBOOT_ANY_CONSOLE
657         if (!console_selected) {
658                 int cur = CYGACC_CALL_IF_SET_CONSOLE_COMM(CYGNUM_CALL_IF_SET_COMM_ID_QUERY_CURRENT);
659                 int i;
660                 // Set baud for all channels
661                 for (i = 0;  i < CYGNUM_HAL_VIRTUAL_VECTOR_COMM_CHANNELS;  i++) {
662                         CYGACC_CALL_IF_SET_CONSOLE_COMM(i);
663                         ret = set_comm_baud_rate(CYGACC_CALL_IF_CONSOLE_PROCS(), rate);
664                         if (ret < 0)
665                                 break;
666                 }
667                 CYGACC_CALL_IF_SET_CONSOLE_COMM(cur);
668         } else
669 #endif
670                 ret = set_comm_baud_rate(CYGACC_CALL_IF_CONSOLE_PROCS(), rate);
671
672         if (ret < 0)
673                 diag_printf("Setting console baud rate to %d failed\n", rate);
674
675         return ret;
676 }
677
678 static void
679 _sleep(int ms)
680 {
681         int i;
682         for (i = 0;  i < ms;  i++) {
683                 CYGACC_CALL_IF_DELAY_US((cyg_int32)1000);
684         }
685 }
686
687 void
688 do_baud_rate(int argc, char *argv[])
689 {
690         int new_rate, ret, old_rate;
691         bool new_rate_set;
692         hal_virtual_comm_table_t *__chan;
693         struct option_info opts[1];
694 #ifdef CYGSEM_REDBOOT_FLASH_CONFIG
695         struct config_option opt;
696 #endif
697
698         init_opts(&opts[0], 'b', true, OPTION_ARG_TYPE_NUM,
699                         &new_rate, &new_rate_set, "new baud rate");
700         if (!scan_opts(argc, argv, 1, opts, 1, NULL, 0, "")) {
701                 return;
702         }
703         __chan = CYGACC_CALL_IF_CONSOLE_PROCS();
704         if (new_rate_set) {
705                 diag_printf("Baud rate will be changed to %d - update your settings\n", new_rate);
706                 _sleep(500);  // Give serial time to flush
707                 old_rate = CYGACC_COMM_IF_CONTROL(*__chan, __COMMCTL_GETBAUD);
708                 ret = set_console_baud_rate(new_rate);
709                 if (ret < 0) {
710                         if (old_rate > 0) {
711                                 // Try to restore
712                                 set_console_baud_rate(old_rate);
713                                 _sleep(500);  // Give serial time to flush
714                                 diag_printf("\nret = %d\n", ret);
715                         }
716                         return;  // Couldn't set the desired rate
717                 }
718                 // Make sure this new rate works or back off to previous value
719                 // Sleep for a few seconds, then prompt to see if it works
720                 _sleep(3000);  // Give serial time to flush
721                 if (!verify_action_with_timeout(5000, "Baud rate changed to %d", new_rate)) {
722                         _sleep(500);  // Give serial time to flush
723                         set_console_baud_rate(old_rate);
724                         _sleep(500);  // Give serial time to flush
725                         return;
726                 }
727 #ifdef CYGSEM_REDBOOT_FLASH_CONFIG
728                 opt.type = CONFIG_INT;
729                 opt.enable = NULL;
730                 opt.enable_sense = 1;
731                 opt.key = "console_baud_rate";
732                 opt.dflt = new_rate;
733                 flash_add_config(&opt, true);
734 #endif
735         } else {
736                 ret = CYGACC_COMM_IF_CONTROL(*__chan, __COMMCTL_GETBAUD);
737                 diag_printf("Baud rate = ");
738                 if (ret <= 0) {
739                         diag_printf("unknown\n");
740                 } else {
741                         diag_printf("%d\n", ret);
742                 }
743         }
744 }
745 #endif
746
747 //
748 // Validate an address to see if it is within any known RAM area
749 //
750 bool
751 valid_address(unsigned char *addr)
752 {
753         int seg;
754
755         for (seg = 0;  seg < CYGBLD_REDBOOT_MAX_MEM_SEGMENTS;  seg++) {
756                 if (mem_segments[seg].start != NO_MEMORY) {
757                         if ((addr >= mem_segments[seg].start) && (addr < mem_segments[seg].end)) {
758                                 return true;
759                         }
760                 }
761         }
762         return false;
763 }
764
765 static unsigned long random;
766 /* provide at least _some_ sort of randomness */
767 #define MAX_LOOPS       1000
768
769 extern unsigned int hal_timer_count(void);
770
771 static void random_init(void)
772 {
773         unsigned int timer;
774         int i;
775
776         unsigned int start = hal_timer_count();
777
778         start = hal_timer_count();
779         for (i = 0; i < MAX_LOOPS; i++) {
780                 timer = hal_timer_count();
781                 srand(random + timer);
782                 random = rand();
783         }
784 }
785 RedBoot_init(random_init, RedBoot_INIT_FIRST);