|
|
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.