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