Removed some tlbflush optimizations as some of them were bogus and lead
[unix-history] / sys / i386 / netboot / main.c
CommitLineData
db4d0741
MR
1/**************************************************************************
2NETBOOT - BOOTP/TFTP Bootstrap Program
3
4Author: Martin Renters
5 Date: Dec/93
6
7**************************************************************************/
8
9#include "netboot.h"
10
11#define ESC 0x1b /* ESC Key */
12
13int jmp_bootmenu[10];
14struct exec head;
15int txtoff;
16void (*kernelentry)();
17char *loadpoint;
18char *bootfile;
19char bootname[128];
20char cfg[32];
21char broadcast[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
22struct nfs_diskless nfsdiskless;
23extern char packet[];
24extern int packetlen;
25char *putdec();
26
27/**************************************************************************
28MAIN - Kick off routine
29**************************************************************************/
30main()
31{
32 int c;
33 char *p;
34 extern char edata[], end[];
35 for (p=edata; p<end; p++) *p = 0; /* Zero BSS */
36#ifdef ASK_BOOT
37 while (1) {
38 printf("\n\rBoot from Network (Y/N) ? ");
39 c = getchar();
40 if ((c >= 'a') && (c <= 'z')) c &= 0x5F;
41 if (c == '\r') break;
42 putchar(c);
43 if (c == 'N')
44 exit(0);
45 if (c == 'Y')
46 break;
47 printf(" - bad response\n\r");
48 }
49#endif
50 gateA20();
51 printf("\r\nBOOTP/TFTP bootstrap loader ESC for menu\n\r");
52 printf("\r\nSearching for adapter...");
53 if (!eth_probe()) {
54 printf("No adapter found.\r\n");
55 exit(0);
56 }
57 bootfile = DEFAULT_BOOTFILE;
58 while (1) {
59 if (setjmp(jmp_bootmenu))
60 bootmenu();
61 else
62 load();
63 }
64}
65
66/**************************************************************************
67LOAD - Try to get booted
68**************************************************************************/
69load()
70{
71 char *p;
72 if (!arptable[ARP_CLIENT].ipaddr || !arptable[ARP_SERVER].ipaddr) {
73 printf("\r\nSearching for server...\r\n");
74 if (!bootp()) {
75 printf("No Server found.\r\n");
76 longjmp(jmp_bootmenu,1);
77 }
78 }
db4d0741
MR
79 printf("station IP %I, server IP %I\r\n",
80 arptable[ARP_CLIENT].ipaddr,
81 arptable[ARP_SERVER].ipaddr);
82 p = cfg;
83 *(p++) = 'c';
84 *(p++) = 'f';
85 *(p++) = 'g';
86 *(p++) = '.';
87 p = putdec(p, arptable[ARP_CLIENT].ipaddr>>24);
88 *(p++) = '.';
89 p = putdec(p, arptable[ARP_CLIENT].ipaddr>>16);
90 *(p++) = '.';
91 p = putdec(p, arptable[ARP_CLIENT].ipaddr>>8);
92 *(p++) = '.';
93 p = putdec(p, arptable[ARP_CLIENT].ipaddr);
94 *p = 0;
95 printf("Loading %s...\r\n",cfg);
96 if (!tftp(cfg, TFTP_CODE_CFG)) {
97 printf("Unable to load config file.\r\n");
98 longjmp(jmp_bootmenu,1);
99 }
100 printf("Loading %s...\r\n",bootfile);
101 if (!tftp(bootfile, TFTP_CODE_BOOT)) {
102 printf("Unable to load boot file.\r\n");
103 longjmp(jmp_bootmenu,1);
104 }
105 if (!(head.a_entry & 0x00F00000)) { /* < 1MB kernel? */
106 printf("<1MB kernel. Relocating\r\n");
107 bcopy(0x100000, 0, 0x400); /* Relocate */
108 bcopy(0x100500, 0x500, ((int)loadpoint) - 0x100500);
109 }
110 kernelentry = (void *)(head.a_entry & 0x00FFFFFF);
111 (*kernelentry)(0,0,0,0,&nfsdiskless,0,0,0);
112}
113
114/**************************************************************************
115POLLKBD - Check for Interrupt from keyboard
116**************************************************************************/
117pollkbd()
118{
119 if (iskey() && (getchar() == ESC)) longjmp(jmp_bootmenu,1);
120}
121
122/**************************************************************************
123UDP_TRANSMIT - Send a UDP datagram
124**************************************************************************/
125udp_transmit(destip, srcsock, destsock, len, buf)
126 unsigned long destip;
127 unsigned short srcsock, destsock;
128 int len;
129 char *buf;
130{
131 struct iphdr *ip;
132 struct udphdr *udp;
133 struct arprequest arpreq, *arpreply;
134 int arpentry, i;
135 unsigned long time;
136 int retry = MAX_ARP_RETRIES;
137 ip = (struct iphdr *)buf;
138 udp = (struct udphdr *)(buf + sizeof(struct iphdr));
139 ip->verhdrlen = 0x45;
140 ip->service = 0;
141 ip->len = htons(len);
142 ip->ident = 0;
143 ip->frags = 0;
144 ip->ttl = 60;
145 ip->protocol = IP_UDP;
146 ip->chksum = 0;
147 convert_ipaddr(ip->src, &arptable[ARP_CLIENT].ipaddr);
148 convert_ipaddr(ip->dest, &destip);
149 ip->chksum = ipchksum(buf, sizeof(struct iphdr));
150 udp->src = htons(srcsock);
151 udp->dest = htons(destsock);
152 udp->len = htons(len - sizeof(struct iphdr));
153 udp->chksum = 0;
154 if (destip == IP_BROADCAST) {
155 eth_transmit(broadcast, IP, len, buf);
156 } else {
157 for(arpentry = 0; arpentry<MAX_ARP; arpentry++)
158 if (arptable[arpentry].ipaddr == destip) break;
159 if (arpentry == MAX_ARP) {
160 printf("%I is not in my arp table!\n");
161 return(0);
162 }
163 for (i = 0; i<ETHER_ADDR_SIZE; i++)
164 if (arptable[arpentry].node[i]) break;
165 if (i == ETHER_ADDR_SIZE) { /* Need to do arp request */
166 arpreq.hwtype = htons(1);
167 arpreq.protocol = htons(IP);
168 arpreq.hwlen = ETHER_ADDR_SIZE;
169 arpreq.protolen = 4;
170 arpreq.opcode = htons(ARP_REQUEST);
171 bcopy(arptable[ARP_CLIENT].node, arpreq.shwaddr, ETHER_ADDR_SIZE);
172 convert_ipaddr(arpreq.sipaddr, &arptable[ARP_CLIENT].ipaddr);
173 bzero(arpreq.thwaddr, ETHER_ADDR_SIZE);
174 convert_ipaddr(arpreq.tipaddr, &destip);
175 while (retry--) {
176 eth_transmit(broadcast, ARP, sizeof(arpreq), &arpreq);
177 time = currticks() + TIMEOUT;
178 while (time > currticks()) {
179 pollkbd();
180 if (eth_poll() && (packetlen >= ETHER_HDR_SIZE + sizeof(arpreq)) &&
181 (((packet[12] << 8) | packet[13]) == ARP)) {
182 arpreply = (struct arprequest *)&packet[ETHER_HDR_SIZE];
183 if ((arpreply->opcode == ntohs(ARP_REPLY)) &&
184 bcompare(arpreply->sipaddr,arpreq.tipaddr, 4)) {
185 bcopy(arpreply->shwaddr, arptable[arpentry].node,ETHER_ADDR_SIZE);
186 goto xmit;
187 }
188 }
189 }
190 }
191 return(0);
192 }
193xmit: eth_transmit(arptable[arpentry].node, IP, len, buf);
194 }
195 return(1);
196}
197
198/**************************************************************************
199TFTP - Try to load something
200**************************************************************************/
201tftp(name, type)
202 char *name;
203 int type;
204{
205 int retry = MAX_TFTP_RETRIES;
206 static unsigned short isocket = 2000;
207 unsigned short osocket = TFTP;
208 unsigned short len, block=1;
209 struct tftp_t tp;
210 unsigned long time;
211 int code;
212 char *p = tp.u.rrq;
213 isocket++;
214 tp.opcode = htons(TFTP_RRQ);
215 while (*name) *(p++) = *(name++);
216 *(p++) = 0;
217 *(p++) = 'o';
218 *(p++) = 'c';
219 *(p++) = 't';
220 *(p++) = 'e';
221 *(p++) = 't';
222 *(p++) = 0;
223 len = p - (char *)&tp;
224 while(retry--) {
225 if (!udp_transmit(arptable[ARP_SERVER].ipaddr, isocket, osocket,
226 len, &tp)) return(0);
227next: time = currticks() + TIMEOUT;
228 while(time > currticks()) {
229 pollkbd();
230 if (eth_poll()) {
231 code = tftp_data(&tp, &block, isocket, &osocket,
232 type);
233 if (!code) continue;
234 if (code == TFTP_CODE_EOF) return(1);
235 if (code == TFTP_CODE_ERROR) return(0);
236 len = TFTP_MIN_PACKET_SIZE;
237 retry = MAX_TFTP_RETRIES;
238 goto next;
239 }
240 }
241 }
242 return(0);
243}
244
245/**************************************************************************
246TFTP_DATA - Check and handle incoming TFTP packets
247**************************************************************************/
248tftp_data(req, block, isocket, osocket, type)
249 struct tftp_t *req;
250 unsigned short *block, isocket, *osocket;
251 int type;
252{
253 struct tftp_t *tp;
254 char *p;
255 int len;
256 if (!chkpacket(TFTP_MIN_PACKET_SIZE, isocket)) return(0);
257 tp = (struct tftp_t *)&packet[ETHER_HDR_SIZE];
258 if (tp->opcode == ntohs(TFTP_ERROR)) {
259 printf("TFTP error %d (%s)\r\n", ntohs(tp->u.err.errcode),
260 tp->u.err.errmsg);
261 longjmp(jmp_bootmenu, 1);
262 }
263 if (tp->opcode != htons(TFTP_DATA)) return(0);
264 len = ntohs(tp->udp.len) - sizeof(struct udphdr) -
265 (2*sizeof(unsigned short));
266 req->opcode = htons(TFTP_ACK); /* Send ack */
267 req->u.ack.block = tp->u.data.block;
268 udp_transmit(arptable[ARP_SERVER].ipaddr, isocket, *osocket,
269 TFTP_MIN_PACKET_SIZE, req);
270 if (*block != ntohs(tp->u.data.block)) return(TFTP_CODE_MORE);
271 if (*block == 1) {
272 *osocket = htons(tp->udp.src);
273 if ((type == TFTP_CODE_CFG) &&
274 (len == sizeof(struct nfs_diskless))) {
275 bcopy(tp->u.data.download, &nfsdiskless, sizeof(struct nfs_diskless));
276 return(TFTP_CODE_EOF);
277 }
278 bcopy(tp->u.data.download, &head, sizeof(struct exec));
279 if ((type == TFTP_CODE_BOOT) &&
280 ((len < sizeof(struct exec)) || (N_BADMAG(head)))) {
281 printf("Not an executable.\r\n");
282 return(TFTP_CODE_ERROR);
283 } else {
284 if (((head.a_entry & 0x00FFFFFF) == 0) &&
285 (head.a_text + head.a_data >= RELOC)) {
286 printf("Executable too large.\r\n");
287 return(TFTP_CODE_ERROR);
288 }
289 /* We load above 1 mb so we don't clobber DOS */
290 loadpoint = (char *)0x100000;
291 printf("text=0x%X", head.a_text);
292 }
293 txtoff = N_TXTOFF(head);
294 }
295 p = tp->u.data.download;
296 *block +=1;
297 while (len--) {
298 if (txtoff) {
299 txtoff--;
300 p++;
301 continue;
302 }
303 if (head.a_text) {
304 *(loadpoint++) = *(p++);
305 head.a_text--;
306 if (!head.a_text) {
307 printf(", data=0x%X",head.a_data);
308 while (((int)loadpoint) & CLOFSET)
309 *(loadpoint++) = 0;
310 }
311 continue;
312 }
313 if (head.a_data) {
314 *(loadpoint++) = *(p++);
315 head.a_data--;
316 if (!head.a_data) {
317 printf(", bss=0x%X\r\n",head.a_bss);
318 return(TFTP_CODE_EOF);
319 }
320
321 }
322 }
323 return((head.a_text || head.a_data) ? TFTP_CODE_MORE : TFTP_CODE_EOF);
324}
325
326/**************************************************************************
327BOOTP - Get my IP address and load information
328**************************************************************************/
329bootp()
330{
331 int retry = MAX_BOOTP_RETRIES;
332 struct bootp_t bp;
333 struct bootp_t *reply;
334 unsigned long time, starttime;
335 bzero(&bp, sizeof(struct bootp_t));
336 bp.bp_op = BOOTP_REQUEST;
337 bp.bp_htype = 1;
338 bp.bp_hlen = ETHER_ADDR_SIZE;
339 bp.bp_xid = starttime = currticks();
340 bcopy(arptable[ARP_CLIENT].node, bp.bp_hwaddr, ETHER_ADDR_SIZE);
341 while(retry--) {
342 udp_transmit(IP_BROADCAST, 0, BOOTP_SERVER,
343 sizeof(struct bootp_t), &bp);
344 time = currticks() + TIMEOUT;
345 while(time > currticks()) {
346 pollkbd();
347 if (eth_poll()) { /* We have something! */
348 reply = (struct bootp_t *)&packet[ETHER_HDR_SIZE];
349 if (((!chkpacket(sizeof(struct bootp_t),
350 BOOTP_CLIENT))) || (reply->bp_op != BOOTP_REPLY))
351 continue;
352 convert_ipaddr(&arptable[ARP_CLIENT].ipaddr,
353 reply->bp_yiaddr);
354 convert_ipaddr(&arptable[ARP_SERVER].ipaddr,
355 reply->bp_siaddr);
356 bzero(arptable[ARP_SERVER].node, ETHER_ADDR_SIZE); /* Kill arp */
9363f593 357 if (reply->bp_file[0]) {
db4d0741 358 bcopy(reply->bp_file, bootname, 128);
9363f593
MR
359 bootfile = bootname;
360 }
db4d0741
MR
361 return(1);
362 }
363 }
364 bp.bp_secs = htons((currticks()-starttime)/20);
365 }
366 return(0);
367}
368
369/**************************************************************************
370IPCHKSUM - Checksum IP Header
371**************************************************************************/
372ipchksum(ip, len)
373 unsigned short *ip;
374 int len;
375{
376 unsigned long sum = 0;
377 len >>= 1;
378 while (len--) {
379 sum += *(ip++);
380 if (sum > 0xFFFF)
381 sum -= 0xFFFF;
382 }
383 return((~sum) & 0x0000FFFF);
384}
385
386/**************************************************************************
387CHKPACKET - Quick check to see if incoming packet is good
388**************************************************************************/
389chkpacket(size, type)
390 int size, type;
391{
392 struct iphdr *ip;
393 struct udphdr *udp;
394 if (packetlen < (ETHER_HDR_SIZE + size)) return(0);
395 if (((packet[12] << 8) | packet[13]) != IP) return(0);
396 ip = (struct iphdr *)&packet[ETHER_HDR_SIZE];
397 if (ip->verhdrlen != 0x45) return(0);
398 if (ipchksum(ip, sizeof(struct iphdr))) return(0);
399 if (ip->protocol != IP_UDP) return(0);
400 udp = (struct udphdr *)&packet[ETHER_HDR_SIZE + sizeof(struct iphdr)];
401 if (ntohs(udp->dest) != type) return(0);
402 return(1);
403}
404
405/**************************************************************************
406CONVERT_IPADDR - Convert IP address from net to machine order
407**************************************************************************/
408convert_ipaddr(d, s)
409 char *d,*s;
410{
411 *(d+3) = *s;
412 *(d+2) = *(s+1);
413 *(d+1) = *(s+2);
414 *d = *(s+3);
415}