Mercurial > flash_v2
comparison packages/redboot/current/src/main.c @ 130:eb9fd8c04db3 ecos-sw-2000-10-23
Merge from eCos master repository on 2000-10-23-17:01:37-BST
| author | jlarmour |
|---|---|
| date | Mon, 23 Oct 2000 17:10:57 +0000 |
| parents | 0c2b7be0d798 |
| children | 0ae0bc38e387 |
comparison
equal
deleted
inserted
replaced
| 129:605a0fc6f385 | 130:eb9fd8c04db3 |
|---|---|
| 53 #include <cyg/hal/hal_tables.h> | 53 #include <cyg/hal/hal_tables.h> |
| 54 | 54 |
| 55 // GDB interfaces | 55 // GDB interfaces |
| 56 extern void breakpoint(void); | 56 extern void breakpoint(void); |
| 57 | 57 |
| 58 // Internal functions | |
| 59 static struct cmd *parse(char *line, int *argc, char **argv); | |
| 60 | |
| 61 // CLI command processing (defined in this file) | 58 // CLI command processing (defined in this file) |
| 62 RedBoot_cmd("help", | 59 RedBoot_cmd("help", |
| 63 "Help about help?", | 60 "Help about help?", |
| 64 "<topic>", | 61 "<topic>", |
| 65 do_help | 62 do_help |
| 69 "[-w <timeout>] [entry]", | 66 "[-w <timeout>] [entry]", |
| 70 do_go | 67 do_go |
| 71 ); | 68 ); |
| 72 RedBoot_cmd("dump", | 69 RedBoot_cmd("dump", |
| 73 "Display (hex dump) a range of memory", | 70 "Display (hex dump) a range of memory", |
| 74 "<location> [<length>]", | 71 "-b <location> [-l <length>]", |
| 75 do_dump | 72 do_dump |
| 76 ); | 73 ); |
| 77 RedBoot_cmd("cache", | 74 RedBoot_cmd("cache", |
| 78 "Manage machine caches", | 75 "Manage machine caches", |
| 79 "[ON | OFF]", | 76 "[ON | OFF]", |
| 80 do_caches | 77 do_caches |
| 81 ); | 78 ); |
| 82 | 79 |
| 83 // Define table boundaries | 80 // Define table boundaries |
| 81 CYG_HAL_TABLE_BEGIN( __RedBoot_INIT_TAB__, RedBoot_inits ); | |
| 82 CYG_HAL_TABLE_END( __RedBoot_INIT_TAB_END__, RedBoot_inits ); | |
| 83 extern struct init_tab_entry __RedBoot_INIT_TAB__[], __RedBoot_INIT_TAB_END__; | |
| 84 CYG_HAL_TABLE_BEGIN( __RedBoot_CMD_TAB__, RedBoot_commands ); | 84 CYG_HAL_TABLE_BEGIN( __RedBoot_CMD_TAB__, RedBoot_commands ); |
| 85 CYG_HAL_TABLE_END( __RedBoot_CMD_TAB_END__, RedBoot_commands ); | 85 CYG_HAL_TABLE_END( __RedBoot_CMD_TAB_END__, RedBoot_commands ); |
| 86 extern struct cmd __RedBoot_CMD_TAB__[], __RedBoot_CMD_TAB_END__; | 86 extern struct cmd __RedBoot_CMD_TAB__[], __RedBoot_CMD_TAB_END__; |
| 87 | |
| 88 CYG_HAL_TABLE_BEGIN( __RedBoot_INIT_TAB__, RedBoot_inits ); | |
| 89 CYG_HAL_TABLE_END( __RedBoot_INIT_TAB_END__, RedBoot_inits ); | |
| 90 extern struct init_tab_entry __RedBoot_INIT_TAB__[], __RedBoot_INIT_TAB_END__; | |
| 91 | 87 |
| 92 // | 88 // |
| 93 // This is the main entry point for RedBoot | 89 // This is the main entry point for RedBoot |
| 94 // | 90 // |
| 95 void | 91 void |
| 127 | 123 |
| 128 #ifdef CYGSEM_REDBOOT_FLASH_CONFIG | 124 #ifdef CYGSEM_REDBOOT_FLASH_CONFIG |
| 129 // Give the guy a chance to abort any boot script | 125 // Give the guy a chance to abort any boot script |
| 130 if (script) { | 126 if (script) { |
| 131 unsigned char *hold_script = script; | 127 unsigned char *hold_script = script; |
| 132 printf("== Executing boot script in %d seconds - enter ^C to abort\n", script_timeout); | 128 int script_timeout_ms = script_timeout * CYGNUM_REDBOOT_FLASH_SCRIPT_TIMEOUT_RESOLUTION; |
| 129 printf("== Executing boot script in %d.%03d seconds - enter ^C to abort\n", | |
| 130 script_timeout_ms/1000, script_timeout_ms%1000); | |
| 133 script = (unsigned char *)0; | 131 script = (unsigned char *)0; |
| 134 res = gets(line, sizeof(line), script_timeout*1000); | 132 res = gets(line, sizeof(line), script_timeout_ms); |
| 135 if (res == -2) { | 133 if (res == -2) { |
| 136 script = (unsigned char *)0; // Disable script | 134 script = (unsigned char *)0; // Disable script |
| 137 } else { | 135 } else { |
| 138 script = hold_script; // Re-enable script | 136 script = hold_script; // Re-enable script |
| 139 } | 137 } |
| 162 } else { | 160 } else { |
| 163 if (strlen(line) > 0) { | 161 if (strlen(line) > 0) { |
| 164 if ((cmd = parse(line, &argc, &argv[0])) != (struct cmd *)0) { | 162 if ((cmd = parse(line, &argc, &argv[0])) != (struct cmd *)0) { |
| 165 (cmd->fun)(argc, argv); | 163 (cmd->fun)(argc, argv); |
| 166 } else { | 164 } else { |
| 167 printf("Illegal command: %s\n", line); | 165 printf("** Error: Illegal command: %s\n", line); |
| 168 } | 166 } |
| 169 } | 167 } |
| 170 prompt = true; | 168 prompt = true; |
| 171 } | 169 } |
| 172 } | 170 } |
| 173 } | 171 } |
| 174 } | 172 } |
| 175 | |
| 176 // | |
| 177 // Scan through an input line and break it into "arguments". These | |
| 178 // are space delimited strings. Return a structure which points to | |
| 179 // the strings, similar to a Unix program. | |
| 180 // Note: original input is destroyed by replacing the delimiters with | |
| 181 // null ('\0') characters for ease of use. | |
| 182 // | |
| 183 struct cmd * | |
| 184 parse(char *line, int *argc, char **argv) | |
| 185 { | |
| 186 char *cp = line; | |
| 187 int indx = 0; | |
| 188 | |
| 189 while (*cp) { | |
| 190 // Skip leading spaces | |
| 191 while (*cp && *cp == ' ') cp++; | |
| 192 if (!*cp) { | |
| 193 break; // Line ended with a string of spaces | |
| 194 } | |
| 195 argv[indx++] = cp; | |
| 196 while (*cp) { | |
| 197 if (*cp == ' ') { | |
| 198 *cp++ = '\0'; | |
| 199 break; | |
| 200 } else if (*cp == '"') { | |
| 201 // Swallow quote, scan till following one | |
| 202 if (argv[indx-1] == cp) { | |
| 203 argv[indx-1] = ++cp; | |
| 204 } | |
| 205 while (*cp && *cp != '"') cp++; | |
| 206 if (!*cp) { | |
| 207 printf("Unbalanced string!\n"); | |
| 208 } else { | |
| 209 *cp++ = '\0'; | |
| 210 break; | |
| 211 } | |
| 212 } else { | |
| 213 cp++; | |
| 214 } | |
| 215 } | |
| 216 } | |
| 217 *argc = indx; | |
| 218 return cmd_search(__RedBoot_CMD_TAB__, &__RedBoot_CMD_TAB_END__, argv[0]); | |
| 219 } | |
| 220 | |
| 221 // | |
| 222 // Search through a list of commands | |
| 223 // | |
| 224 struct cmd * | |
| 225 cmd_search(struct cmd *tab, struct cmd *tabend, char *arg) | |
| 226 { | |
| 227 int cmd_len; | |
| 228 struct cmd *cmd, *cmd2; | |
| 229 // Search command table | |
| 230 cmd_len = strlen(arg); | |
| 231 cmd = tab; | |
| 232 while (cmd != tabend) { | |
| 233 if (strncmpci(arg, cmd->str, cmd_len) == 0) { | |
| 234 if (strlen(cmd->str) > cmd_len) { | |
| 235 // Check for ambiguous commands here | |
| 236 // Note: If there are commands which are not length-unique | |
| 237 // then this check will be invalid. E.g. "du" and "dump" | |
| 238 bool first = true; | |
| 239 cmd2 = tab; | |
| 240 while (cmd2 != tabend) { | |
| 241 if ((cmd != cmd2) && | |
| 242 (strncmpci(arg, cmd2->str, cmd_len) == 0)) { | |
| 243 if (first) { | |
| 244 printf("Ambiguous command '%s', choices are: %s", arg, cmd->str); | |
| 245 first = false; | |
| 246 } | |
| 247 printf(" %s", cmd2->str); | |
| 248 } | |
| 249 cmd2++; | |
| 250 } | |
| 251 if (!first) { | |
| 252 // At least one ambiguity found - fail the lookup | |
| 253 printf("\n"); | |
| 254 return (struct cmd *)0; | |
| 255 } | |
| 256 } | |
| 257 return cmd; | |
| 258 } | |
| 259 cmd++; | |
| 260 } | |
| 261 return (struct cmd *)0; | |
| 262 } | |
| 263 | |
| 264 void | |
| 265 cmd_usage(struct cmd *tab, struct cmd *tabend, char *prefix) | |
| 266 { | |
| 267 struct cmd *cmd; | |
| 268 printf("Usage:\n"); for (cmd = tab; cmd != tabend; cmd++) { | |
| 269 printf(" %s%s %s\n", prefix, cmd->str, cmd->usage); | |
| 270 } | |
| 271 } | |
| 272 | |
| 273 // Option processing | |
| 274 | |
| 275 // Initialize option table entry (required because these entries | |
| 276 // may have dynamic contents, thus cannot be statically initialized) | |
| 277 // | |
| 278 void | |
| 279 init_opts(struct option_info *opts, char flag, bool takes_arg, | |
| 280 int arg_type, void **arg, bool *arg_set, char *name) | |
| 281 { | |
| 282 opts->flag = flag; | |
| 283 opts->takes_arg = takes_arg; | |
| 284 opts->arg_type = arg_type, | |
| 285 opts->arg = arg; | |
| 286 opts->arg_set = arg_set; | |
| 287 opts->name = name; | |
| 288 } | |
| 289 | |
| 290 // | |
| 291 // Scan command line arguments (argc/argv), processing options, etc. | |
| 292 // | |
| 293 bool | |
| 294 scan_opts(int argc, char *argv[], int first, | |
| 295 struct option_info *opts, int num_opts, | |
| 296 void **def_arg, int def_arg_type, char *def_descr) | |
| 297 { | |
| 298 bool ret = true; | |
| 299 bool flag_ok; | |
| 300 bool def_arg_set = false; | |
| 301 int i, j; | |
| 302 char c, *s; | |
| 303 struct option_info *opt; | |
| 304 | |
| 305 if (def_arg && (def_arg_type == OPTION_ARG_TYPE_STR)) { | |
| 306 *def_arg = (char *)0; | |
| 307 } | |
| 308 opt = opts; | |
| 309 for (j = 0; j < num_opts; j++, opt++) { | |
| 310 if (opt->arg_set) { | |
| 311 *opt->arg_set = false; | |
| 312 } | |
| 313 if (!opt->takes_arg) { | |
| 314 switch (opt->arg_type) { | |
| 315 case OPTION_ARG_TYPE_NUM: | |
| 316 *(int *)opt->arg = 0; | |
| 317 break; | |
| 318 case OPTION_ARG_TYPE_FLG: | |
| 319 *(bool *)opt->arg = false; | |
| 320 break; | |
| 321 } | |
| 322 } | |
| 323 } | |
| 324 for (i = first; i < argc; i++) { | |
| 325 if (argv[i][0] == '-') { | |
| 326 c = argv[i][1]; | |
| 327 flag_ok = false; | |
| 328 opt = opts; | |
| 329 for (j = 0; j < num_opts; j++, opt++) { | |
| 330 if (c == opt->flag) { | |
| 331 if (opt->arg_set && *opt->arg_set) { | |
| 332 printf("%s alread set\n", opt->name); | |
| 333 ret = false; | |
| 334 } | |
| 335 if (opt->takes_arg) { | |
| 336 if (argv[i][2] == '=') { | |
| 337 s = &argv[i][3]; | |
| 338 } else { | |
| 339 s = argv[i+1]; | |
| 340 i++; | |
| 341 } | |
| 342 switch (opt->arg_type) { | |
| 343 case OPTION_ARG_TYPE_NUM: | |
| 344 if (!parse_num(s, (unsigned long *)opt->arg, 0, 0)) { | |
| 345 printf("invalid number '%s' for %s\n", s, opt->name); | |
| 346 ret = false; | |
| 347 } | |
| 348 break; | |
| 349 case OPTION_ARG_TYPE_STR: | |
| 350 *opt->arg = s; | |
| 351 break; | |
| 352 } | |
| 353 *opt->arg_set = true; | |
| 354 } else { | |
| 355 switch (opt->arg_type) { | |
| 356 case OPTION_ARG_TYPE_NUM: | |
| 357 *(int *)opt->arg = *(int *)opt->arg + 1; | |
| 358 break; | |
| 359 case OPTION_ARG_TYPE_FLG: | |
| 360 *(bool *)opt->arg = true; | |
| 361 break; | |
| 362 } | |
| 363 } | |
| 364 flag_ok = true; | |
| 365 break; | |
| 366 } | |
| 367 } | |
| 368 if (!flag_ok) { | |
| 369 printf("invalid flag '%c'\n", c); | |
| 370 ret = false; | |
| 371 } | |
| 372 } else { | |
| 373 if (def_arg) { | |
| 374 if (def_arg_set) { | |
| 375 printf("%s already set\n", def_descr); | |
| 376 ret = false; | |
| 377 } | |
| 378 switch (def_arg_type) { | |
| 379 case OPTION_ARG_TYPE_NUM: | |
| 380 if (!parse_num(argv[i], (unsigned long *)def_arg, 0, 0)) { | |
| 381 printf("invalid number '%s' for %s\n", argv[i], def_descr); | |
| 382 ret = false; | |
| 383 } | |
| 384 break; | |
| 385 case OPTION_ARG_TYPE_STR: | |
| 386 *def_arg = argv[i]; | |
| 387 break; | |
| 388 } | |
| 389 def_arg_set = true; | |
| 390 } else { | |
| 391 printf("no default/non-flag arguments supported\n"); | |
| 392 ret = false; | |
| 393 } | |
| 394 } | |
| 395 } | |
| 396 return ret; | |
| 397 } | |
| 398 | |
| 399 // | |
| 400 // Parse (scan) a number | |
| 401 // | |
| 402 bool | |
| 403 parse_num(char *s, unsigned long *val, char **es, char *delim) | |
| 404 { | |
| 405 bool first = true; | |
| 406 int radix = 10; | |
| 407 char c; | |
| 408 unsigned long result = 0; | |
| 409 int digit; | |
| 410 | |
| 411 while (*s == ' ') s++; | |
| 412 while (*s) { | |
| 413 if (first && (s[0] == '0') && (tolower(s[1]) == 'x')) { | |
| 414 radix = 16; | |
| 415 s += 2; | |
| 416 } | |
| 417 first = false; | |
| 418 c = *s++; | |
| 419 if (_is_hex(c) && ((digit = _from_hex(c)) < radix)) { | |
| 420 // Valid digit | |
| 421 result = (result * radix) + digit; | |
| 422 } else { | |
| 423 if (delim != (char *)0) { | |
| 424 // See if this character is one of the delimiters | |
| 425 char *dp = delim; | |
| 426 while (*dp && (c != *dp)) dp++; | |
| 427 if (*dp) break; // Found a good delimiter | |
| 428 } | |
| 429 return false; // Malformatted number | |
| 430 } | |
| 431 } | |
| 432 *val = result; | |
| 433 if (es != (char **)0) { | |
| 434 *es = s; | |
| 435 } | |
| 436 return true; | |
| 437 } | |
| 438 | |
| 439 bool | |
| 440 parse_bool(char *s, bool *val) | |
| 441 { | |
| 442 while (*s == ' ') s++; | |
| 443 if ((*s == 't') || (*s == 'T')) { | |
| 444 *val = true; | |
| 445 } else | |
| 446 if ((*s == 'f') || (*s == 'F')) { | |
| 447 *val = false; | |
| 448 } else { | |
| 449 return false; | |
| 450 } | |
| 451 return true; | |
| 452 } | |
| 453 | |
| 454 | 173 |
| 455 void | 174 void |
| 456 do_caches(int argc, char *argv[]) | 175 do_caches(int argc, char *argv[]) |
| 457 { | 176 { |
| 458 unsigned long oldints; | 177 unsigned long oldints; |
| 494 } | 213 } |
| 495 | 214 |
| 496 void | 215 void |
| 497 do_dump(int argc, char *argv[]) | 216 do_dump(int argc, char *argv[]) |
| 498 { | 217 { |
| 218 struct option_info opts[2]; | |
| 499 unsigned long base, len; | 219 unsigned long base, len; |
| 500 | 220 bool base_set, len_set; |
| 501 if (argc < 2) { | 221 |
| 222 init_opts(&opts[0], 'b', true, OPTION_ARG_TYPE_NUM, | |
| 223 (void **)&base, (bool *)&base_set, "base address"); | |
| 224 init_opts(&opts[1], 'l', true, OPTION_ARG_TYPE_NUM, | |
| 225 (void **)&len, (bool *)&len_set, "length"); | |
| 226 if (!scan_opts(argc, argv, 1, opts, 2, 0, 0, "")) | |
| 227 { | |
| 228 return; | |
| 229 } | |
| 230 if (!base_set) { | |
| 502 printf("Dump what [location]?\n"); | 231 printf("Dump what [location]?\n"); |
| 503 return; | 232 return; |
| 504 } | 233 } |
| 505 if (!parse_num(argv[1], &base, 0, 0)) { | 234 if (!len_set) { |
| 506 printf("Invalid start address: %s\n", argv[1]); | |
| 507 return; | |
| 508 } | |
| 509 if (argc > 2) { | |
| 510 if (!parse_num(argv[2], &len, 0, 0)) { | |
| 511 printf("Invalid length/end address: %s\n", argv[2]); | |
| 512 return; | |
| 513 } | |
| 514 } else { | |
| 515 len = 32; | 235 len = 32; |
| 516 } | 236 } |
| 517 dump_buf((void *)base, len); | 237 dump_buf((void *)base, len); |
| 518 } | 238 } |
| 519 | 239 |
