Mercurial > ecos
diff packages/redboot/current/src/main.c @ 115:6ed91473a1cd ecos-sw-2000-08-21
Merge from eCos master repository on 2000-08-21-22:40:54-BST
| author | jlarmour |
|---|---|
| date | Fri, 25 Aug 2000 17:32:38 +0000 |
| parents | |
| children | bd1a71e3e476 |
line wrap: on
line diff
new file mode 100644 --- /dev/null +++ b/packages/redboot/current/src/main.c @@ -0,0 +1,536 @@ +//========================================================================== +// +// main.c +// +// RedBoot main routine +// +//========================================================================== +//####COPYRIGHTBEGIN#### +// +// ------------------------------------------- +// The contents of this file are subject to the Red Hat eCos Public License +// Version 1.1 (the "License"); you may not use this file except in +// compliance with the License. You may obtain a copy of the License at +// http://www.redhat.com/ +// +// Software distributed under the License is distributed on an "AS IS" +// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +// License for the specific language governing rights and limitations under +// the License. +// +// The Original Code is eCos - Embedded Configurable Operating System, +// released September 30, 1998. +// +// The Initial Developer of the Original Code is Red Hat. +// Portions created by Red Hat are +// Copyright (C) 1998, 1999, 2000 Red Hat, Inc. +// All Rights Reserved. +// ------------------------------------------- +// +//####COPYRIGHTEND#### +//========================================================================== +//#####DESCRIPTIONBEGIN#### +// +// Author(s): gthomas +// Contributors: gthomas +// Date: 2000-07-14 +// Purpose: +// Description: +// +// This code is part of RedBoot (tm). +// +//####DESCRIPTIONEND#### +// +//========================================================================== + +#define DEFINE_VARS +#include <redboot.h> +#include <cyg/hal/hal_arch.h> +#include <cyg/hal/hal_intr.h> +#include <cyg/hal/hal_cache.h> +#include CYGHWR_MEMORY_LAYOUT_H + +#include <cyg/hal/hal_tables.h> + +// GDB interfaces +extern void breakpoint(void); + +// Internal functions +static struct cmd *parse(char *line, int *argc, char **argv); + +// CLI command processing (defined in this file) +RedBoot_cmd("help", + "Help about help?", + "<topic>", + do_help + ); +RedBoot_cmd("go", + "Execute code at a location", + "[-w <timeout>] [entry]", + do_go + ); +RedBoot_cmd("dump", + "Display (hex dump) a range of memory", + "<location> [<length>]", + do_dump + ); +RedBoot_cmd("cache", + "Manage machine caches", + "[ON | OFF]", + do_caches + ); + +// Define table boundaries +CYG_HAL_TABLE_BEGIN( __RedBoot_CMD_TAB__, RedBoot_commands ); +CYG_HAL_TABLE_END( __RedBoot_CMD_TAB_END__, RedBoot_commands ); +extern struct cmd __RedBoot_CMD_TAB__[], __RedBoot_CMD_TAB_END__; + +CYG_HAL_TABLE_BEGIN( __RedBoot_INIT_TAB__, RedBoot_inits ); +CYG_HAL_TABLE_END( __RedBoot_INIT_TAB_END__, RedBoot_inits ); +extern void_fun_ptr __RedBoot_INIT_TAB__[], __RedBoot_INIT_TAB_END__; + +// +// This is the main entry point for RedBoot +// +void +cyg_start(void) +{ + int res; + bool prompt = true; + char line[256]; + struct cmd *cmd; + int cur = CYGACC_CALL_IF_SET_CONSOLE_COMM(CYGNUM_CALL_IF_SET_COMM_ID_QUERY_CURRENT); + void_fun_ptr *init_fun; + + CYGACC_CALL_IF_SET_CONSOLE_COMM(CYGNUM_HAL_VIRTUAL_VECTOR_CONSOLE_CHANNEL); +#ifdef CYGPKG_REDBOOT_ANY_CONSOLE + console_selected = false; +#endif + CYGACC_CALL_IF_DELAY_US(2*100000); + + ram_start = (unsigned char *)CYGMEM_REGION_ram; + ram_end = (unsigned char *)(CYGMEM_REGION_ram+CYGMEM_REGION_ram_SIZE); + + printf("\nRedBoot(tm) debug environment - built %s, %s\n", __TIME__, __DATE__); + printf("Copyright (C) 2000, Red Hat, Inc.\n\n"); + printf("RAM: %p-%p\n", ram_start, ram_end); + + config_ok = false; + + for (init_fun = __RedBoot_INIT_TAB__; init_fun != &__RedBoot_INIT_TAB_END__; init_fun++) { + (*init_fun)(); + } + +#ifdef CYGSEM_REDBOOT_FLASH_CONFIG + // Give the guy a chance to abort any boot script + if (script) { + unsigned char *hold_script = script; + printf("== Executing boot script in %d seconds - enter ^C to abort\n", script_timeout); + script = (unsigned char *)0; + res = gets(line, sizeof(line), script_timeout*1000); + if (res == -2) { + script = (unsigned char *)0; // Disable script + } else { + script = hold_script; // Re-enable script + } + } +#endif + + while (true) { + if (prompt) { + printf("RedBoot> "); + prompt = false; + } + res = gets(line, sizeof(line), 250); + if (res < 0) { + // No input arrived +#ifdef CYGPKG_REDBOOT_NETWORKING + if (have_net) { + // Check for incoming TCP debug connection + net_io_test(); + } +#endif + } else { + if (res == 0) { + // Special case of '$' - need to start GDB protocol + CYGACC_CALL_IF_SET_CONSOLE_COMM(cur); + breakpoint(); // Get GDB stubs started, with a proper environment, etc. + } else { + if (strlen(line) > 0) { + if ((cmd = parse(line, &argc, &argv[0])) != (struct cmd *)0) { + (cmd->fun)(argc, argv); + } else { + printf("Illegal command: %s\n", line); + } + } + prompt = true; + } + } + } +} + +// +// Scan through an input line and break it into "arguments". These +// are space delimited strings. Return a structure which points to +// the strings, similar to a Unix program. +// Note: original input is destroyed by replacing the delimiters with +// null ('\0') characters for ease of use. +// +struct cmd * +parse(char *line, int *argc, char **argv) +{ + char *cp = line; + int indx = 0; + + while (*cp) { + // Skip leading spaces + while (*cp && *cp == ' ') cp++; + if (!*cp) { + break; // Line ended with a string of spaces + } + argv[indx++] = cp; + while (*cp) { + if (*cp == ' ') { + *cp++ = '\0'; + break; + } else if (*cp == '"') { + // Swallow quote, scan till following one + if (argv[indx-1] == cp) { + argv[indx-1] = ++cp; + } + while (*cp && *cp != '"') cp++; + if (!*cp) { + printf("Unbalanced string!\n"); + } else { + *cp++ = '\0'; + break; + } + } else { + cp++; + } + } + } + *argc = indx; + return cmd_search(__RedBoot_CMD_TAB__, &__RedBoot_CMD_TAB_END__, argv[0]); +} + +// +// Search through a list of commands +// +struct cmd * +cmd_search(struct cmd *tab, struct cmd *tabend, char *arg) +{ + int cmd_len; + struct cmd *cmd, *cmd2; + // Search command table + cmd_len = strlen(arg); + cmd = tab; + while (cmd != tabend) { + if (strncmpci(arg, cmd->str, cmd_len) == 0) { + if (strlen(cmd->str) > cmd_len) { + // Check for ambiguous commands here + // Note: If there are commands which are not length-unique + // then this check will be invalid. E.g. "du" and "dump" + bool first = true; + cmd2 = tab; + while (cmd2 != tabend) { + if ((cmd != cmd2) && + (strncmpci(arg, cmd2->str, cmd_len) == 0)) { + if (first) { + printf("Ambiguous command '%s', choices are: %s", arg, cmd->str); + first = false; + } + printf(" %s", cmd2->str); + } + cmd2++; + } + if (!first) { + // At least one ambiguity found - fail the lookup + printf("\n"); + return (struct cmd *)0; + } + } + return cmd; + } + cmd++; + } + return (struct cmd *)0; +} + +void +cmd_usage(struct cmd *tab, struct cmd *tabend, char *prefix) +{ + struct cmd *cmd; + printf("Usage:\n"); for (cmd = tab; cmd != tabend; cmd++) { + printf(" %s%s %s\n", prefix, cmd->str, cmd->usage); + } +} + +// Option processing + +// Initialize option table entry (required because these entries +// may have dynamic contents, thus cannot be statically initialized) +// +void +init_opts(struct option_info *opts, char flag, bool takes_arg, + int arg_type, void **arg, bool *arg_set, char *name) +{ + opts->flag = flag; + opts->takes_arg = takes_arg; + opts->arg_type = arg_type, + opts->arg = arg; + opts->arg_set = arg_set; + opts->name = name; +} + +// +// Scan command line arguments (argc/argv), processing options, etc. +// +bool +scan_opts(int argc, char *argv[], int first, + struct option_info *opts, int num_opts, + void **def_arg, int def_arg_type, char *def_descr) +{ + bool ret = true; + bool flag_ok; + bool def_arg_set = false; + int i, j; + char c, *s; + struct option_info *opt; + + if (def_arg && (def_arg_type == OPTION_ARG_TYPE_STR)) { + *def_arg = (char *)0; + } + opt = opts; + for (j = 0; j < num_opts; j++, opt++) { + *opt->arg_set = false; + if (!opt->takes_arg) { + *(int *)opt->arg = 0; + } + } + for (i = first; i < argc; i++) { + if (argv[i][0] == '-') { + c = argv[i][1]; + flag_ok = false; + opt = opts; + for (j = 0; j < num_opts; j++, opt++) { + if (c == opt->flag) { + if (*opt->arg_set) { + printf("%s alread set\n", opt->name); + ret = false; + } + if (opt->takes_arg) { + if (argv[i][2] == '=') { + s = &argv[i][3]; + } else { + s = argv[i+1]; + i++; + } + switch (opt->arg_type) { + case OPTION_ARG_TYPE_NUM: + if (!parse_num(s, (unsigned long *)opt->arg, 0, 0)) { + printf("invalid number '%s' for %s\n", s, opt->name); + ret = false; + } + break; + case OPTION_ARG_TYPE_STR: + *opt->arg = s; + break; + } + *opt->arg_set = true; + } else { + *(int *)opt->arg = *(int *)opt->arg + 1; + } + flag_ok = true; + break; + } + } + if (!flag_ok) { + printf("invalid flag '%c'\n", c); + ret = false; + } + } else { + if (def_arg) { + if (def_arg_set) { + printf("%s already set\n", def_descr); + ret = false; + } + switch (def_arg_type) { + case OPTION_ARG_TYPE_NUM: + if (!parse_num(argv[i], (unsigned long *)def_arg, 0, 0)) { + printf("invalid number '%s' for %s\n", argv[i], def_descr); + ret = false; + } + break; + case OPTION_ARG_TYPE_STR: + *def_arg = argv[i]; + break; + } + def_arg_set = true; + } else { + printf("no default/non-flag arguments supported\n"); + ret = false; + } + } + } + return ret; +} + +// +// Parse (scan) a number +// +bool +parse_num(char *s, unsigned long *val, char **es, char *delim) +{ + bool first = true; + int radix = 10; + char c; + unsigned long result = 0; + int digit; + + while (*s == ' ') s++; + while (*s) { + if (first && (s[0] == '0') && (tolower(s[1]) == 'x')) { + radix = 16; + s += 2; + } + first = false; + c = *s++; + if (_is_hex(c) && ((digit = _from_hex(c)) < radix)) { + // Valid digit + result = (result * radix) + digit; + } else { + if (delim != (char *)0) { + // See if this character is one of the delimiters + char *dp = delim; + while (*dp && (c != *dp)) dp++; + if (*dp) break; // Found a good delimiter + } + return false; // Malformatted number + } + } + *val = result; + if (es != (char **)0) { + *es = s; + } + return true; +} + +bool +parse_bool(char *s, bool *val) +{ + while (*s == ' ') s++; + if ((*s == 't') || (*s == 'T')) { + *val = true; + } else + if ((*s == 'f') || (*s == 'F')) { + *val = false; + } else { + return false; + } + return true; +} + + +void +do_caches(int argc, char *argv[]) +{ + unsigned long oldints; + if (argc == 2) { + if (strcmpci(argv[1], "on") == 0) { + HAL_DISABLE_INTERRUPTS(oldints); + HAL_ICACHE_ENABLE(); + HAL_DCACHE_ENABLE(); + HAL_RESTORE_INTERRUPTS(oldints); + } else if (strcmpci(argv[1], "off") == 0) { + HAL_DISABLE_INTERRUPTS(oldints); + HAL_DCACHE_SYNC(); + HAL_ICACHE_DISABLE(); + HAL_DCACHE_DISABLE(); + HAL_DCACHE_SYNC(); + HAL_ICACHE_INVALIDATE_ALL(); + HAL_DCACHE_INVALIDATE_ALL(); + HAL_RESTORE_INTERRUPTS(oldints); + } else { + printf("Invalid cache mode: %s\n", argv[1]); + } + } else { + printf("caches ?\n"); + } +} + + +void +do_help(int argc, char *argv[]) +{ + struct cmd *cmd; + + cmd = __RedBoot_CMD_TAB__; + while (cmd != &__RedBoot_CMD_TAB_END__) { + printf("%s\n %s %s\n", cmd->help, cmd->str, cmd->usage); + cmd++; + } + return; +} + +void +do_dump(int argc, char *argv[]) +{ + unsigned long base, len; + + if (argc < 2) { + printf("Dump what [location]?\n"); + return; + } + if (!parse_num(argv[1], &base, 0, 0)) { + printf("Invalid start address: %s\n", argv[1]); + return; + } + if (argc > 2) { + if (!parse_num(argv[2], &len, 0, 0)) { + printf("Invalid length/end address: %s\n", argv[2]); + return; + } + } else { + len = 32; + } + dump_buf((void *)base, len); +} + +void +do_go(int argc, char *argv[]) +{ + typedef void code_fun(void); + unsigned long entry; + unsigned long oldints; + code_fun *fun; + bool wait_time_set; + int wait_time, res; + struct option_info opts[1]; + char line[8]; + + entry = (unsigned long)entry_address; // Default from last 'load' operation + init_opts(&opts[0], 'w', true, OPTION_ARG_TYPE_NUM, + (void **)&wait_time, (bool *)&wait_time_set, "wait timeout"); + if (!scan_opts(argc, argv, 1, opts, 1, (void *)&entry, OPTION_ARG_TYPE_NUM, "starting address")) + { + return; + } + if (wait_time_set) { + printf("About to start execution at %p - abort with ^C within %d seconds\n", + (void *)entry, wait_time); + res = gets(line, sizeof(line), wait_time*1000); + if (res == -2) { + return; + } + } + fun = (code_fun *)entry; + HAL_DISABLE_INTERRUPTS(oldints); + HAL_DCACHE_SYNC(); + HAL_ICACHE_DISABLE(); + HAL_DCACHE_DISABLE(); + HAL_DCACHE_SYNC(); + HAL_ICACHE_INVALIDATE_ALL(); + HAL_DCACHE_INVALIDATE_ALL(); + (*fun)(); +}
