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