xref: /netbsd-src/sys/arch/sandpoint/stand/altboot/main.c (revision b7b7574d3bf8eeb51a1fa3977b59142ec6434a55)
1 /* $NetBSD: main.c,v 1.25 2014/03/26 17:35:08 christos Exp $ */
2 
3 /*-
4  * Copyright (c) 2007 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Tohru Nishimura.
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  *
19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 #include <sys/param.h>
33 #include <sys/reboot.h>
34 
35 #include <lib/libsa/stand.h>
36 #include <lib/libsa/loadfile.h>
37 #include <lib/libkern/libkern.h>
38 
39 #include <machine/bootinfo.h>
40 
41 #include "globals.h"
42 
43 static const struct bootarg {
44 	const char *name;
45 	int value;
46 } bootargs[] = {
47 	{ "multi",	RB_AUTOBOOT },
48 	{ "auto",	RB_AUTOBOOT },
49 	{ "ask",	RB_ASKNAME },
50 	{ "single",	RB_SINGLE },
51 	{ "ddb",	RB_KDB },
52 	{ "userconf",	RB_USERCONF },
53 	{ "norm",	AB_NORMAL },
54 	{ "quiet",	AB_QUIET },
55 	{ "verb",	AB_VERBOSE },
56 	{ "silent",	AB_SILENT },
57 	{ "debug",	AB_DEBUG },
58 	{ "altboot",	-1 }
59 };
60 
61 /* default PATA drive configuration is "10": single master on first channel */
62 static char *drive_config = "10";
63 
64 void *bootinfo; /* low memory reserved to pass bootinfo structures */
65 int bi_size;	/* BOOTINFO_MAXSIZE */
66 char *bi_next;
67 
68 void bi_init(void *);
69 void bi_add(void *, int, int);
70 
71 struct btinfo_memory bi_mem;
72 struct btinfo_console bi_cons;
73 struct btinfo_clock bi_clk;
74 struct btinfo_prodfamily bi_fam;
75 struct btinfo_bootpath bi_path;
76 struct btinfo_rootdevice bi_rdev;
77 struct btinfo_net bi_net;
78 struct btinfo_modulelist *btinfo_modulelist;
79 size_t btinfo_modulelist_size;
80 
81 struct boot_module {
82 	char *bm_kmod;
83 	ssize_t bm_len;
84 	struct boot_module *bm_next;
85 };
86 struct boot_module *boot_modules;
87 char module_base[80];
88 uint32_t kmodloadp;
89 int modules_enabled = 0;
90 
91 void module_add(const char *);
92 void module_load(const char *);
93 int module_open(struct boot_module *);
94 
95 void main(int, char **, char *, char *);
96 
97 extern char bootprog_name[], bootprog_rev[];
98 extern char newaltboot[], newaltboot_end[];
99 
100 struct pcidev lata[2];
101 struct pcidev lnif[2];
102 struct pcidev lusb[3];
103 int nata, nnif, nusb;
104 
105 int brdtype;
106 uint32_t busclock, cpuclock;
107 
108 static int check_bootname(char *);
109 static int input_cmdline(char **, int);
110 static int parse_cmdline(char **, int, char *, char *);
111 static int is_space(char);
112 #ifdef DEBUG
113 static void sat_test(void);
114 static void findflash(void);
115 #endif
116 
117 #define	BNAME_DEFAULT "wd0:"
118 #define MAX_ARGS 10
119 
120 void
121 main(int argc, char *argv[], char *bootargs_start, char *bootargs_end)
122 {
123 	unsigned long marks[MARK_MAX];
124 	struct brdprop *brdprop;
125 	char *new_argv[MAX_ARGS];
126 	char *bname;
127 	ssize_t len;
128 	int err, fd, howto, i, n;
129 
130 	printf("\n>> %s altboot, revision %s\n", bootprog_name, bootprog_rev);
131 
132 	brdprop = brd_lookup(brdtype);
133 	printf(">> %s, cpu %u MHz, bus %u MHz, %dMB SDRAM\n", brdprop->verbose,
134 	    cpuclock / 1000000, busclock / 1000000, bi_mem.memsize >> 20);
135 
136 	nata = pcilookup(PCI_CLASS_IDE, lata, 2);
137 	if (nata == 0)
138 		nata = pcilookup(PCI_CLASS_RAID, lata, 2);
139 	if (nata == 0)
140 		nata = pcilookup(PCI_CLASS_MISCSTORAGE, lata, 2);
141 	if (nata == 0)
142 		nata = pcilookup(PCI_CLASS_SCSI, lata, 2);
143 	nnif = pcilookup(PCI_CLASS_ETH, lnif, 2);
144 	nusb = pcilookup(PCI_CLASS_USB, lusb, 3);
145 
146 #ifdef DEBUG
147 	if (nata == 0)
148 		printf("No IDE/SATA found\n");
149 	else for (n = 0; n < nata; n++) {
150 		int b, d, f, bdf, pvd;
151 		bdf = lata[n].bdf;
152 		pvd = lata[n].pvd;
153 		pcidecomposetag(bdf, &b, &d, &f);
154 		printf("%04x.%04x DSK %02d:%02d:%02d\n",
155 		    PCI_VENDOR(pvd), PCI_PRODUCT(pvd), b, d, f);
156 	}
157 	if (nnif == 0)
158 		printf("no NET found\n");
159 	else for (n = 0; n < nnif; n++) {
160 		int b, d, f, bdf, pvd;
161 		bdf = lnif[n].bdf;
162 		pvd = lnif[n].pvd;
163 		pcidecomposetag(bdf, &b, &d, &f);
164 		printf("%04x.%04x NET %02d:%02d:%02d\n",
165 		    PCI_VENDOR(pvd), PCI_PRODUCT(pvd), b, d, f);
166 	}
167 	if (nusb == 0)
168 		printf("no USB found\n");
169 	else for (n = 0; n < nusb; n++) {
170 		int b, d, f, bdf, pvd;
171 		bdf = lusb[0].bdf;
172 		pvd = lusb[0].pvd;
173 		pcidecomposetag(bdf, &b, &d, &f);
174 		printf("%04x.%04x USB %02d:%02d:%02d\n",
175 		    PCI_VENDOR(pvd), PCI_PRODUCT(pvd), b, d, f);
176 	}
177 #endif
178 
179 	pcisetup();
180 	pcifixup();
181 
182 	/*
183 	 * When argc is too big then it is probably a pointer, which could
184 	 * indicate that we were launched as a Linux kernel module using
185 	 * "bootm".
186 	 */
187 	if (argc > MAX_ARGS) {
188 		if (argv != NULL) {
189 			/*
190 			 * initrd image was loaded:
191 			 * check if it contains a valid altboot command line
192 			 */
193 			char *p = (char *)argv;
194 
195 			if (strncmp(p, "altboot:", 8) == 0) {
196 				*p = 0;
197 				for (p = p + 8; *p >= ' '; p++);
198 				argc = parse_cmdline(new_argv, MAX_ARGS,
199 				    ((char *)argv) + 8, p);
200 				argv = new_argv;
201 			} else
202 				argc = 0;	/* boot default */
203 		} else {
204 			/* parse standard Linux bootargs */
205 			argc = parse_cmdline(new_argv, MAX_ARGS,
206 			    bootargs_start, bootargs_end);
207 			argv = new_argv;
208 		}
209 	}
210 
211 	/* look for a PATA drive configuration string under the arguments */
212 	for (n = 1; n < argc; n++) {
213 		if (strncmp(argv[n], "ide:", 4) == 0 &&
214 		    argv[n][4] >= '0' && argv[n][4] <= '2') {
215 			drive_config = &argv[n][4];
216 			break;
217 		}
218 	}
219 
220 	/* intialize a disk driver */
221 	for (i = 0, n = 0; i < nata; i++)
222 		n += dskdv_init(&lata[i]);
223 	if (n == 0)
224 		printf("IDE/SATA device driver was not found\n");
225 
226 	/* initialize a network interface */
227 	for (n = 0; n < nnif; n++)
228 		if (netif_init(&lnif[n]) != 0)
229 			break;
230 	if (n >= nnif)
231 		printf("no NET device driver was found\n");
232 
233 	/* wait 2s for user to enter interactive mode */
234 	for (n = 200; n >= 0; n--) {
235 		if (n % 100 == 0)
236 			printf("\rHit any key to enter interactive mode: %d",
237 			    n / 100);
238 		if (tstchar()) {
239 #ifdef DEBUG
240 			unsigned c;
241 
242 			c = toupper(getchar());
243 			if (c == 'C') {
244 				/* controller test terminal */
245 				sat_test();
246 				n = 200;
247 				continue;
248 			}
249 			else if (c == 'F') {
250 				/* find strings in Flash ROM */
251 				findflash();
252 				n = 200;
253 				continue;
254 			}
255 #else
256 			(void)getchar();
257 #endif
258 			/* enter command line */
259 			argv = new_argv;
260 			argc = input_cmdline(argv, MAX_ARGS);
261 			break;
262 		}
263 		delay(10000);
264 	}
265 	putchar('\n');
266 
267 	howto = RB_AUTOBOOT;		/* default is autoboot = 0 */
268 
269 	/* get boot options and determine bootname */
270 	for (n = 1; n < argc; n++) {
271 		if (strncmp(argv[n], "ide:", 4) == 0)
272 			continue; /* ignore drive configuration argument */
273 
274 		for (i = 0; i < sizeof(bootargs) / sizeof(bootargs[0]); i++) {
275 			if (strncasecmp(argv[n], bootargs[i].name,
276 			    strlen(bootargs[i].name)) == 0) {
277 				howto |= bootargs[i].value;
278 				break;
279 			}
280 		}
281 		if (i >= sizeof(bootargs) / sizeof(bootargs[0]))
282 			break;	/* break on first unknown string */
283 	}
284 
285 	/*
286 	 * If no device name is given, we construct a list of drives
287 	 * which have valid disklabels.
288 	 */
289 	if (n >= argc) {
290 		static const size_t blen = sizeof("wdN:");
291 		n = 0;
292 		argc = 0;
293 		argv = alloc(MAX_UNITS * (sizeof(char *) + blen));
294 		bname = (char *)(argv + MAX_UNITS);
295 		for (i = 0; i < MAX_UNITS; i++) {
296 			if (!dlabel_valid(i))
297 				continue;
298 			snprintf(bname, blen, "wd%d:", i);
299 			argv[argc++] = bname;
300 			bname += blen;
301 		}
302 		/* use default drive if no valid disklabel is found */
303 		if (argc == 0) {
304 			argc = 1;
305 			argv[0] = BNAME_DEFAULT;
306 		}
307 	}
308 
309 	/* try to boot off kernel from the drive list */
310 	while (n < argc) {
311 		bname = argv[n++];
312 
313 		if (check_bootname(bname) == 0) {
314 			printf("%s not a valid bootname\n", bname);
315 			continue;
316 		}
317 
318 		if ((fd = open(bname, 0)) < 0) {
319 			if (errno == ENOENT)
320 				printf("\"%s\" not found\n", bi_path.bootpath);
321 			continue;
322 		}
323 		printf("loading \"%s\" ", bi_path.bootpath);
324 		marks[MARK_START] = 0;
325 
326 		if (howto == -1) {
327 			/* load another altboot binary and replace ourselves */
328 			len = read(fd, (void *)0x100000, 0x1000000 - 0x100000);
329 			if (len == -1)
330 				goto loadfail;
331 			close(fd);
332 			netif_shutdown_all();
333 
334 			memcpy((void *)0xf0000, newaltboot,
335 			    newaltboot_end - newaltboot);
336 			__syncicache((void *)0xf0000,
337 			    newaltboot_end - newaltboot);
338 			printf("Restarting...\n");
339 			run((void *)1, argv, (void *)0x100000, (void *)len,
340 			    (void *)0xf0000);
341 		}
342 
343 		err = fdloadfile(fd, marks, LOAD_KERNEL);
344 		close(fd);
345 		if (err < 0)
346 			continue;
347 
348 		printf("entry=%p, ssym=%p, esym=%p\n",
349 		    (void *)marks[MARK_ENTRY],
350 		    (void *)marks[MARK_SYM],
351 		    (void *)marks[MARK_END]);
352 
353 		bootinfo = (void *)0x4000;
354 		bi_init(bootinfo);
355 		bi_add(&bi_cons, BTINFO_CONSOLE, sizeof(bi_cons));
356 		bi_add(&bi_mem, BTINFO_MEMORY, sizeof(bi_mem));
357 		bi_add(&bi_clk, BTINFO_CLOCK, sizeof(bi_clk));
358 		bi_add(&bi_path, BTINFO_BOOTPATH, sizeof(bi_path));
359 		bi_add(&bi_rdev, BTINFO_ROOTDEVICE, sizeof(bi_rdev));
360 		bi_add(&bi_fam, BTINFO_PRODFAMILY, sizeof(bi_fam));
361 		if (brdtype == BRD_SYNOLOGY || brdtype == BRD_DLINKDSM) {
362 			/* need to pass this MAC address to kernel */
363 			bi_add(&bi_net, BTINFO_NET, sizeof(bi_net));
364 		}
365 
366 		if (modules_enabled) {
367 			if (fsmod != NULL)
368 				module_add(fsmod);
369 			kmodloadp = marks[MARK_END];
370 			btinfo_modulelist = NULL;
371 			module_load(bname);
372 			if (btinfo_modulelist != NULL &&
373 			    btinfo_modulelist->num > 0)
374 				bi_add(btinfo_modulelist, BTINFO_MODULELIST,
375 				    btinfo_modulelist_size);
376 		}
377 
378 		launchfixup();
379 		netif_shutdown_all();
380 
381 		__syncicache((void *)marks[MARK_ENTRY],
382 		    (u_int)marks[MARK_SYM] - (u_int)marks[MARK_ENTRY]);
383 
384 		run((void *)marks[MARK_SYM], (void *)marks[MARK_END],
385 		    (void *)howto, bootinfo, (void *)marks[MARK_ENTRY]);
386 
387 		/* should never come here */
388 		printf("exec returned. Restarting...\n");
389 		_rtt();
390 	}
391   loadfail:
392 	printf("load failed. Restarting...\n");
393 	_rtt();
394 }
395 
396 void
397 bi_init(void *addr)
398 {
399 	struct btinfo_magic bi_magic;
400 
401 	memset(addr, 0, BOOTINFO_MAXSIZE);
402 	bi_next = (char *)addr;
403 	bi_size = 0;
404 
405 	bi_magic.magic = BOOTINFO_MAGIC;
406 	bi_add(&bi_magic, BTINFO_MAGIC, sizeof(bi_magic));
407 }
408 
409 void
410 bi_add(void *new, int type, int size)
411 {
412 	struct btinfo_common *bi;
413 
414 	if (bi_size + size > BOOTINFO_MAXSIZE)
415 		return;				/* XXX error? */
416 
417 	bi = new;
418 	bi->next = size;
419 	bi->type = type;
420 	memcpy(bi_next, new, size);
421 	bi_next += size;
422 }
423 
424 void
425 module_add(const char *name)
426 {
427 	struct boot_module *bm, *bmp;
428 
429 	while (*name == ' ' || *name == '\t')
430 		++name;
431 
432 	bm = alloc(sizeof(struct boot_module) + strlen(name) + 1);
433 	if (bm == NULL) {
434 		printf("couldn't allocate module %s\n", name);
435 		return;
436 	}
437 
438 	bm->bm_kmod = (char *)(bm + 1);
439 	bm->bm_len = -1;
440 	bm->bm_next = NULL;
441 	strcpy(bm->bm_kmod, name);
442 	if ((bmp = boot_modules) == NULL)
443 		boot_modules = bm;
444 	else {
445 		while (bmp->bm_next != NULL)
446 			bmp = bmp->bm_next;
447 		bmp->bm_next = bm;
448 	}
449 }
450 
451 #define PAGE_SIZE	4096
452 #define alignpg(x)	(((x)+PAGE_SIZE-1) & ~(PAGE_SIZE-1))
453 
454 void
455 module_load(const char *kernel_path)
456 {
457 	struct boot_module *bm;
458 	struct bi_modulelist_entry *bi;
459 	struct stat st;
460 	char *p;
461 	int size, fd;
462 
463 	strcpy(module_base, kernel_path);
464 	if ((p = strchr(module_base, ':')) == NULL)
465 		return; /* eeh?! */
466 	p += 1;
467 	size = sizeof(module_base) - (p - module_base);
468 
469 	if (netbsd_version / 1000000 % 100 == 99) {
470 		/* -current */
471 		snprintf(p, size,
472 		    "/stand/sandpoint/%d.%d.%d/modules",
473 		    netbsd_version / 100000000,
474 		    netbsd_version / 1000000 % 100,
475 		    netbsd_version / 100 % 100);
476 	}
477 	 else if (netbsd_version != 0) {
478 		/* release */
479 		snprintf(p, size,
480 		    "/stand/sandpoint/%d.%d/modules",
481 		    netbsd_version / 100000000,
482 		    netbsd_version / 1000000 % 100);
483 	}
484 
485 	/*
486 	 * 1st pass; determine module existence
487 	 */
488 	size = 0;
489 	for (bm = boot_modules; bm != NULL; bm = bm->bm_next) {
490 		fd = module_open(bm);
491 		if (fd == -1)
492 			continue;
493 		if (fstat(fd, &st) == -1 || st.st_size == -1) {
494 			printf("WARNING: couldn't stat %s\n", bm->bm_kmod);
495 			close(fd);
496 			continue;
497 		}
498 		bm->bm_len = (int)st.st_size;
499 		close(fd);
500 		size += sizeof(struct bi_modulelist_entry);
501 	}
502 	if (size == 0)
503 		return;
504 
505 	size += sizeof(struct btinfo_modulelist);
506 	btinfo_modulelist = alloc(size);
507 	if (btinfo_modulelist == NULL) {
508 		printf("WARNING: couldn't allocate module list\n");
509 		return;
510 	}
511 	btinfo_modulelist_size = size;
512 	btinfo_modulelist->num = 0;
513 
514 	/*
515 	 * 2nd pass; load modules into memory
516 	 */
517 	kmodloadp = alignpg(kmodloadp);
518 	bi = (struct bi_modulelist_entry *)(btinfo_modulelist + 1);
519 	for (bm = boot_modules; bm != NULL; bm = bm->bm_next) {
520 		if (bm->bm_len == -1)
521 			continue; /* already found unavailable */
522 		fd = module_open(bm);
523 		printf("module \"%s\" ", bm->bm_kmod);
524 		size = read(fd, (char *)kmodloadp, SSIZE_MAX);
525 		if (size < bm->bm_len)
526 			printf("WARNING: couldn't load");
527 		else {
528 			snprintf(bi->kmod, sizeof(bi->kmod), bm->bm_kmod);
529 			bi->type = BI_MODULE_ELF;
530 			bi->len = size;
531 			bi->base = kmodloadp;
532 			btinfo_modulelist->num += 1;
533 			printf("loaded at 0x%08x size 0x%x", kmodloadp, size);
534 			kmodloadp += alignpg(size);
535 			bi += 1;
536 		}
537 		printf("\n");
538 		close(fd);
539 	}
540 	btinfo_modulelist->endpa = kmodloadp;
541 }
542 
543 int
544 module_open(struct boot_module *bm)
545 {
546 	char path[80];
547 	int fd;
548 
549 	snprintf(path, sizeof(path),
550 	    "%s/%s/%s.kmod", module_base, bm->bm_kmod, bm->bm_kmod);
551 	fd = open(path, 0);
552 	return fd;
553 }
554 
555 /*
556  * Return the drive configuration for the requested channel 'ch'.
557  * Channel 2 is the first channel of the next IDE controller.
558  * 0: for no drive present on channel
559  * 1: for master drive present on channel, no slave
560  * 2: for master and slave drive present
561  */
562 int
563 get_drive_config(int ch)
564 {
565 	if (drive_config != NULL) {
566 		if (strlen(drive_config) <= ch)
567 			return 0;	/* an unspecified channel is unused */
568 		if (drive_config[ch] >= '0' && drive_config[ch] <= '2')
569 			return drive_config[ch] - '0';
570 	}
571 	return -1;
572 }
573 
574 void *
575 allocaligned(size_t size, size_t align)
576 {
577 	uint32_t p;
578 
579 	if (align-- < 2)
580 		return alloc(size);
581 	p = (uint32_t)alloc(size + align);
582 	return (void *)((p + align) & ~align);
583 }
584 
585 static int hex2nibble(char c)
586 {
587 
588 	if (c >= 'a')
589 		c &= ~0x20;
590 	if (c >= 'A' && c <= 'F')
591 		c -= 'A' - ('9' + 1);
592 	else if (c < '0' || c > '9')
593 		return -1;
594 
595 	return c - '0';
596 }
597 
598 uint32_t
599 read_hex(const char *s)
600 {
601 	int n;
602 	uint32_t val;
603 
604 	val = 0;
605 	while ((n = hex2nibble(*s++)) >= 0)
606 		val = (val << 4) | n;
607 	return val;
608 }
609 
610 static int
611 check_bootname(char *s)
612 {
613 	/*
614 	 * nfs:
615 	 * nfs:<bootfile>
616 	 * tftp:
617 	 * tftp:<bootfile>
618 	 * wd[N[P]]:<bootfile>
619 	 * mem:<address>
620 	 *
621 	 * net is a synonym of nfs.
622 	 */
623 	if (strncmp(s, "nfs:", 4) == 0 || strncmp(s, "net:", 4) == 0 ||
624 	    strncmp(s, "tftp:", 5) == 0 || strncmp(s, "mem:", 4) == 0)
625 		return 1;
626 	if (s[0] == 'w' && s[1] == 'd') {
627 		s += 2;
628 		if (*s != ':' && *s >= '0' && *s <= '3') {
629 			++s;
630 			if (*s != ':' && *s >= 'a' && *s <= 'p')
631 				++s;
632 		}
633 		return *s == ':';
634 	}
635 	return 0;
636 }
637 
638 static int input_cmdline(char **argv, int maxargc)
639 {
640 	char *cmdline;
641 
642 	printf("\nbootargs> ");
643 	cmdline = alloc(256);
644 	gets(cmdline);
645 
646 	return parse_cmdline(argv, maxargc, cmdline,
647 	    cmdline + strlen(cmdline));
648 }
649 
650 static int
651 parse_cmdline(char **argv, int maxargc, char *p, char *end)
652 {
653 	int argc;
654 
655 	argv[0] = "";
656 	for (argc = 1; argc < maxargc && p < end; argc++) {
657 		while (is_space(*p))
658 			p++;
659 		if (p >= end)
660 			break;
661 		argv[argc] = p;
662 		while (!is_space(*p) && p < end)
663 			p++;
664 		*p++ = '\0';
665 	}
666 
667 	return argc;
668 }
669 
670 static int
671 is_space(char c)
672 {
673 
674 	return c > '\0' && c <= ' ';
675 }
676 
677 #ifdef DEBUG
678 static void
679 findflash(void)
680 {
681 	char buf[256];
682 	int i, n;
683 	unsigned char c, *p;
684 
685 	for (;;) {
686 		printf("\nfind> ");
687 		gets(buf);
688 		if (tolower((unsigned)buf[0]) == 'x')
689 			break;
690 		for (i = 0, n = 0, c = 0; buf[i]; i++) {
691 			c <<= 4;
692 			c |= hex2nibble(buf[i]);
693 			if (i & 1)
694 				buf[n++] = c;
695 		}
696 		printf("Searching for:");
697 		for (i = 0; i < n; i++)
698 			printf(" %02x", buf[i]);
699 		printf("\n");
700 		for (p = (unsigned char *)0xff000000;
701 		     p <= (unsigned char *)(0xffffffff-n); p++) {
702 			for (i = 0; i < n; i++) {
703 				if (p[i] != buf[i])
704 					break;
705 			}
706 			if (i >= n)
707 				printf("Found at %08x\n", (unsigned)p);
708 		}
709 	}
710 }
711 
712 static void
713 sat_test(void)
714 {
715 	char buf[1024];
716 	int i, j, n, pos;
717 	unsigned char c;
718 
719 	putchar('\n');
720 	for (;;) {
721 		do {
722 			for (pos = 0; pos < 1024 && sat_tstch() != 0; pos++)
723 				buf[pos] = sat_getch();
724 			if (pos > 1023)
725 				break;
726 			delay(100000);
727 		} while (sat_tstch());
728 
729 		for (i = 0; i < pos; i += 16) {
730 			if ((n = i + 16) > pos)
731 				n = pos;
732 			for (j = 0; j < n; j++)
733 				printf("%02x ", (unsigned)buf[i + j]);
734 			for (; j < 16; j++)
735 				printf("   ");
736 			putchar('\"');
737 			for (j = 0; j < n; j++) {
738 				c = buf[i + j];
739 				putchar((c >= 0x20 && c <= 0x7e) ? c : '.');
740 			}
741 			printf("\"\n");
742 		}
743 
744 		printf("controller> ");
745 		gets(buf);
746 		if (buf[0] == '*' && buf[1] == 'X')
747 			break;
748 
749 		if (buf[0] == '0' && tolower((unsigned)buf[1]) == 'x') {
750 			for (i = 2, n = 0, c = 0; buf[i]; i++) {
751 				c <<= 4;
752 				c |= hex2nibble(buf[i]);
753 				if (i & 1)
754 					buf[n++] = c;
755 			}
756 		} else
757 			n = strlen(buf);
758 
759 		if (n > 0)
760 			sat_write(buf, n);
761 	}
762 }
763 #endif
764