]> git.lizzy.rs Git - plan9front.git/blob - sys/src/boot/pc/pxe.c
let the kernel set dma mode for ata by default
[plan9front.git] / sys / src / boot / pc / pxe.c
1 #include <u.h>
2 #include "fns.h"
3
4 enum {
5         Tftp_READ       = 1,
6         Tftp_WRITE      = 2,
7         Tftp_DATA       = 3,
8         Tftp_ACK        = 4,
9         Tftp_ERROR      = 5,
10         Tftp_OACK       = 6,
11
12         TftpPort        = 69,
13
14         Segsize         = 512,
15         Maxpath         = 64,
16 };
17
18 typedef uchar IP4[4];
19
20 typedef struct Tftp Tftp;
21 typedef struct Dhcp Dhcp;
22
23 struct Tftp
24 {
25         IP4 sip;
26         IP4 dip;
27         IP4 gip;
28
29         int sport;
30         int dport;
31
32         char *rp;
33         char *ep;
34
35         int eof;
36         
37         char pkt[2+2+Segsize];
38         char nul;
39 };
40
41 struct Dhcp
42 {
43         uchar opcode;
44         uchar hardware;
45         uchar hardlen;
46         uchar gatehops;
47         uchar ident[4];
48         uchar seconds[2];
49         uchar flags[2];
50         uchar cip[4];
51         uchar yip[4];
52         uchar sip[4];
53         uchar gip[4];
54         uchar mac[16];
55         char sname[64];
56         char bootfile[128];
57 };
58
59 int pxecall(int op, void *buf);
60
61 static void*
62 unfar(ulong seg, ulong off)
63 {
64         return (void*)((off & 0xFFFF) + (seg & 0xFFFF)*16);
65 }
66
67 static void
68 puts(void *x, ushort v)
69 {
70         uchar *p = x;
71
72         p[1] = (v>>8) & 0xFF;
73         p[0] = v & 0xFF;
74 }
75
76 static ushort
77 gets(void *x)
78 {
79         uchar *p = x;
80
81         return p[1]<<8 | p[0];
82 }
83
84 static void
85 hnputs(void *x, ushort v)
86 {
87         uchar *p = x;
88
89         p[0] = (v>>8) & 0xFF;
90         p[1] = v & 0xFF;
91 }
92
93 static ushort
94 nhgets(void *x)
95 {
96         uchar *p = x;
97
98         return p[0]<<8 | p[1];
99 }
100
101 static void
102 moveip(IP4 d, IP4 s)
103 {
104         memmove(d, s, sizeof(d));
105 }
106
107 static int
108 getip(IP4 yip, IP4 sip, IP4 gip, char mac[16])
109 {
110         struct {
111                 uchar status[2];
112                 uchar pkttype[2];
113                 uchar bufsize[2];
114                 uchar off[2];
115                 uchar seg[2];
116                 uchar lim[2];
117         } buf;
118         int i, r;
119         Dhcp *p;
120
121         memset(&buf, 0, sizeof(buf));
122         puts(buf.pkttype, 3);
123
124         if(r = pxecall(0x71, &buf))
125                 return -r;
126         if((p = unfar(gets(buf.seg), gets(buf.off))) == 0)
127                 return -1;
128         moveip(yip, p->yip);
129         moveip(sip, p->sip);
130         moveip(gip, p->gip);
131         mac[12] = 0;
132         for(i=0; i<6; i++){
133                 mac[i*2] = hex[p->mac[i]>>4];
134                 mac[i*2+1] = hex[p->mac[i]&15];
135         }
136         return 0;
137 }
138
139 static int
140 udpopen(IP4 sip)
141 {
142         struct {
143                 uchar status[2];
144                 uchar sip[4];
145         } buf;
146
147         puts(buf.status, 0);
148         moveip(buf.sip, sip);
149         return pxecall(0x30, &buf);
150 }
151
152 static int
153 udpclose(void)
154 {
155         char status[2];
156         puts(status, 0);
157         return pxecall(0x31, status);
158 }
159
160 static int
161 udpread(IP4 sip, IP4 dip, int *sport, int dport, int *len, void *data)
162 {
163         struct {
164                 uchar status[2];
165                 uchar sip[4];
166                 uchar dip[4];
167                 uchar sport[2];
168                 uchar dport[2];
169                 uchar len[2];
170                 uchar off[2];
171                 uchar seg[2];
172         } buf;
173         int r;
174
175         puts(buf.status, 0);
176         moveip(buf.sip, sip);
177         moveip(buf.dip, dip);
178         hnputs(buf.sport, *sport);
179         hnputs(buf.dport, dport);
180         puts(buf.len, *len);
181         puts(buf.off, (long)data);
182         puts(buf.seg, 0);
183         if(r = pxecall(0x32, &buf))
184                 return r;
185         moveip(sip, buf.sip);
186         *sport = nhgets(buf.sport);
187         *len = gets(buf.len);
188         return 0;
189 }
190
191 static int
192 udpwrite(IP4 ip, IP4 gw, int sport, int dport, int len, void *data)
193 {
194         struct {
195                 uchar status[2];
196                 uchar ip[4];
197                 uchar gw[4];
198                 uchar sport[2];
199                 uchar dport[2];
200                 uchar len[2];
201                 uchar off[2];
202                 uchar seg[2];
203         } buf;
204
205         puts(buf.status, 0);
206         moveip(buf.ip, ip);
207         moveip(buf.gw, gw);
208         hnputs(buf.sport, sport);
209         hnputs(buf.dport, dport);
210         puts(buf.len, len);
211         puts(buf.off, (long)data);
212         puts(buf.seg, 0);
213         return pxecall(0x33, &buf);
214 }
215
216 int
217 read(void *f, void *data, int len)
218 {
219         Tftp *t = f;
220         int n;
221
222         if(!t->eof && t->rp >= t->ep){
223                 if(t->rp){
224                         hnputs(t->pkt, Tftp_ACK);
225                         udpwrite(t->dip, t->gip, t->sport, t->dport, 4, t->pkt);
226                         t->rp = t->ep = 0;
227                 }
228                 for(;;){
229                         n = sizeof(t->pkt);
230                         if(udpread(t->dip, t->sip, &t->dport, t->sport, &n, t->pkt))
231                                 continue;
232                         if(n >= 4)
233                                 break;
234                 }
235                 switch(nhgets(t->pkt)){
236                 case Tftp_DATA:
237                         t->rp = t->pkt + 4;
238                         t->ep = t->pkt + n;
239                         t->eof = n < Segsize;
240                         break;
241                 case Tftp_ERROR:
242                         print(t->pkt+4);
243                         print(crnl);
244                 default:
245                         t->eof = 1;
246                         return -1;
247                 }
248         }
249         n = t->ep - t->rp;
250         if(len > n)
251                 len = n;
252         memmove(data, t->rp, len);
253         t->rp += len;
254         return len;
255 }
256
257 void
258 close(void *f)
259 {
260         Tftp *t = f;
261         t->eof = 1;
262         udpclose();
263 }
264
265 static int
266 tftpopen(Tftp *t, char *path, IP4 sip, IP4 dip, IP4 gip)
267 {
268         static ushort xport = 6666;
269         int r, n;
270         char *p;
271
272         moveip(t->sip, sip);
273         moveip(t->gip, gip);
274         memset(t->dip, 0, sizeof(t->dip));
275         t->sport = xport++;
276         t->dport = 0;
277         t->rp = t->ep = 0;
278         t->eof = 0;
279         t->nul = 0;
280         if(r = udpopen(t->sip))
281                 return r;
282         p = t->pkt;
283         hnputs(p, Tftp_READ); p += 2;
284         n = strlen(path)+1;
285         memmove(p, path, n); p += n;
286         memmove(p, "octet", 6); p += 6;
287         n = p - t->pkt;
288         for(;;){
289                 if(r = udpwrite(dip, t->gip, t->sport, TftpPort, n, t->pkt))
290                         break;
291                 if(r = read(t, 0, 0))
292                         break;
293                 return 0;
294         }
295         close(t);
296         return r;
297 }
298
299 void
300 start(void *)
301 {
302         char mac[16], path[Maxpath], *kern;
303         IP4 yip, sip, gip;
304         void *f;
305         Tftp t;
306
307         if(getip(yip, sip, gip, mac)){
308                 print("bad dhcp\r\n");
309                 halt();
310         }
311         memmove(path, "/cfg/pxe/", 9);
312         memmove(path+9, mac, 13);
313         if(tftpopen(f = &t, path, yip, sip, gip)){
314                 print("no config\r\n");
315                 f = 0;
316         }
317         for(;;){
318                 kern = configure(f, path); f = 0;
319                 if(tftpopen(&t, kern, yip, sip, gip)){
320                         print("not found\r\n");
321                         continue;
322                 }
323                 print(bootkern(&t));
324                 print(crnl);
325         }
326 }