1/* $NetBSD: main.c,v 1.7 2016/06/11 06:29:24 dholland Exp $ */ 2 3/* 4 * Copyright (c) 2003 Naoto Shimazaki. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY NAOTO SHIMAZAKI AND CONTRIBUTORS ``AS IS'' 17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 18 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE NAOTO OR CONTRIBUTORS BE 20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 26 * THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29/* 30 * Boot loader for L-Card+ 31 * 32 * ROM Map 33 * ------- 34 * ROM1 35 * BFFF FFFF ------------------------------ 36 * 37 * reserved 38 * 39 * BF80 0000 ------------------------------ 40 * 41 * ROM0 42 * BFFF FFFF ------------------------------ 43 * 44 * user storage (max 2Mbytes) 45 * 46 * BFE0 0000 ------------------------------ 47 * 48 * reserved 49 * 50 * BFD4 0000 ------------------------------ 51 * 52 * boot params 53 * 54 * BFD2 0000 ------------------------------ 55 * 56 * second boot loader (mirror image) 57 * or Linux Kernel 58 * 59 * BFD0 0000 ------------------------------ 60 * 61 * first boot loader (L-Card+ original loader) 62 * 63 * reset vector 64 * BFC0 0000 ------------------------------ 65 * 66 * gziped kernel image (max 4Mbytes) 67 * 68 * BF80 0000 ------------------------------ 69 * 70 * 71 * 72 * RAM Map 73 * ------- 74 * 75 * 80FF FFFF ------------------------------ 76 * ROM ICE work 77 * 80FF FE00 ------------------------------ 78 * ROM ICE stack 79 * 80FF FDA8 ------------------------------ 80 * 81 * 82 * 83 * kernel 84 * 8004 0000 ------------------------------ 85 * kernel stack (growing to lower) 86 * 87 * 88 * boot loader heap (growing to upper) 89 * boot loader text & data (at exec time) 90 * 8000 1000 ------------------------------ 91 * vector table 92 * 8000 0000 ------------------------------ 93 * 94 * virtual memory space 95 * 96 * 0000 0000 ------------------------------ 97 * 98 * 99 * 100 * ROMCS0 <-> ROMCS3 mapping 101 * 102 * ROMCS0 ROMCS3 103 * BE7F FFFF <-> BFFF FFFF 104 * BE40 0000 <-> BFC0 0000 reset vector 105 * BE00 0000 <-> BF80 0000 106 * 107 * 108 */ 109#include <sys/cdefs.h> 110__KERNEL_RCSID(0, "$NetBSD: main.c,v 1.7 2016/06/11 06:29:24 dholland Exp $"); 111 112#include <lib/libsa/stand.h> 113 114#include <lib/libsa/loadfile.h> 115#include <lib/libkern/libkern.h> 116 117#include <hpcmips/vr/vripreg.h> 118#include <hpcmips/vr/cmureg.h> 119#include <hpcmips/vr/vr4181giureg.h> 120 121#include "extern.h" 122#include "i28f128reg.h" 123 124/* XXX */ 125#define ISABRGCTL 0x00 126#define ISABRGSTS 0x02 127#define XISACTL 0x04 128 129#define BOOTTIMEOUT 9 /* must less than 10 */ 130#define LINEBUFLEN 80 131 132extern const char bootprog_rev[]; 133extern const char bootprog_name[]; 134 135static void command_help(char *opt); 136static void command_dump(char *opt); 137static void command_boot(char *opt); 138static void command_load(char *opt); 139static void command_fill(char *opt); 140static void command_write(char *opt); 141static void command_option(char *subcmd); 142static void opt_subcmd_print(char *opt); 143static void opt_subcmd_read(char *opt); 144static void opt_subcmd_write(char *opt); 145static void opt_subcmd_path(char *opt); 146static void opt_subcmd_bootp(char *opt); 147static void opt_subcmd_ip(char *opt); 148 149 150struct boot_option bootopts; 151 152static struct bootmenu_command commands[] = { 153 { "?", command_help }, 154 { "h", command_help }, 155 { "d", command_dump }, 156 { "b", command_boot }, 157 { "l", command_load }, 158 { "f", command_fill }, 159 { "w", command_write }, 160 { "o", command_option }, 161 { NULL, NULL }, 162}; 163 164static struct bootmenu_command opt_subcommands[] = { 165 { "p", opt_subcmd_print }, 166 { "r", opt_subcmd_read }, 167 { "w", opt_subcmd_write }, 168 { "path", opt_subcmd_path }, 169 { "bootp", opt_subcmd_bootp }, 170 { "ip", opt_subcmd_ip }, 171 { NULL, NULL }, 172}; 173 174static void 175print_banner(void) 176{ 177 printf("\n"); 178 printf(">> %s, Revision %s\n", bootprog_name, bootprog_rev); 179#if 0 180 printf(">> Memory: %d/%d k\n", getbasemem(), getextmem()); 181#endif 182} 183 184static void 185init_devices(void) 186{ 187 /* Init RTC */ 188 REGWRITE_2(VRETIMEH, 0, 0); 189 REGWRITE_2(VRETIMEM, 0, 0); 190 REGWRITE_2(VRETIMEL, 0, 0); 191 192 193 /* 194 * CLKSPEEDREG 0x6012 195 * DIV DIV2 mode 196 * CLKSP 18 (0x12) 197 * PClock (CPU clock) 65.536MHz 198 * PClock = (18.432MHz / CLKSP) x 64 199 * = (18.432MHz / 18) x 64 200 * = 65.536MHz 201 * TClock (peripheral clock) 32.768MHz 202 * TClock = PClock / DIV 203 * = 65.536MHz / 2 204 * = 32.768MHz 205 */ 206 207 /* 208 * setup ISA BUS clock freqency 209 * 210 * set PCLK (internal peripheral clock) to 32.768MHz (TClock / 1) 211 * set External ISA bus clock to 10.922MHz (TClock / 3) 212 */ 213 REGWRITE_2(VR4181_ISABRG_ADDR, ISABRGCTL, 0x0003); 214 REGWRITE_2(VR4181_ISABRG_ADDR, XISACTL, 0x0401); 215 216 /* 217 * setup peripheral's clock supply 218 * 219 * CSU: disable 220 * AIU: enable (AIU, ADU, ADU18M) 221 * PIU: disable 222 * SIU: enable (SIU18M) 223 */ 224 REGWRITE_2(VR4181_CMU_ADDR, 0, CMUMASK_SIU | CMUMASK_AIU); 225 226 /* 227 * setup GPIO 228 */ 229#if 0 230 /* L-Card+ generic setup */ 231 /* 232 * pin mode comment 233 * GP0 : GPI not used 234 * GP1 : GPI not used 235 * GP2 : GPO LED6 (0: on 1: off) 236 * GP3 : PCS0 chip select for CS8900A Lan controller 237 * GP4 : GPI IRQ input from CS8900A 238 * GP5 : GPI not used 239 * GP6 : GPI not used 240 * GP7 : GPI reserved by TANBAC TB0193 241 */ 242 REGWRITE_2(VR4181_GIU81_ADDR, VR4181GIU_PIOD_L_REG_W, 0xffff); 243 REGWRITE_2(VR4181_GIU81_ADDR, VR4181GIU_MODE0_REG_W, 244 GP3_PCS0 | GP2_GPO); 245 /* 246 * pin mode comment 247 * GP8 : GPO LED5 (0: on 1: off) 248 * GP9 : GPI CD2 249 * GP10: GPI CD1 250 * GP11: GPI not used 251 * GP12: GPI not used 252 * GP13: GPI not used 253 * GP14: GPI not used 254 * GP15: GPI not used 255 */ 256 REGWRITE_2(VR4181_GIU81_ADDR, VR4181GIU_MODE1_REG_W, GP8_GPO); 257 /* 258 * pin mode comment 259 * GP16: IORD ISA bus 260 * GP17: IOWR ISA bus 261 * GP18: IORDY ISA bus 262 * GP19: GPI not used 263 * GP20: GPI not used 264 * GP21: RESET resets CS8900A 265 * GP22: ROMCS0 ROM chip select 266 * GP23: ROMCS1 ROM chip select 267 */ 268 REGWRITE_2(VR4181_GIU81_ADDR, VR4181GIU_MODE2_REG_W, 269 GP23_ROMCS1 | GP22_ROMCS0 | GP21_RESET 270 | GP18_IORDY | GP17_IOWR | GP16_IORD); 271 /* 272 * GP24: ROMCS2 ROM chip select 273 * GP25: RxD1 SIU1 274 * GP26: TxD1 SIU1 275 * GP27: RTS1 SIU1 276 * GP28: CTS1 SIU1 277 * GP29: GPI LED3 278 * GP30: GPI reserved by TANBAC TB0193 279 * GP31: GPI LED4 280 */ 281 REGWRITE_2(VR4181_GIU81_ADDR, VR4181GIU_MODE3_REG_W, 282 GP30_GPI 283 | GP28_CTS1 | GP27_RTS1 | GP26_TxD1 | GP25_RxD1 284 | GP24_ROMCS2); 285#else 286 /* e-care node specific setup */ 287 /* 288 * pin mode comment 289 * GP0 : GPO ECNRTC_RST 290 * GP1 : GPO ECNRTC_CLK 291 * GP2 : GPO LED6 (0: on 1: off) 292 * GP3 : PCS0 chip select for CS8900A Lan controller 293 * GP4 : GPI IRQ input from CS8900A 294 * GP5 : GPO ECNRTC_DIR 295 * GP6 : GPO ECNRTC_OUT 296 * GP7 : GPI reserved by TANBAC TB0193 297 */ 298 REGWRITE_2(VR4181_GIU81_ADDR, VR4181GIU_PIOD_L_REG_W, 0xffff); 299 REGWRITE_2(VR4181_GIU81_ADDR, VR4181GIU_MODE0_REG_W, 300 GP6_GPO | GP5_GPO | GP3_PCS0 301 | GP2_GPO | GP1_GPO | GP0_GPO); 302 303 /* 304 * pin mode comment 305 * GP8 : GPO LED5 (0: on 1: off) 306 * GP9 : GPI CD2 307 * GP10: GPI CD1 308 * GP11: GPI not used 309 * GP12: GPI ECNRTC_IN 310 * GP13: GPI not used 311 * GP14: GPI not used 312 * GP15: GPI not used 313 */ 314 REGWRITE_2(VR4181_GIU81_ADDR, VR4181GIU_MODE1_REG_W, 315 GP12_GPI | GP8_GPO); 316 317 /* 318 * pin mode comment 319 * GP16: IORD ISA bus 320 * GP17: IOWR ISA bus 321 * GP18: IORDY ISA bus 322 * GP19: GPI not used 323 * GP20: GPI not used 324 * GP21: RESET resets CS8900A 325 * GP22: ROMCS0 ROM chip select 326 * GP23: ROMCS1 ROM chip select 327 */ 328 REGWRITE_2(VR4181_GIU81_ADDR, VR4181GIU_MODE2_REG_W, 329 GP23_ROMCS1 | GP22_ROMCS0 | GP21_RESET 330 | GP18_IORDY | GP17_IOWR | GP16_IORD); 331 /* 332 * GP24: ROMCS2 ROM chip select 333 * GP25: RxD1 SIU1 334 * GP26: TxD1 SIU1 335 * GP27: RTS1 SIU1 336 * GP28: CTS1 SIU1 337 * GP29: GPI LED3 338 * GP30: GPI reserved by TANBAC TB0193 339 * GP31: GPI LED4 340 */ 341 REGWRITE_2(VR4181_GIU81_ADDR, VR4181GIU_MODE3_REG_W, 342 GP30_GPI 343 | GP28_CTS1 | GP27_RTS1 | GP26_TxD1 | GP25_RxD1 344 | GP24_ROMCS2); 345#endif 346 347#if 0 348 /* 349 * setup interrupt 350 * 351 * I4TYP: falling edge trigger 352 * GIMSK4: unmask 353 * GIEN4: enable 354 * other: unused, mask, disable 355 */ 356 REGWRITE_2(VR4181_GIU81_ADDR, VR4181GIU_INTTYP_L_REG_W, 357 I4TYP_HIGH_LEVEL); 358 REGWRITE_2(VR4181_GIU81_ADDR, VR4181GIU_INTMASK_REG_W, 359 0xffffU & ~GIMSK4); 360 REGWRITE_2(VR4181_GIU81_ADDR, VR4181GIU_INTEN_REG_W, GIEN4); 361#endif 362 363 /* 364 * programmable chip select 365 * 366 * PCS0 is used to select CS8900A Ethernet controller 367 * on TB0193 368 * 369 * PCS0: 370 * 0x14010000 - 0x14010fff 371 * I/O access, 16bit cycle, both of read/write 372 * PCS1: unused 373 */ 374 REGWRITE_2(VR4181_GIU81_ADDR, VR4181GIU_PCS0STRA_REG_W, 0x0000); 375 REGWRITE_2(VR4181_GIU81_ADDR, VR4181GIU_PCS0STPA_REG_W, 0x0fff); 376 REGWRITE_2(VR4181_GIU81_ADDR, VR4181GIU_PCS0HIA_REG_W, 0x1401); 377 REGWRITE_2(VR4181_GIU81_ADDR, VR4181GIU_PCSMODE_REG_W, 378 PCS0MIOB_IO | PCS0DSIZE_16BIT | PCS0MD_READWRITE); 379} 380 381/* 382 * chops the head from the arguments and returns the arguments if any, 383 * or possibly an empty string. 384 */ 385static char * 386get_next_arg(char *arg) 387{ 388 char *opt; 389 390 if ((opt = strchr(arg, ' ')) == NULL) { 391 opt = ""; 392 } else { 393 *opt++ = '\0'; 394 } 395 396 /* trim leading blanks */ 397 while (*opt == ' ') 398 opt++; 399 400 return opt; 401} 402 403static void 404command_help(char *opt) 405{ 406 printf("commands are:\n" 407 "boot:\tb\n" 408 "dump:\td addr [addr]\n" 409 "fill:\tf addr addr char\n" 410 "load:\tl [offset] (with following S-Record)\n" 411 "write:\tw dst src len\n" 412 "option:\to subcommand [params]\n" 413 "help:\th|?\n" 414 "\n" 415 "option subcommands are:\n" 416 "print:\to p\n" 417 "read:\to r\n" 418 "write:\to w\n" 419 "path:\to path pathname\n" 420 "bootp:\to bootp yes|no\n" 421 "ip:\to ip remote local netmask gateway\n" 422 ); 423} 424 425static void 426bad_param(void) 427{ 428 printf("bad param\n"); 429 command_help(NULL); 430} 431 432static const u_int8_t print_cnv[] = { 433 '0', '1', '2', '3', '4', '5', '6', '7', 434 '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; 435 436static void 437printhexul(u_int32_t n) 438{ 439 int i; 440 441 for (i = 28; i >= 0; i -= 4) 442 putchar(print_cnv[(n >> i) & 0x0f]); 443} 444 445static void 446printhexuc(u_int8_t n) 447{ 448 int i; 449 450 for (i = 4; i >= 0; i -= 4) 451 putchar(print_cnv[(n >> i) & 0x0f]); 452} 453 454static void 455command_dump(char *opt) 456{ 457 char *endptr; 458 const char *p; 459 const char *line_fence; 460 const char *limit; 461 462 p = (const char *) strtoul(opt, &endptr, 16); 463 if (opt == endptr) { 464 bad_param(); 465 return; 466 } 467 468 opt = get_next_arg(opt); 469 limit = (const char *) strtoul(opt, &endptr, 16); 470 if (opt == endptr) { 471 limit = p + 256; 472 } 473 474 for (;;) { 475 printhexul((u_int32_t) p); 476 putchar(' '); 477 line_fence = p + 16; 478 while (p < line_fence) { 479 printhexuc(*p++); 480 putchar(' '); 481 if (p >= limit) { 482 putchar('\n'); 483 return; 484 } 485 } 486 putchar('\n'); 487 if (ISKEY) { 488 if (getchar() == '\x03') 489 break; 490 } 491 } 492} 493 494static void 495command_boot(char *opt) 496{ 497 u_long marks[MARK_MAX]; 498 499 marks[MARK_START] = 0; 500 if (loadfile(bootopts.b_pathname, marks, LOAD_KERNEL)) { 501 printf("loadfile failed\n"); 502 return; 503 } 504 start_netbsd(); 505 /* no return */ 506} 507 508/* 509 * loading S-Record 510 */ 511static int 512load_srec(char *offset) 513{ 514 char s2lbuf[9]; 515 char c; 516 char rectype; 517 u_int32_t reclen; 518 u_int32_t reclen_bk; 519 u_int32_t recaddr; 520 char *endptr; 521 char *p; 522 u_int32_t sum; 523 int err = 0; 524 525 for (;;) { 526 /* 527 * the first step is to read a S-Record. 528 */ 529 if ((c = getchar()) != 'S') 530 goto out; 531 532 rectype = getchar(); 533 534 s2lbuf[0] = getchar(); 535 s2lbuf[1] = getchar(); 536 s2lbuf[2] = '\0'; 537 reclen_bk = reclen = strtoul(s2lbuf, &endptr, 16); 538 if (endptr != &s2lbuf[2]) 539 goto out; 540 sum = reclen; 541 542 p = s2lbuf; 543 544 switch (rectype) { 545 case '0': 546 /* just ignore */ 547 do { 548 c = getchar(); 549 } while (c != '\r' && c != '\n'); 550 continue; 551 552 case '3': 553 *p++ = getchar(); 554 *p++ = getchar(); 555 reclen--; 556 /* FALLTHRU */ 557 case '2': 558 *p++ = getchar(); 559 *p++ = getchar(); 560 reclen--; 561 /* FALLTHRU */ 562 case '1': 563 *p++ = getchar(); 564 *p++ = getchar(); 565 *p++ = getchar(); 566 *p++ = getchar(); 567 *p = '\0'; 568 reclen -= 2; 569 570 recaddr = strtoul(s2lbuf, &endptr, 16); 571 if (endptr != p) 572 goto out; 573 sum += (recaddr >> 24) & 0xff; 574 sum += (recaddr >> 16) & 0xff; 575 sum += (recaddr >> 8) & 0xff; 576 sum += recaddr & 0xff; 577 578 p = offset + recaddr; 579 /* 580 * XXX 581 * address range is must be chaked here! 582 */ 583 reclen--; 584 s2lbuf[2] = '\0'; 585 while (reclen > 0) { 586 s2lbuf[0] = getchar(); 587 s2lbuf[1] = getchar(); 588 *p = (u_int8_t) strtoul(s2lbuf, &endptr, 16); 589 if (endptr != &s2lbuf[2]) 590 goto out; 591 sum += *p++; 592 reclen--; 593 } 594 break; 595 596 case '7': 597 case '8': 598 case '9': 599 goto out2; 600 601 default: 602 goto out; 603 } 604 605 s2lbuf[0] = getchar(); 606 s2lbuf[1] = getchar(); 607 s2lbuf[2] = '\0'; 608 sum += (strtoul(s2lbuf, &endptr, 16) & 0xff); 609 sum &= 0xff; 610 if (sum != 0xff) { 611 printf("checksum error\n"); 612 err = 1; 613 goto out2; 614 } 615 616 c = getchar(); 617 if (c != '\r' && c != '\n') 618 goto out; 619 } 620 /* never reach */ 621 return 1; 622 623out: 624 printf("invalid S-Record\n"); 625 err = 1; 626 627out2: 628 do { 629 c = getchar(); 630 } while (c != '\r' && c != '\n'); 631 632 return err; 633} 634 635static void 636command_load(char *opt) 637{ 638 char *endptr; 639 char *offset; 640 641 offset = (char *) strtoul(opt, &endptr, 16); 642 if (opt == endptr) 643 offset = 0; 644 load_srec(offset); 645} 646 647static void 648command_fill(char *opt) 649{ 650 char *endptr; 651 char *p; 652 char *limit; 653 int c; 654 655 p = (char *) strtoul(opt, &endptr, 16); 656 if (opt == endptr) { 657 bad_param(); 658 return; 659 } 660 661 opt = get_next_arg(opt); 662 limit = (char *) strtoul(opt, &endptr, 16); 663 if (opt == endptr) { 664 bad_param(); 665 return; 666 } 667 668 opt = get_next_arg(opt); 669 c = strtoul(opt, &endptr, 16); 670 if (opt == endptr) 671 c = '\0'; 672 673 memset(p, c, limit - p); 674} 675 676static void 677check_write_verify_flash(u_int32_t src, u_int32_t dst, size_t len) 678{ 679 int status; 680 681 if ((dst & I28F128_BLOCK_MASK) != 0) { 682 printf("dst addr must be aligned to block boundary (0x%x)\n", 683 I28F128_BLOCK_SIZE); 684 return; 685 } 686 687 if (i28f128_probe((void *) dst)) { 688 printf("dst addr is not a intel 28F128\n"); 689 } else { 690 printf("intel 28F128 detected\n"); 691 } 692 693 if ((status = i28f128_region_write((void *) dst, (void *) src, len)) 694 != 0) { 695 printf("write mem to flash failed status = %x\n", status); 696 return; 697 } 698 699 printf("verifying..."); 700 if (memcmp((void *) dst, (void *) src, len)) { 701 printf("verify error\n"); 702 return; 703 } 704 printf("ok\n"); 705 706 printf("writing memory to flash succeeded\n"); 707} 708 709static void 710command_write(char *opt) 711{ 712 char *endptr; 713 u_int32_t src; 714 u_int32_t dst; 715 size_t len; 716 717 dst = strtoul(opt, &endptr, 16); 718 if (opt == endptr) 719 goto out; 720 721 opt = get_next_arg(opt); 722 src = strtoul(opt, &endptr, 16); 723 if (opt == endptr) 724 goto out; 725 726 opt = get_next_arg(opt); 727 len = strtoul(opt, &endptr, 16); 728 if (opt == endptr) 729 goto out; 730 731 check_write_verify_flash(src, dst, len); 732 return; 733 734out: 735 bad_param(); 736 return; 737} 738 739static void 740command_option(char *subcmd) 741{ 742 char *opt; 743 int i; 744 745 opt = get_next_arg(subcmd); 746 747 /* dispatch subcommand */ 748 for (i = 0; opt_subcommands[i].c_name != NULL; i++) { 749 if (strcmp(subcmd, opt_subcommands[i].c_name) == 0) { 750 opt_subcommands[i].c_fn(opt); 751 break; 752 } 753 } 754 if (opt_subcommands[i].c_name == NULL) { 755 printf("unknown option subcommand\n"); 756 command_help(NULL); 757 } 758} 759 760static void 761opt_subcmd_print(char *opt) 762{ 763 printf("boot options:\n" 764 "magic:\t\t%s\n" 765 "pathname:\t`%s'\n" 766 "bootp:\t\t%s\n", 767 bootopts.b_magic == BOOTOPT_MAGIC ? "ok" : "bad", 768 bootopts.b_pathname, 769 bootopts.b_flags & B_F_USE_BOOTP ? "yes" : "no"); 770 printf("remote IP:\t%s\n", inet_ntoa(bootopts.b_remote_ip)); 771 printf("local IP:\t%s\n", inet_ntoa(bootopts.b_local_ip)); 772 printf("netmask:\t%s\n", intoa(bootopts.b_netmask)); 773 printf("gateway IP:\t%s\n", inet_ntoa(bootopts.b_gate_ip)); 774} 775 776static void 777opt_subcmd_read(char *opt) 778{ 779 bootopts = *((struct boot_option *) BOOTOPTS_BASE); 780 if (bootopts.b_magic != BOOTOPT_MAGIC) 781 bootopts.b_pathname[0] = '\0'; 782} 783 784static void 785opt_subcmd_write(char *opt) 786{ 787 bootopts.b_magic = BOOTOPT_MAGIC; 788 789 check_write_verify_flash((u_int32_t) &bootopts, BOOTOPTS_BASE, 790 sizeof bootopts); 791} 792 793static void 794opt_subcmd_path(char *opt) 795{ 796 strlcpy(bootopts.b_pathname, opt, sizeof bootopts.b_pathname); 797} 798 799static void 800opt_subcmd_bootp(char *opt) 801{ 802 if (strcmp(opt, "yes") == 0) { 803 bootopts.b_flags |= B_F_USE_BOOTP; 804 } else if (strcmp(opt, "no") == 0) { 805 bootopts.b_flags &= ~B_F_USE_BOOTP; 806 } else { 807 bad_param(); 808 } 809} 810 811static void 812opt_subcmd_ip(char *opt) 813{ 814 bootopts.b_remote_ip.s_addr = inet_addr(opt); 815 opt = get_next_arg(opt); 816 bootopts.b_local_ip.s_addr = inet_addr(opt); 817 opt = get_next_arg(opt); 818 bootopts.b_netmask = inet_addr(opt); 819 opt = get_next_arg(opt); 820 bootopts.b_gate_ip.s_addr = inet_addr(opt); 821} 822 823static void 824bootmenu(void) 825{ 826 char input[LINEBUFLEN]; 827 char *cmd; 828 char *opt; 829 int i; 830 831 for (;;) { 832 833 /* input a line */ 834 input[0] = '\0'; 835 printf("> "); 836 kgets(input, sizeof(input)); 837 cmd = input; 838 839 /* skip leading whitespace. */ 840 while(*cmd == ' ') 841 cmd++; 842 843 if(*cmd) { 844 /* here, some command entered */ 845 846 opt = get_next_arg(cmd); 847 848 /* dispatch command */ 849 for (i = 0; commands[i].c_name != NULL; i++) { 850 if (strcmp(cmd, commands[i].c_name) == 0) { 851 commands[i].c_fn(opt); 852 break; 853 } 854 } 855 if (commands[i].c_name == NULL) { 856 printf("unknown command\n"); 857 command_help(NULL); 858 } 859 } 860 861 } 862} 863 864static char 865awaitkey(void) 866{ 867 int i; 868 int j; 869 char c = 0; 870 871 while (ISKEY) 872 getchar(); 873 874 for (i = BOOTTIMEOUT; i > 0; i--) { 875 printf("%d\b", i); 876 for (j = 0; j < 1000000; j++) { 877 if (ISKEY) { 878 while (ISKEY) 879 c = getchar(); 880 goto out; 881 } 882 } 883 } 884 885out: 886 printf("0\n"); 887 return(c); 888} 889 890__dead void 891_rtt(void) 892{ 893 for (;;) 894 ; 895} 896 897int 898main(void) 899{ 900 char c; 901 902 init_devices(); 903 904 comcninit(); 905 906 opt_subcmd_read(NULL); 907 908 print_banner(); 909 910 c = awaitkey(); 911 if (c != '\r' && c != '\n' && c != '\0') { 912 printf("type \"?\" or \"h\" for help.\n"); 913 bootmenu(); /* does not return */ 914 } 915 916 command_boot(NULL); 917 /* 918 * command_boot() returns only if it failed to boot. 919 * we enter to boot menu in this case. 920 */ 921 bootmenu(); 922 923 return 0; 924} 925