|
|
1.1 ! root 1: /* netboot ! 2: * ! 3: * main.c,v ! 4: * Revision 1.2 1993/07/09 15:24:12 brezak ! 5: * Cleanup warnings and add netbsd kernel name suffix. ! 6: * ! 7: * Revision 1.1 1993/07/08 16:04:02 brezak ! 8: * Diskless boot prom code from Jim McKim ([email protected]) ! 9: * ! 10: * Revision 1.4 1993/06/30 20:14:13 mckim ! 11: * Added BOOTP support. ! 12: * ! 13: * Revision 1.3 1993/06/08 14:27:08 mckim ! 14: * Reboot options (argv[1]) passed to kernel. ! 15: * ! 16: * Revision 1.2 1993/05/28 20:01:27 mckim ! 17: * Fixed various StartProg() problems. ! 18: * ! 19: * Revision 1.1.1.1 1993/05/28 11:41:07 mckim ! 20: * Initial version. ! 21: * ! 22: * ! 23: * source code in this file is from: ! 24: * 386BSD boot blocks by Julian Elischer ([email protected]) ! 25: * 386BSD Adaptec 1542 SCSI boot blocks by Pace Willisson ([email protected]) ! 26: * ! 27: * Mach Operating System ! 28: * Copyright (c) 1992, 1991 Carnegie Mellon University ! 29: * All Rights Reserved. ! 30: * ! 31: * Permission to use, copy, modify and distribute this software and its ! 32: * documentation is hereby granted, provided that both the copyright ! 33: * notice and this permission notice appear in all copies of the ! 34: * software, derivative works or modified versions, and any portions ! 35: * thereof, and that both notices appear in supporting documentation. ! 36: * ! 37: * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" ! 38: * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR ! 39: * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. ! 40: * ! 41: * Carnegie Mellon requests users of this software to return to ! 42: * ! 43: * Software Distribution Coordinator or [email protected] ! 44: * School of Computer Science ! 45: * Carnegie Mellon University ! 46: * Pittsburgh PA 15213-3890 ! 47: * ! 48: * any improvements or extensions that they make and grant Carnegie Mellon ! 49: * the rights to redistribute these changes. ! 50: */ ! 51: ! 52: /* ! 53: Copyright 1988, 1989, 1990, 1991, 1992 ! 54: by Intel Corporation, Santa Clara, California. ! 55: ! 56: All Rights Reserved ! 57: ! 58: Permission to use, copy, modify, and distribute this software and ! 59: its documentation for any purpose and without fee is hereby ! 60: granted, provided that the above copyright notice appears in all ! 61: copies and that both the copyright notice and this permission notice ! 62: appear in supporting documentation, and that the name of Intel ! 63: not be used in advertising or publicity pertaining to distribution ! 64: of the software without specific, written prior permission. ! 65: ! 66: INTEL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE ! 67: INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, ! 68: IN NO EVENT SHALL INTEL BE LIABLE FOR ANY SPECIAL, INDIRECT, OR ! 69: CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM ! 70: LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT, ! 71: NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION ! 72: WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ! 73: */ ! 74: ! 75: ! 76: #include "config.h" ! 77: #include "nbtypes.h" ! 78: #include "assert.h" ! 79: #include "param.h" ! 80: #include "packet.h" ! 81: #include "ether.h" ! 82: #include "inet.h" ! 83: #include "arp.h" ! 84: #include "tftp.h" ! 85: ! 86: #include "proto.h" ! 87: ! 88: u_long work_area_org = RELOC; ! 89: u_long kernel_size; ! 90: u_short real_cs; ! 91: u_long howto = 0; ! 92: u_char vendor_area[64]; ! 93: ! 94: enum LoadErr { ! 95: load_success, ! 96: load_no_answer, ! 97: load_bad_format, ! 98: load_bad_size, ! 99: }; ! 100: ! 101: static inline enum LoadErr ! 102: LoadProgFromServer(ipaddr_t server, ipaddr_t gateway, char *file_name) { ! 103: /* TBD - fail (or at least warn) if we don't get the entire file */ ! 104: u_long start_addr; ! 105: u_long boot_area_org; ! 106: u_long tmp_reloc_org; ! 107: u_long kern_copy_org; ! 108: u_long kern_copy_p; ! 109: struct exec head; ! 110: u_long boot_argv[4]; ! 111: #if 1 /* ndef USE_BUFFER */ ! 112: u_char tmpbuf[4096]; /* we need to load the first 4k here */ ! 113: #endif ! 114: ! 115: SetTftpParms(server, gateway, file_name); ! 116: ! 117: /* TBD - heuristics about what we are loading - load linux, ... also */ ! 118: ! 119: if (Read(&head, sizeof(head)) != sizeof(head)) ! 120: return load_bad_size; ! 121: ! 122: if (head.a_magic != 0413 ) { ! 123: printf("Invalid format!\n"); ! 124: return load_bad_format; ! 125: } ! 126: ! 127: /* Load/tftp the executable to a temporary area beyond 640k - after ! 128: successful load, copy to correct area. If load fails or is interrrupted, ! 129: we can recover gracefully ! 130: */ ! 131: ! 132: start_addr = (u_long)head.a_entry; ! 133: boot_area_org = start_addr & 0x00f00000; /* some MEG boundary */ ! 134: tmp_reloc_org = 0x00100000; ! 135: #ifdef USE_BUFFER ! 136: kern_copy_org = tmp_reloc_org + WORK_AREA_SIZE; /* leave free for relocation */ ! 137: #else ! 138: kern_copy_org = boot_area_org; /* leave free for relocation */ ! 139: #endif ! 140: kern_copy_p = kern_copy_org; ! 141: kernel_size = head.a_text + head.a_data + head.a_bss; ! 142: ! 143: printf("Loading "); ! 144: IpPrintAddr(server); ! 145: printf(":%s @ 0x%x\n", file_name, boot_area_org); ! 146: #ifndef USE_BUFFER ! 147: if(boot_area_org < work_area_org) { ! 148: if((boot_area_org + head.a_text + head.a_data) > work_area_org) { ! 149: printf("kernel will not fit below loader\n"); ! 150: return load_bad_size; ! 151: } ! 152: if((boot_area_org + head.a_text + head.a_data + head.a_bss) > 0xa0000) { ! 153: printf("kernel too big, won't fit in 640K with bss\n"); ! 154: printf("Only hope is to link the kernel for > 1MB\n"); ! 155: return load_bad_size; ! 156: } ! 157: if(boot_area_org + kernel_size > work_area_org) { ! 158: printf("loader overlaps bss, kernel must bzero\n"); ! 159: } ! 160: } ! 161: #else ! 162: if(boot_area_org + kernel_size > 0xa0000) { ! 163: printf("kernel too big, won't fit in 640K with bss\n"); ! 164: printf("Only hope is to link the kernel for > 1MB\n"); ! 165: return load_bad_size; ! 166: } ! 167: /* check if too large for tmp buffer (TBD) */ ! 168: #endif ! 169: printf("text=0x%x", head.a_text); ! 170: ! 171: #if 01 ! 172: /* skip to first 4k boundry */ ! 173: Read(tmpbuf, 4096-sizeof(head)); ! 174: #endif ! 175: ! 176: #if 0 /* ndef USE_BUFFER */ ! 177: /********************************************************/ ! 178: /* LOAD THE TEXT SEGMENT */ ! 179: /* don't clobber the first 4k yet (BIOS NEEDS IT) */ ! 180: /********************************************************/ ! 181: Read(tmpbuf, sizeof(tmpbuf)); ! 182: kern_copy_p += sizeof(tmpbuf); ! 183: PhysRead(kern_copy_p, head.a_text - sizeof(tmpbuf)); ! 184: kern_copy_p += head.a_text - sizeof(tmpbuf); ! 185: #else ! 186: /********************************************************/ ! 187: /* LOAD THE TEXT SEGMENT */ ! 188: /********************************************************/ ! 189: PhysRead(kern_copy_p, head.a_text); ! 190: kern_copy_p += head.a_text; ! 191: #endif ! 192: ! 193: /********************************************************/ ! 194: /* Load the Initialised data after the text */ ! 195: /********************************************************/ ! 196: /* TBD - this is bogus - file system oriented */ ! 197: #define CLSIZE 1 ! 198: #define NBPG 4096 /* bytes/page */ ! 199: #define CLOFSET (CLSIZE*NBPG-1) /* for clusters, like PGOFSET */ ! 200: ! 201: while (kern_copy_p & CLOFSET) ! 202: *(char *)kern_copy_p++ = 0; ! 203: ! 204: printf(" data=0x%x", head.a_data); ! 205: PhysRead(kern_copy_p, head.a_data); ! 206: kern_copy_p += head.a_data; ! 207: ! 208: /********************************************************/ ! 209: /* Skip over the uninitialised data */ ! 210: /* (but clear it) */ ! 211: /********************************************************/ ! 212: printf(" bss=0x%x", head.a_bss); ! 213: if (kern_copy_p < RELOC && ! 214: (kern_copy_p + head.a_bss) > RELOC) { ! 215: PhysBzero(kern_copy_p, RELOC-(u_int)kern_copy_p); ! 216: } else { ! 217: PhysBzero(kern_copy_p, head.a_bss); ! 218: } ! 219: ! 220: #ifdef LOADSYMS /* not yet, haven't worked this out yet */ ! 221: if (kern_copy_p > 0x100000) { ! 222: /********************************************************/ ! 223: /*copy in the symbol header */ ! 224: /********************************************************/ ! 225: PhysBcopy(&head.a_syms, kern_copy_p, sizeof(head.a_syms)); ! 226: kern_copy_p += sizeof(head.a_syms); ! 227: ! 228: /********************************************************/ ! 229: /* READ in the symbol table */ ! 230: /********************************************************/ ! 231: printf(" symbols=[+0x%x", head.a_syms); ! 232: Read(kern_copy_p, head.a_syms); ! 233: kern_copy_p += head.a_syms; ! 234: ! 235: /********************************************************/ ! 236: /* Followed by the next integer (another header) */ ! 237: /* more debug symbols? */ ! 238: /********************************************************/ ! 239: read(&i, sizeof(u_int)); ! 240: PhysBcopy(&i, kern_copy_p, sizeof(u_int)); ! 241: i -= sizeof(u_int); ! 242: kern_copy_p += sizeof(u_int); ! 243: ! 244: /********************************************************/ ! 245: /* and that many bytes of (debug symbols?) */ ! 246: /********************************************************/ ! 247: printf("+0x%x]", i); ! 248: Read(kern_copy_p, i); ! 249: kern_copy_p += i; ! 250: } ! 251: #endif LOADSYMS ! 252: ! 253: /********************************************************/ ! 254: /* and note the end address of all this */ ! 255: /********************************************************/ ! 256: ! 257: printf(" total=0x%x",kern_copy_p - kern_copy_org); ! 258: ! 259: boot_argv[0] = 0; ! 260: boot_argv[1] = howto; ! 261: boot_argv[2] = 0; ! 262: boot_argv[3] = 0; ! 263: ! 264: /* TBD - place vendor_area on stack */ ! 265: ! 266: printf(" entry point=0x%x\n" ,((u_int)start_addr) & 0xffffff); ! 267: ! 268: if (howto) { ! 269: static char *rb_option_name[9] = { ! 270: "askname", ! 271: "single", ! 272: "nosync", ! 273: "halt", ! 274: "initname", ! 275: "dfltroot", ! 276: "kdb", ! 277: "rdonly", ! 278: "dump", ! 279: }; ! 280: int i; ! 281: printf("Starting kernel with options (0x%x): ", howto); ! 282: for (i=0; i<9; i++) { ! 283: if (howto & (1<<i)) { ! 284: printf("%s ", rb_option_name[i]); ! 285: } ! 286: } ! 287: printf("\n"); ! 288: } ! 289: ! 290: #if 0 /* ndef USE_BUFFER */ ! 291: PhysBcopy(tmpbuf, boot_area_org, sizeof(tmpbuf)); ! 292: #endif ! 293: ! 294: StartProg(start_addr & 0xffffff, boot_argv); ! 295: ! 296: return load_success; /* hah! */ ! 297: } ! 298: ! 299: int GetHex(int old) { ! 300: int r, c, ch; ! 301: r = 0; ! 302: ch = 0; ! 303: while((c=getchar()) != '\n') { ! 304: ch = 1; ! 305: if (c>='0' && c<='9') ! 306: r = r*16 + (c-'0'); ! 307: else if (c>='a' && c<='f') ! 308: r = r*16 + (c+10-'a'); ! 309: } ! 310: if (ch) ! 311: return r; ! 312: else ! 313: return old; ! 314: } ! 315: ! 316: static char ! 317: ToHex(int n) { ! 318: n &= 0x0F; ! 319: return n >= 10 ? n - 10 + 'A' : n + '0'; ! 320: } ! 321: ! 322: static char name_set[][9] = { ! 323: "xxxxxxxx", ! 324: "default", ! 325: }; ! 326: ! 327: static char *ext_set[] = { ! 328: ".netbsd", ! 329: ".netbsd.old", ! 330: ".386bsd", ! 331: ".386bsd.old", ! 332: ".vmunix", ! 333: ".vmunix.old", ! 334: }; ! 335: ! 336: static ipaddr_t server_set[2] = { ! 337: 0, ! 338: IP_BCASTADDR, ! 339: }; ! 340: ! 341: static inline void ! 342: TryToLoadSomething(void) { ! 343: int nserver; ! 344: for (nserver=0; nserver<nelt(server_set); nserver++) { ! 345: int nname; ! 346: char file_name[MAX_FILE_NAME_LEN+1]; ! 347: file_name[0] = '\0'; ! 348: if (GetIpAddress(&server_set[nserver], &ip_myaddr, &ip_gateway, file_name)) { ! 349: if (*file_name) { ! 350: LoadProgFromServer(server_set[nserver], ip_gateway, file_name); ! 351: } ! 352: else { ! 353: /* no file name supplied from server, synthesize one */ ! 354: inetaddr_t ip; ! 355: ip.a = ip_myaddr; ! 356: name_set[0][0] = ToHex(ip.s.a0 >> 4); ! 357: name_set[0][1] = ToHex(ip.s.a0); ! 358: name_set[0][2] = ToHex(ip.s.a1 >> 4); ! 359: name_set[0][3] = ToHex(ip.s.a1); ! 360: name_set[0][4] = ToHex(ip.s.a2 >> 4); ! 361: name_set[0][5] = ToHex(ip.s.a2); ! 362: name_set[0][6] = ToHex(ip.s.a3 >> 4); ! 363: name_set[0][7] = ToHex(ip.s.a3); ! 364: name_set[0][8] = 0; ! 365: for (nname=0; nname<nelt(name_set); nname++) { ! 366: int next; ! 367: for (next=0; next<nelt(ext_set); next++) { ! 368: strncpy(file_name, name_set[nname], MAX_FILE_NAME_LEN); ! 369: strncat(file_name, ext_set[next], MAX_FILE_NAME_LEN-strlen(file_name)); ! 370: LoadProgFromServer(server_set[nserver], ip_gateway, file_name); ! 371: } ! 372: } ! 373: } ! 374: } ! 375: } ! 376: } ! 377: ! 378: ! 379: static char * ! 380: DecimalToByte(char *s, u_char *n) { ! 381: for (*n = 0; *s >= '0' && *s <= '9'; s++) ! 382: *n = (*n * 10) + *s - '0'; ! 383: return s; ! 384: } ! 385: ! 386: static ipaddr_t ! 387: IpConvertAddr(char *p) { ! 388: inetaddr_t addr; ! 389: ! 390: if (p == (char *)0 || *p == '\0') ! 391: return IP_ANYADDR; ! 392: p = DecimalToByte(p, &addr.s.a0); ! 393: if (*p == '\0' || *p++ != '.') ! 394: return IP_ANYADDR; ! 395: p = DecimalToByte(p, &addr.s.a1); ! 396: if (*p == '\0' || *p++ != '.') ! 397: return IP_ANYADDR; ! 398: p = DecimalToByte(p, &addr.s.a2); ! 399: if (*p == '\0' || *p++ != '.') ! 400: return IP_ANYADDR; ! 401: p = DecimalToByte(p, &addr.s.a3); ! 402: if (*p != '\0') ! 403: return IP_ANYADDR; ! 404: return addr.a; ! 405: } ! 406: ! 407: static int ! 408: GetLine(char **argv, int argvsize) { ! 409: char *p, ch; ! 410: static char line[128]; ! 411: int argc; ! 412: ! 413: /* ! 414: * Read command line, implement some simple editing features ! 415: */ ! 416: p = line; ! 417: while ((ch = getchar()) != '\r' && ch != '\n' && (p-line) < sizeof(line)) { ! 418: if (ch == '\b') { ! 419: if (p > line) { ! 420: p--; ! 421: printf(" \b"); ! 422: } ! 423: } else ! 424: *p++ = ch; ! 425: } ! 426: *p = '\0'; ! 427: ! 428: /* ! 429: * Break command line up into an argument vector ! 430: */ ! 431: argc = 0; ! 432: for (p = line; *p == ' ' || *p == '\t'; p++) ! 433: /* skip white spaces */; ! 434: while (*p != ' ' && *p != '\t' && *p != '\n' && *p != '\0') { ! 435: if (argc > argvsize) break; ! 436: argv[(argc)++] = p; ! 437: for (; *p != ' ' && *p != '\t' && *p != '\n' && *p != '\0'; p++) ! 438: /* skip word */; ! 439: if (*p != '\0') *p++ ='\0'; ! 440: for (; *p == ' ' || *p == '\t'; p++) ! 441: /* skip white spaces */; ! 442: } ! 443: argv[(argc)] = (char *)0; ! 444: return argc; ! 445: } ! 446: ! 447: enum cmd_token_type { ! 448: CMD_GO, ! 449: CMD_HELP, ! 450: CMD_RESET, ! 451: CMD_AUTO, ! 452: CMD_WHO, ! 453: CMD_REBOOT, ! 454: CMD_DISKBOOT, ! 455: CMD_ADDRESS, ! 456: CMD_GATEWAY, ! 457: CMD_TFTP, ! 458: CMD_DEBUG, ! 459: CMD_SINGLE, ! 460: CMD_FILE, ! 461: CMD_SERVER, ! 462: }; ! 463: ! 464: struct commands { ! 465: enum cmd_token_type cmd_token; ! 466: char *cmd_name; ! 467: char *cmd_help; ! 468: } commands[] = { ! 469: {CMD_GO, "go", " start loaded binary"}, ! 470: {CMD_HELP, "help", " this help message"}, ! 471: {CMD_RESET, "reset", " reset ethernet board"}, ! 472: {CMD_AUTO, "auto", " continue with auto boot"}, ! 473: {CMD_WHO, "whoami", " get IP address"}, ! 474: {CMD_REBOOT, "reboot", " hard reboot"}, ! 475: {CMD_DISKBOOT, "diskboot", " soft reboot (from disk)"}, ! 476: {CMD_ADDRESS, "address", "[<addr>] set IP address"}, ! 477: {CMD_GATEWAY, "gateway", "[<addr>] set IP gateway"}, ! 478: {CMD_SERVER, "server", "[<addr>] set server IP address"}, ! 479: {CMD_FILE, "file", "[<name>] set boot file name"}, ! 480: {CMD_TFTP, "tftp", " TFTP download"}, ! 481: {CMD_DEBUG, "debug", " enter kernel debugger at boot"}, ! 482: {CMD_SINGLE, "single", " enter single user at boot"}, ! 483: }; ! 484: ! 485: #define ARGVECSIZE 100 ! 486: ! 487: /* ! 488: * A very simple and terse monitor ! 489: */ ! 490: static void ! 491: Monitor(void) { ! 492: char *argv[ARGVECSIZE]; ! 493: static char file_name[MAX_FILE_NAME_LEN+1] = "default.bsd386"; ! 494: int loaded, argc; ! 495: int i; ! 496: int token; ! 497: static ipaddr_t ip_servaddr = IP_ANYADDR; ! 498: ! 499: loaded = 0; ! 500: printf("\n" ! 501: #ifdef USE_BOOTP ! 502: "BOOTP/" ! 503: #endif ! 504: #ifdef USE_RARP ! 505: "RARP/" ! 506: #endif ! 507: "TFTP monitor mode\n"); ! 508: for (;;) { ! 509: char filename[MAX_FILE_NAME_LEN+1]; ! 510: ipaddr_t gateway; ! 511: printf("ethernet boot monitor: "); ! 512: if ((argc = GetLine(argv, ARGVECSIZE)) > 0) { ! 513: ! 514: for (token = -1, i = 0; i < nelt(commands); i++) { ! 515: if (strcmp(argv[0], commands[i].cmd_name) == 0) { ! 516: token = commands[i].cmd_token; ! 517: break; ! 518: } ! 519: } ! 520: switch (token) { ! 521: case CMD_HELP: ! 522: for (i = 0; i < nelt(commands); i++) ! 523: printf("%s %s\n", commands[i].cmd_name, commands[i].cmd_help); ! 524: break; ! 525: case CMD_RESET: ! 526: PktInit(); ! 527: EtherReset(); ! 528: break; ! 529: case CMD_REBOOT: ! 530: EtherStop(); ! 531: ResetCpu(); ! 532: break; ! 533: case CMD_DISKBOOT: ! 534: EtherStop(); ! 535: exit(0); ! 536: break; ! 537: case CMD_AUTO: ! 538: return; ! 539: case CMD_WHO: ! 540: (void) GetIpAddress(&ip_servaddr, &ip_myaddr, &gateway, filename); ! 541: break; ! 542: case CMD_ADDRESS: ! 543: if (argc != 2) { ! 544: printf("My IP address is "); ! 545: IpPrintAddr(ip_myaddr); ! 546: printf("\n"); ! 547: } else ! 548: ip_myaddr = IpConvertAddr(argv[1]); ! 549: break; ! 550: case CMD_SERVER: ! 551: if (argc != 2) { ! 552: printf("Server's IP address is "); ! 553: IpPrintAddr(ip_servaddr); ! 554: printf("\n"); ! 555: } else ! 556: ip_servaddr = IpConvertAddr(argv[1]); ! 557: break; ! 558: case CMD_FILE: ! 559: if (argc != 2) { ! 560: printf("File name is \"%s\"\n", file_name); ! 561: } else ! 562: strncpy(file_name, argv[1], MAX_FILE_NAME_LEN); ! 563: break; ! 564: case CMD_GATEWAY: ! 565: if (argc != 2) { ! 566: printf("Gateway IP address is "); ! 567: IpPrintAddr(ip_gateway); ! 568: printf("\n"); ! 569: } else ! 570: ip_gateway = IpConvertAddr(argv[1]); ! 571: break; ! 572: case CMD_DEBUG: ! 573: howto ^= RB_KDB; ! 574: break; ! 575: case CMD_SINGLE: ! 576: howto ^= RB_SINGLE; ! 577: break; ! 578: case CMD_TFTP: ! 579: if (ip_myaddr == IP_ANYADDR) { ! 580: printf("This machine's IP address must be set first.\n"); ! 581: goto complain; ! 582: } ! 583: loaded = LoadProgFromServer(ip_servaddr, ip_gateway, file_name); ! 584: printf("File could not be loaded, giving up.\n"); ! 585: break; ! 586: default: ! 587: goto complain; ! 588: } ! 589: } else ! 590: complain: ! 591: printf("Invalid or incorrect command. Type \"help\" for help.\n"); ! 592: } ! 593: } ! 594: ! 595: static jmp_buf jmp_env; ! 596: ! 597: void ! 598: HandleKbdAttn(void) { ! 599: if (IsKbdCharReady()) ! 600: if (getc() == 0x1b) { ! 601: EtherReset(); ! 602: PktInit(); ! 603: longjmp(jmp_env, 1); ! 604: } ! 605: } ! 606: ! 607: int time_zero; ! 608: ! 609: void ! 610: main(void) { ! 611: ! 612: extern char edata[], end[]; ! 613: char volatile * volatile p; ! 614: ! 615: /* clear bss */ ! 616: for (p = edata; p < end; p++) ! 617: *p = 0; ! 618: ! 619: printf( ! 620: #ifdef USE_BOOTP ! 621: "BOOTP/" ! 622: #endif ! 623: #ifdef USE_RARP ! 624: "RARP/" ! 625: #endif ! 626: "TFTP bootstrap loader @0x%x: %d/%d k of memory. ^] for attn.\n", ! 627: work_area_org, ! 628: GetMemSize(0), ! 629: GetMemSize(1)); ! 630: ! 631: gateA20(); ! 632: ! 633: PktInit(); ! 634: if (!EtherInit()) { ! 635: printf("No ethernet board found\n"); ! 636: exit(1); ! 637: } ! 638: srand((time_zero=timer()) ^ eth_myaddr[5]); ! 639: ! 640: printf("Ethernet address is "); ! 641: EtherPrintAddr(eth_myaddr); ! 642: printf("\n"); ! 643: ! 644: for (;;) { ! 645: if (setjmp(jmp_env)) ! 646: Monitor(); ! 647: else { ! 648: TryToLoadSomething(); ! 649: } ! 650: } ! 651: } ! 652: ! 653: #ifdef __GNUC__ ! 654: void ! 655: __main(void) { ! 656: } ! 657: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.