xref: /netbsd-src/sys/arch/sandpoint/stand/altboot/main.c (revision 62f324d0121177eaf2e0384f92fd9ca2a751c795)
1 /* $NetBSD: main.c,v 1.22 2012/12/25 17:02:35 phx 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(char *);
92 void module_load(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 		n = 0;
291 		argc = 0;
292 		argv = alloc(MAX_UNITS * (sizeof(char *) + sizeof("wdN:")));
293 		bname = (char *)(argv + MAX_UNITS);
294 		for (i = 0; i < MAX_UNITS; i++) {
295 			if (!dlabel_valid(i))
296 				continue;
297 			sprintf(bname, "wd%d:", i);
298 			argv[argc++] = bname;
299 			bname += sizeof("wdN:");
300 		}
301 		/* use default drive if no valid disklabel is found */
302 		if (argc == 0) {
303 			argc = 1;
304 			argv[0] = BNAME_DEFAULT;
305 		}
306 	}
307 
308 	/* try to boot off kernel from the drive list */
309 	while (n < argc) {
310 		bname = argv[n++];
311 
312 		if (check_bootname(bname) == 0) {
313 			printf("%s not a valid bootname\n", bname);
314 			continue;
315 		}
316 
317 		if ((fd = open(bname, 0)) < 0) {
318 			if (errno == ENOENT)
319 				printf("\"%s\" not found\n", bi_path.bootpath);
320 			continue;
321 		}
322 		printf("loading \"%s\" ", bi_path.bootpath);
323 		marks[MARK_START] = 0;
324 
325 		if (howto == -1) {
326 			/* load another altboot binary and replace ourselves */
327 			len = read(fd, (void *)0x100000, 0x1000000 - 0x100000);
328 			if (len == -1)
329 				goto loadfail;
330 			close(fd);
331 			netif_shutdown_all();
332 
333 			memcpy((void *)0xf0000, newaltboot,
334 			    newaltboot_end - newaltboot);
335 			__syncicache((void *)0xf0000,
336 			    newaltboot_end - newaltboot);
337 			printf("Restarting...\n");
338 			run((void *)1, argv, (void *)0x100000, (void *)len,
339 			    (void *)0xf0000);
340 		}
341 
342 		err = fdloadfile(fd, marks, LOAD_KERNEL);
343 		close(fd);
344 		if (err < 0)
345 			continue;
346 
347 		printf("entry=%p, ssym=%p, esym=%p\n",
348 		    (void *)marks[MARK_ENTRY],
349 		    (void *)marks[MARK_SYM],
350 		    (void *)marks[MARK_END]);
351 
352 		bootinfo = (void *)0x4000;
353 		bi_init(bootinfo);
354 		bi_add(&bi_cons, BTINFO_CONSOLE, sizeof(bi_cons));
355 		bi_add(&bi_mem, BTINFO_MEMORY, sizeof(bi_mem));
356 		bi_add(&bi_clk, BTINFO_CLOCK, sizeof(bi_clk));
357 		bi_add(&bi_path, BTINFO_BOOTPATH, sizeof(bi_path));
358 		bi_add(&bi_rdev, BTINFO_ROOTDEVICE, sizeof(bi_rdev));
359 		bi_add(&bi_fam, BTINFO_PRODFAMILY, sizeof(bi_fam));
360 		if (brdtype == BRD_SYNOLOGY || brdtype == BRD_DLINKDSM) {
361 			/* need to pass this MAC address to kernel */
362 			bi_add(&bi_net, BTINFO_NET, sizeof(bi_net));
363 		}
364 
365 		if (modules_enabled) {
366 			if (fsmod != NULL)
367 				module_add(fsmod);
368 			kmodloadp = marks[MARK_END];
369 			btinfo_modulelist = NULL;
370 			module_load(bname);
371 			if (btinfo_modulelist != NULL &&
372 			    btinfo_modulelist->num > 0)
373 				bi_add(btinfo_modulelist, BTINFO_MODULELIST,
374 				    btinfo_modulelist_size);
375 		}
376 
377 		launchfixup();
378 		netif_shutdown_all();
379 
380 		__syncicache((void *)marks[MARK_ENTRY],
381 		    (u_int)marks[MARK_SYM] - (u_int)marks[MARK_ENTRY]);
382 
383 		run((void *)marks[MARK_SYM], (void *)marks[MARK_END],
384 		    (void *)howto, bootinfo, (void *)marks[MARK_ENTRY]);
385 
386 		/* should never come here */
387 		printf("exec returned. Restarting...\n");
388 		_rtt();
389 	}
390   loadfail:
391 	printf("load failed. Restarting...\n");
392 	_rtt();
393 }
394 
395 void
396 bi_init(void *addr)
397 {
398 	struct btinfo_magic bi_magic;
399 
400 	memset(addr, 0, BOOTINFO_MAXSIZE);
401 	bi_next = (char *)addr;
402 	bi_size = 0;
403 
404 	bi_magic.magic = BOOTINFO_MAGIC;
405 	bi_add(&bi_magic, BTINFO_MAGIC, sizeof(bi_magic));
406 }
407 
408 void
409 bi_add(void *new, int type, int size)
410 {
411 	struct btinfo_common *bi;
412 
413 	if (bi_size + size > BOOTINFO_MAXSIZE)
414 		return;				/* XXX error? */
415 
416 	bi = new;
417 	bi->next = size;
418 	bi->type = type;
419 	memcpy(bi_next, new, size);
420 	bi_next += size;
421 }
422 
423 void
424 module_add(char *name)
425 {
426 	struct boot_module *bm, *bmp;
427 
428 	while (*name == ' ' || *name == '\t')
429 		++name;
430 
431 	bm = alloc(sizeof(struct boot_module) + strlen(name) + 1);
432 	if (bm == NULL) {
433 		printf("couldn't allocate module %s\n", name);
434 		return;
435 	}
436 
437 	bm->bm_kmod = (char *)(bm + 1);
438 	bm->bm_len = -1;
439 	bm->bm_next = NULL;
440 	strcpy(bm->bm_kmod, name);
441 	if ((bmp = boot_modules) == NULL)
442 		boot_modules = bm;
443 	else {
444 		while (bmp->bm_next != NULL)
445 			bmp = bmp->bm_next;
446 		bmp->bm_next = bm;
447 	}
448 }
449 
450 #define PAGE_SIZE	4096
451 #define alignpg(x)	(((x)+PAGE_SIZE-1) & ~(PAGE_SIZE-1))
452 
453 void
454 module_load(char *kernel_path)
455 {
456 	struct boot_module *bm;
457 	struct bi_modulelist_entry *bi;
458 	struct stat st;
459 	char *p;
460 	int size, fd;
461 
462 	strcpy(module_base, kernel_path);
463 	if ((p = strchr(module_base, ':')) == NULL)
464 		return; /* eeh?! */
465 	p += 1;
466 	size = sizeof(module_base) - (p - module_base);
467 
468 	if (netbsd_version / 1000000 % 100 == 99) {
469 		/* -current */
470 		snprintf(p, size,
471 		    "/stand/sandpoint/%d.%d.%d/modules",
472 		    netbsd_version / 100000000,
473 		    netbsd_version / 1000000 % 100,
474 		    netbsd_version / 100 % 100);
475 	}
476 	 else if (netbsd_version != 0) {
477 		/* release */
478 		snprintf(p, size,
479 		    "/stand/sandpoint/%d.%d/modules",
480 		    netbsd_version / 100000000,
481 		    netbsd_version / 1000000 % 100);
482 	}
483 
484 	/*
485 	 * 1st pass; determine module existence
486 	 */
487 	size = 0;
488 	for (bm = boot_modules; bm != NULL; bm = bm->bm_next) {
489 		fd = module_open(bm);
490 		if (fd == -1)
491 			continue;
492 		if (fstat(fd, &st) == -1 || st.st_size == -1) {
493 			printf("WARNING: couldn't stat %s\n", bm->bm_kmod);
494 			close(fd);
495 			continue;
496 		}
497 		bm->bm_len = (int)st.st_size;
498 		close(fd);
499 		size += sizeof(struct bi_modulelist_entry);
500 	}
501 	if (size == 0)
502 		return;
503 
504 	size += sizeof(struct btinfo_modulelist);
505 	btinfo_modulelist = alloc(size);
506 	if (btinfo_modulelist == NULL) {
507 		printf("WARNING: couldn't allocate module list\n");
508 		return;
509 	}
510 	btinfo_modulelist_size = size;
511 	btinfo_modulelist->num = 0;
512 
513 	/*
514 	 * 2nd pass; load modules into memory
515 	 */
516 	kmodloadp = alignpg(kmodloadp);
517 	bi = (struct bi_modulelist_entry *)(btinfo_modulelist + 1);
518 	for (bm = boot_modules; bm != NULL; bm = bm->bm_next) {
519 		if (bm->bm_len == -1)
520 			continue; /* already found unavailable */
521 		fd = module_open(bm);
522 		printf("module \"%s\" ", bm->bm_kmod);
523 		size = read(fd, (char *)kmodloadp, SSIZE_MAX);
524 		if (size < bm->bm_len)
525 			printf("WARNING: couldn't load");
526 		else {
527 			snprintf(bi->kmod, sizeof(bi->kmod), bm->bm_kmod);
528 			bi->type = BI_MODULE_ELF;
529 			bi->len = size;
530 			bi->base = kmodloadp;
531 			btinfo_modulelist->num += 1;
532 			printf("loaded at 0x%08x size 0x%x", kmodloadp, size);
533 			kmodloadp += alignpg(size);
534 			bi += 1;
535 		}
536 		printf("\n");
537 		close(fd);
538 	}
539 	btinfo_modulelist->endpa = kmodloadp;
540 }
541 
542 int
543 module_open(struct boot_module *bm)
544 {
545 	char path[80];
546 	int fd;
547 
548 	snprintf(path, sizeof(path),
549 	    "%s/%s/%s.kmod", module_base, bm->bm_kmod, bm->bm_kmod);
550 	fd = open(path, 0);
551 	return fd;
552 }
553 
554 /*
555  * Return the drive configuration for the requested channel 'ch'.
556  * Channel 2 is the first channel of the next IDE controller.
557  * 0: for no drive present on channel
558  * 1: for master drive present on channel, no slave
559  * 2: for master and slave drive present
560  */
561 int
562 get_drive_config(int ch)
563 {
564 	if (drive_config != NULL) {
565 		if (strlen(drive_config) <= ch)
566 			return 0;	/* an unspecified channel is unused */
567 		if (drive_config[ch] >= '0' && drive_config[ch] <= '2')
568 			return drive_config[ch] - '0';
569 	}
570 	return -1;
571 }
572 
573 void *
574 allocaligned(size_t size, size_t align)
575 {
576 	uint32_t p;
577 
578 	if (align-- < 2)
579 		return alloc(size);
580 	p = (uint32_t)alloc(size + align);
581 	return (void *)((p + align) & ~align);
582 }
583 
584 static int hex2nibble(char c)
585 {
586 
587 	if (c >= 'a')
588 		c &= ~0x20;
589 	if (c >= 'A' && c <= 'F')
590 		c -= 'A' - ('9' + 1);
591 	else if (c < '0' || c > '9')
592 		return -1;
593 
594 	return c - '0';
595 }
596 
597 uint32_t
598 read_hex(const char *s)
599 {
600 	int n;
601 	uint32_t val;
602 
603 	val = 0;
604 	while ((n = hex2nibble(*s++)) >= 0)
605 		val = (val << 4) | n;
606 	return val;
607 }
608 
609 static int
610 check_bootname(char *s)
611 {
612 	/*
613 	 * nfs:
614 	 * nfs:<bootfile>
615 	 * tftp:
616 	 * tftp:<bootfile>
617 	 * wd[N[P]]:<bootfile>
618 	 * mem:<address>
619 	 *
620 	 * net is a synonym of nfs.
621 	 */
622 	if (strncmp(s, "nfs:", 4) == 0 || strncmp(s, "net:", 4) == 0 ||
623 	    strncmp(s, "tftp:", 5) == 0 || strncmp(s, "mem:", 4) == 0)
624 		return 1;
625 	if (s[0] == 'w' && s[1] == 'd') {
626 		s += 2;
627 		if (*s != ':' && *s >= '0' && *s <= '3') {
628 			++s;
629 			if (*s != ':' && *s >= 'a' && *s <= 'p')
630 				++s;
631 		}
632 		return *s == ':';
633 	}
634 	return 0;
635 }
636 
637 static int input_cmdline(char **argv, int maxargc)
638 {
639 	char *cmdline;
640 
641 	printf("\nbootargs> ");
642 	cmdline = alloc(256);
643 	gets(cmdline);
644 
645 	return parse_cmdline(argv, maxargc, cmdline,
646 	    cmdline + strlen(cmdline));
647 }
648 
649 static int
650 parse_cmdline(char **argv, int maxargc, char *p, char *end)
651 {
652 	int argc;
653 
654 	argv[0] = "";
655 	for (argc = 1; argc < maxargc && p < end; argc++) {
656 		while (is_space(*p))
657 			p++;
658 		if (p >= end)
659 			break;
660 		argv[argc] = p;
661 		while (!is_space(*p) && p < end)
662 			p++;
663 		*p++ = '\0';
664 	}
665 
666 	return argc;
667 }
668 
669 static int
670 is_space(char c)
671 {
672 
673 	return c > '\0' && c <= ' ';
674 }
675 
676 #ifdef DEBUG
677 static void
678 findflash(void)
679 {
680 	char buf[256];
681 	int i, n;
682 	unsigned char c, *p;
683 
684 	for (;;) {
685 		printf("\nfind> ");
686 		gets(buf);
687 		if (tolower((unsigned)buf[0]) == 'x')
688 			break;
689 		for (i = 0, n = 0, c = 0; buf[i]; i++) {
690 			c <<= 4;
691 			c |= hex2nibble(buf[i]);
692 			if (i & 1)
693 				buf[n++] = c;
694 		}
695 		printf("Searching for:");
696 		for (i = 0; i < n; i++)
697 			printf(" %02x", buf[i]);
698 		printf("\n");
699 		for (p = (unsigned char *)0xff000000;
700 		     p <= (unsigned char *)(0xffffffff-n); p++) {
701 			for (i = 0; i < n; i++) {
702 				if (p[i] != buf[i])
703 					break;
704 			}
705 			if (i >= n)
706 				printf("Found at %08x\n", (unsigned)p);
707 		}
708 	}
709 }
710 
711 static void
712 sat_test(void)
713 {
714 	char buf[1024];
715 	int i, j, n, pos;
716 	unsigned char c;
717 
718 	putchar('\n');
719 	for (;;) {
720 		do {
721 			for (pos = 0; pos < 1024 && sat_tstch() != 0; pos++)
722 				buf[pos] = sat_getch();
723 			if (pos > 1023)
724 				break;
725 			delay(100000);
726 		} while (sat_tstch());
727 
728 		for (i = 0; i < pos; i += 16) {
729 			if ((n = i + 16) > pos)
730 				n = pos;
731 			for (j = 0; j < n; j++)
732 				printf("%02x ", (unsigned)buf[i + j]);
733 			for (; j < 16; j++)
734 				printf("   ");
735 			putchar('\"');
736 			for (j = 0; j < n; j++) {
737 				c = buf[i + j];
738 				putchar((c >= 0x20 && c <= 0x7e) ? c : '.');
739 			}
740 			printf("\"\n");
741 		}
742 
743 		printf("controller> ");
744 		gets(buf);
745 		if (buf[0] == '*' && buf[1] == 'X')
746 			break;
747 
748 		if (buf[0] == '0' && tolower((unsigned)buf[1]) == 'x') {
749 			for (i = 2, n = 0, c = 0; buf[i]; i++) {
750 				c <<= 4;
751 				c |= hex2nibble(buf[i]);
752 				if (i & 1)
753 					buf[n++] = c;
754 			}
755 		} else
756 			n = strlen(buf);
757 
758 		if (n > 0)
759 			sat_write(buf, n);
760 	}
761 }
762 #endif
763