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