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
132 extern const char bootprog_rev[];
133 extern const char bootprog_name[];
134
135 static void command_help(char *opt);
136 static void command_dump(char *opt);
137 static void command_boot(char *opt);
138 static void command_load(char *opt);
139 static void command_fill(char *opt);
140 static void command_write(char *opt);
141 static void command_option(char *subcmd);
142 static void opt_subcmd_print(char *opt);
143 static void opt_subcmd_read(char *opt);
144 static void opt_subcmd_write(char *opt);
145 static void opt_subcmd_path(char *opt);
146 static void opt_subcmd_bootp(char *opt);
147 static void opt_subcmd_ip(char *opt);
148
149
150 struct boot_option bootopts;
151
152 static 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
164 static 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
174 static void
print_banner(void)175 print_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
184 static void
init_devices(void)185 init_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 */
385 static char *
get_next_arg(char * arg)386 get_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
403 static void
command_help(char * opt)404 command_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
425 static void
bad_param(void)426 bad_param(void)
427 {
428 printf("bad param\n");
429 command_help(NULL);
430 }
431
432 static 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
436 static void
printhexul(u_int32_t n)437 printhexul(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
445 static void
printhexuc(u_int8_t n)446 printhexuc(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
454 static void
command_dump(char * opt)455 command_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
494 static void
command_boot(char * opt)495 command_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 */
511 static int
load_srec(char * offset)512 load_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
623 out:
624 printf("invalid S-Record\n");
625 err = 1;
626
627 out2:
628 do {
629 c = getchar();
630 } while (c != '\r' && c != '\n');
631
632 return err;
633 }
634
635 static void
command_load(char * opt)636 command_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
647 static void
command_fill(char * opt)648 command_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
676 static void
check_write_verify_flash(u_int32_t src,u_int32_t dst,size_t len)677 check_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
709 static void
command_write(char * opt)710 command_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
734 out:
735 bad_param();
736 return;
737 }
738
739 static void
command_option(char * subcmd)740 command_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
760 static void
opt_subcmd_print(char * opt)761 opt_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
776 static void
opt_subcmd_read(char * opt)777 opt_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
784 static void
opt_subcmd_write(char * opt)785 opt_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
793 static void
opt_subcmd_path(char * opt)794 opt_subcmd_path(char *opt)
795 {
796 strlcpy(bootopts.b_pathname, opt, sizeof bootopts.b_pathname);
797 }
798
799 static void
opt_subcmd_bootp(char * opt)800 opt_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
811 static void
opt_subcmd_ip(char * opt)812 opt_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
823 static void
bootmenu(void)824 bootmenu(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
864 static char
awaitkey(void)865 awaitkey(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
885 out:
886 printf("0\n");
887 return(c);
888 }
889
890 __dead void
_rtt(void)891 _rtt(void)
892 {
893 for (;;)
894 ;
895 }
896
897 int
main(void)898 main(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