Home | History | Annotate | Line # | Download | only in lcboot
      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
    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
    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 *
    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
    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
    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(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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    794 opt_subcmd_path(char *opt)
    795 {
    796 	strlcpy(bootopts.b_pathname, opt, sizeof bootopts.b_pathname);
    797 }
    798 
    799 static void
    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
    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
    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
    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
    891 _rtt(void)
    892 {
    893 	for (;;)
    894 		;
    895 }
    896 
    897 int
    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