Home | History | Annotate | Line # | Download | only in lcboot
main.c revision 1.3
      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