xref: /netbsd-src/sys/arch/hpcmips/stand/lcboot/main.c (revision d48f14661dda8638fee055ba15d35bdfb29b9fa8)
1 /* $NetBSD: main.c,v 1.5 2005/12/11 12:17:34 christos 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.5 2005/12/11 12:17:34 christos 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