Adjust memory layout for 2.6.22+ kernels with 32KB setup code
[mknbi.git] / first32.c
1 #include        "stddef.h"
2 #include        "string.h"
3 #include        "linux-asm-io.h"
4 #include        "etherboot.h"
5 #include        "start32.h"
6 #include        "elf_boot.h"
7
8 #ifndef FIRST32DOS
9 #define FIRST32LINUX    1
10 #endif
11
12 #ifdef  FIRST32LINUX
13 #define SERIAL_CONSOLE 0
14 /*
15  * This program is free software; you can redistribute it and/or
16  * modify it under the terms of the GNU General Public License as
17  * published by the Free Software Foundation; either version 2, or (at
18  * your option) any later version.
19  */
20
21 /*
22
23 Memory layout assumed by mknbi and this program
24
25 0x07C00-0x07FFF   0.5 kB        floppy boot sector if loaded from floppy
26 0x0F???-0x0FFFF     ? kB        large Etherboot data buffers (deprecated)
27 0x10000-0x8FFFF 512.0 kB        kernel (from tagged image)
28 0x90000-0x901FF   0.5 kB        Linux floppy boot sector (from Linux image)
29 0x90200-0x981FF  32.0 kB        kernel setup (from Linux image)
30 0x98200-0x983FF   0.5 kB        tagged image header ("directory")
31 0x98400-0x987FF   1.0 kB        kernel parameters (generated by mknbi)
32 0x98800-0x9CFFF   6.0 kB        this program (generated by mknbi)
33
34 0x94000-0x9FFFF  48.0 kB        Etherboot (top few kB may be used by BIOS)
35                                 Normally Etherboot starts at 0x94000
36 0x100000-                       kernel (if bzImage) (from tagged image)
37 after bzImage kernel            ramdisk (optional) (from tagged image)
38                                 moved to below top of memory by this program
39                                 but not higher than 896kB or what the
40                                 limit in setup.S says
41
42 */
43
44 #define         PARAMSIZE       512
45
46 extern void printf(const char *, ...);
47 extern int sprintf(char *, const char *, ...);
48 extern void xstartlinux(unsigned long);
49 extern void exit(int);
50
51 #ifdef  FIRST32ELF
52 static Elf32_Phdr       *seg[S_END] = { 0 };
53 #else
54 static struct segment   *seg[S_END] = { 0 };
55 #endif
56 static unsigned char    *ip, *op;
57 static short            *vgamode;
58 static struct bootp_t   *bp;
59 static unsigned char    *vendortags;
60 unsigned long           top_of_initrd = 0;
61 static enum { RD_TOP, RD_ASIS, RD_HEXADDR } rdmode = RD_TOP;
62 static unsigned long    rdaddr;
63
64
65 #if SERIAL_CONSOLE
66 /* Base Address */
67 #define TTYS0 0x3f8
68 /* Data */
69 #define TTYS0_RBR (TTYS0+0x00)
70 #define TTYS0_TBR (TTYS0+0x00)
71 /* Control */
72 #define TTYS0_IER (TTYS0+0x01)
73 #define TTYS0_IIR (TTYS0+0x02)
74 #define TTYS0_FCR (TTYS0+0x02)
75 #define TTYS0_LCR (TTYS0+0x03)
76 #define TTYS0_MCR (TTYS0+0x04)
77
78 #define TTYS0_DLL (TTYS0+0x00)
79 #define TTYS0_DLM (TTYS0+0x01)
80 /* Status */
81 #define TTYS0_LSR (TTYS0+0x05)
82 #define TTYS0_MSR (TTYS0+0x06)
83 #define TTYS0_SCR (TTYS0+0x07)
84
85 static void ttys0_tx_byte(unsigned byte)
86 {
87         while((inb(TTYS0_LSR) & 0x20) == 0)
88                 ;
89         outb(byte, TTYS0_TBR);
90 }
91
92 #endif
93 void putchar(int c)
94 {
95         if (c == '\n')
96                 putchar('\r');
97 #if SERIAL_CONSOLE
98         ttys0_tx_byte(c);
99 #endif
100         console_putc(c);
101 }
102
103 static inline void quit(void)
104 {
105         printf("Bad argument\n");
106         exit(0);
107 }
108
109 static void nomem(void)
110 {
111         printf("Out of parameter space\n");
112         exit(0);
113 }
114
115 static inline void checkvendor(void)
116 {
117         union {
118                 unsigned long   l;
119                 unsigned char   c[4];
120         } u;
121
122         memcpy(u.c, vendortags, sizeof(u));
123         if (u.l == RFC_1048 || u.l == VEND_CMU || u.l == VEND_STAN)
124                 vendortags += 4;
125         else
126                 vendortags = 0;
127 }
128
129 #ifdef  FIRST32ELF
130 static inline void locate_segs(union infoblock *header)
131 {
132         int             i;
133         Elf32_Phdr      *s;
134
135         s = (Elf32_Phdr *)((char *)header + header->ehdr.e_phoff);
136         for (i = 0; i < S_END && i < header->ehdr.e_phnum; i++, s++) {
137                 seg[i] = s;
138 #if     DEBUG > 1
139                 printf("%d %#X\n", i, s->p_paddr);
140 #endif
141         }
142 }
143
144 #else
145
146 static inline void locate_segs(union infoblock *header)
147 {
148         int             i;
149         struct segment  *s;
150
151         s = (struct segment *)((char *)header + sizeof(struct imgheader)
152                 + ((header->img.length & 0xF0) >> 2));
153         for (i = 0; i < S_END; i++, s++) {
154                 seg[i] = s;
155 #if     DEBUG > 1
156                 printf("%d %#X\n", i, s->p_paddr);
157 #endif
158                 if (s->flags & F_FINAL)
159                         break;
160                 s = (struct segment *)((char *)s + ((s->lengths & 0xF0) >> 2));
161         }
162 }
163 #endif  /* !FIRST32ELF */
164
165 /*
166  *      Find DHCP vendor tag, return pointer to tag length
167  */
168 static unsigned char *gettag(unsigned int tag)
169 {
170         unsigned char           *p;
171         unsigned char           c;
172         static unsigned char    emptytag[] = { 0, 0 };
173
174         if (vendortags == 0)
175                 return (emptytag);
176         for (p = vendortags; (c = *p) != RFC1533_END; ) {
177                 if (c == RFC1533_PAD)
178                         p++;
179                 else if (c == tag)
180                         return (p + 1);
181                 else
182                         p += p[1] + 2;
183         }
184         return (emptytag);
185 }
186
187 static void outtag(unsigned char *value)
188 {
189         int                     len;
190
191         len = *value++;
192         if (op + len > ip)
193                 nomem();
194         while (len-- > 0)
195                 *op++ = *value++;
196 }
197
198 /* Return 1 if s2 is a prefix of s1 */
199 static int strprefix(const unsigned char *s1, const unsigned char *s2)
200 {
201         while (*s1 != '\0' && *s2 != '\0' && *s1++ == *s2++)
202                 ;
203         /* Have we reached the end of s2? */
204         return (*s2 == '\0');
205 }
206
207 enum keyword { K_VGA, K_NFSROOT, K_IP, K_RDBASE, K_MEM };
208
209 static inline int match_keyword(const unsigned char *start)
210 {
211         if (strprefix(start, "vga"))
212                 return (K_VGA);
213         if (strprefix(start, "nfsroot"))
214                 return (K_NFSROOT);
215         if (strprefix(start, "ip"))
216                 return (K_IP);
217         if (strprefix(start, "rdbase"))
218                 return (K_RDBASE);
219         if (strprefix(start, "mem"))
220                 return (K_MEM);
221         return (-1);
222 }
223
224 #define isws(c) ((c) == ' ' || (c) == '\t')
225
226 static inline int copy_and_match(void)
227 {
228         int                     c;
229         unsigned char           *start;
230
231         start = ip;
232         /* Stop copying at = if it exists */
233         while ((c = *ip) != '\0' && !isws(c) && c != '=') {
234                 *op++ = *ip++;
235         }
236         if (c == '=') {
237                 ip++;
238                 *op++ = '=';
239                 return (match_keyword(start));
240         }
241         return (-1);
242 }
243
244 static unsigned long gethex(const unsigned char *p)
245 {
246         unsigned long           value = 0;
247
248         for (;;) {
249                 int c = *p++;
250                 if (c >= '0' && c <= '9')
251                         c -= '0';
252                 else if (c >= 'a' && c <= 'f')
253                         c -= 'a' - 10;
254                 else if (c >= 'A' && c <= 'F')
255                         c -= 'A' - 10;
256                 else
257                         break;
258                 value <<= 4;
259                 value |= c;
260         }
261         return (value);
262 }
263
264 static int getdec(const unsigned char *p)
265 {
266         int                     value = 0, sign = 0;
267
268         if (*p == '-') {
269                 sign = 1;
270                 p++;
271         }
272         for (;;) {
273                 int c = *p++;
274                 if (c >= '0' && c <= '9')
275                         c -= '0';
276                 else
277                         break;
278                 value *= 10;
279                 value += c;
280         }
281         return (sign ? -value : value);
282 }
283
284 static void copy_nonws(void)
285 {
286         int                     c;
287
288         /* Copy up to next whitespace */
289         while ((c = *ip) != '\0' && !isws(c))
290                 *op++ = *ip++;
291 }
292
293 static void discard_arg(void)
294 {
295         int                     c;
296
297         /* Discard up to next whitespace */
298         while ((c = *ip) != '\0' && !isws(c))
299                 ip++;
300 }
301
302 static int outip(const unsigned char *p)
303 {
304         long            ip;
305
306         if (*p == 0)
307                 return (0);
308         memcpy(&ip, p + 1, sizeof(ip));
309         return sprintf(op, "%@", ip);
310 }
311
312 static inline void subst_value(int kwindex)
313 {
314         int                     c;
315         unsigned char           *p;
316
317         if (kwindex == K_VGA) {
318                 /* backup over "vga=" */
319                 op -= sizeof("vga=") - 1;
320                 if (strprefix(ip, "ask"))
321                         c = -3;
322                 else if (strprefix(ip, "extended"))
323                         c = -2;
324                 else if (strprefix(ip, "normal"))
325                         c = -1;
326                 else if (strprefix(ip, "0x"))
327                         c = gethex(ip+2);
328                 else    /* assume decimal mode number */
329                         c = getdec(ip);
330                 *vgamode = c;
331                 discard_arg();
332         } else if (kwindex == K_NFSROOT && strprefix(ip, "rom") &&
333                 (ip[3] == '\0' || isws(ip[3]))) {
334                 outtag(gettag(RFC1533_ROOTPATH));
335                 discard_arg();
336         } else if (kwindex == K_IP && strprefix(ip, "rom") &&
337                 (ip[3] == '\0' || isws(ip[3]))) {
338                 long            ip;
339                 op += sprintf(op, "%@:%@:", bp->bp_yiaddr, bp->bp_siaddr);
340                 p = gettag(RFC1533_GATEWAY);
341                 op += outip(p);
342                 *op++ = ':';
343                 p = gettag(RFC1533_NETMASK);
344                 op += outip(p);
345                 *op++ = ':';
346                 outtag(gettag(RFC1533_HOSTNAME));
347                 p = gettag(RFC1533_VENDOR_ETHDEV);
348                 if (*p)
349                         *op++ = ':';
350                 outtag(p);
351                 discard_arg();
352         } else if (kwindex == K_RDBASE) {
353                 if (strprefix(ip, "top"))
354                         rdmode = RD_TOP;
355                 else if (strprefix(ip, "asis"))
356                         rdmode = RD_ASIS;
357                 else if (strprefix(ip, "0x")) {
358                         rdmode = RD_HEXADDR;
359                         rdaddr = gethex(ip+2);
360                 }
361                 discard_arg();
362         } else if (kwindex == K_MEM) {
363                 unsigned char   *p;
364                 unsigned long   memsize;
365                 memsize = getdec(p = ip);
366                 while (*p >= '0' && *p <= '9')
367                         ++p;
368                 if (*p == 'G')
369                         memsize <<= 30;
370                 else if (*p == 'M')
371                         memsize <<= 20;
372                 else if (*p == 'K')
373                         memsize <<= 10;
374                 top_of_initrd = memsize;
375                 copy_nonws();
376         } else
377                 copy_nonws();
378 }
379
380 static inline int skipws(void)
381 {
382         int                     c;
383
384         while ((c = *ip) != '\0' && isws(c))
385                 ip++;
386         return (c);
387 }
388
389 /*
390  *      The parameters are copied from the input area to the output
391  *      area, looking out for keyword=value pairs while doing so.
392  *      If a possible keyword is found, indicated by an =,
393  *      it is matched against a small list.
394  *      If it matches none of the keywords on the list,
395  *      the value is copied unchanged.
396  *      If it matches a keyword, then the appropriate substitutions
397  *      are made.
398  *      While doing the substitution, a check is made that the output
399  *      pointer doesn't overrun the input pointer. This is the only
400  *      place it could happen, as the substitution may be longer than
401  *      the original.
402  */
403 static inline void process_params(void)
404 {
405         int                     i;
406
407         while (skipws() != '\0') {
408                 if ((i = copy_and_match()) >= 0)
409                         subst_value(i);
410                 else
411                         copy_nonws();
412                 *op++ = ' ';
413         }
414         /* There may be a space after the last arg, probably does not matter
415            but this is a reminder */
416         *op = '\0';
417 }
418
419 /*
420  * String is not null terminated, count of chars following is in first element
421  * If there are 6 colons, returns char position after 6th colon
422  * Else returns one position after string
423  * which forces the length calculated below to be negative
424  * Length of 7th argument can be calculated by subtracting the
425  * length of the string preceding from the total length.
426  */
427 static inline unsigned char *skip6colons(unsigned char *p)
428 {
429         int     len, coloncount;
430
431         for (len = *p++, coloncount = 6; len > 0 && coloncount > 0; p++, len--)
432                 if (*p == ':')
433                         coloncount--;
434         return (p + (coloncount > 0));
435 }
436
437 static void parse_elf_boot_notes(
438         void *notes, union infoblock **rheader, struct bootp_t **rbootp)
439 {
440         unsigned char *note, *end;
441         Elf_Bhdr *bhdr;
442         Elf_Nhdr *hdr;
443
444         bhdr = notes;
445         if (bhdr->b_signature != ELF_BHDR_MAGIC) {
446                 return;
447         }
448
449         note = ((char *)bhdr) + sizeof(*bhdr);
450         end  = ((char *)bhdr) + bhdr->b_size;
451         while (note < end) {
452                 unsigned char *n_name, *n_desc, *next;
453                 hdr = (Elf_Nhdr *)note;
454                 n_name = note + sizeof(*hdr);
455                 n_desc = n_name + ((hdr->n_namesz + 3) & ~3);
456                 next = n_desc + ((hdr->n_descsz + 3) & ~3);
457                 if (next > end) 
458                         break;
459 #if 0
460                 printf("n_type: %x n_name(%d): n_desc(%d): \n", 
461                         hdr->n_type, hdr->n_namesz, hdr->n_descsz);
462 #endif
463
464                 if ((hdr->n_namesz == 10) &&
465                         (memcmp(n_name, "Etherboot", 10) == 0)) {
466                         switch(hdr->n_type) {
467                         case EB_BOOTP_DATA:
468                                 *rbootp = *((void **)n_desc);
469                                 break;
470                         case EB_HEADER:
471                                 *rheader = *((void **)n_desc);
472                                 break;
473                         default:
474                                 break;
475                         }
476                 }
477                 note = next;
478         }
479 }
480
481 int first(struct ebinfo *eb, union infoblock *header, struct bootp_t *bootp)
482 {
483         int                     i;
484         unsigned char           *p, *q, *params;
485         struct bootblock        *boot;
486         struct setupblock       *setup;
487         union {
488                 unsigned long   l;
489                 unsigned char   c[4];
490         } u;
491
492 #if DEBUG > 1
493         printf("&eb = %#X\n", &eb);
494 #endif
495         printf(MKNBI_VERSION "/" __FILE__
496 #ifdef  FIRST32ELF
497                 " (ELF)"
498 #endif
499                 " (GPL)\n");
500 #if DEBUG > 1
501         printf("eb = %#X, header = %#X, bootp = %#X\n", eb, header, bootp);
502 #endif
503         /* Sanity checks */
504 #ifdef  FIRST32ELF
505         parse_elf_boot_notes(eb, &header, &bootp);
506         if (header->img.magic != ELF_MAGIC
507 #else
508         if (header->img.magic != TAG_MAGIC
509 #endif
510                 || bootp->bp_op != BOOTP_REPLY)
511                 quit();
512         bp = bootp;
513         vendortags = (unsigned char *)bootp->bp_vend;
514         checkvendor();
515         locate_segs(header);
516         /* Locate boot block */
517         boot = (struct bootblock *)seg[S_BOOT]->p_paddr;
518         /* Point to word to alter if vga=... specified */
519         vgamode = &boot->vgamode;
520         /* Locate setup block */
521         setup = (struct setupblock *)seg[S_SETUP]->p_paddr;
522         /* Adjust loader type byte */
523         setup->su_type = SU_MY_LOADER_TYPE;
524         /* If setup version >= 0x202, use new command line protocol.
525            This frees setup.S from being tied to 0x90000 */
526         if (setup->su_version >= 0x202)
527                 setup->su_cmd_line_ptr = params = (unsigned char *)seg[S_PARAMS]->p_paddr;
528         else {  /* Use old protocol */
529                 /* Adjust boot block pointers to point to command line */
530                 boot->cl_magic = CL_MAGIC;
531                 boot->cl_offset = (params = (unsigned char *)seg[S_PARAMS]->p_paddr) - ((unsigned char *)boot);
532         }
533         p = params + (i = strlen(params) + 1);
534         /* Append T129 if present */
535         q = gettag(RFC1533_VENDOR_MAGIC);
536         /* Check T128 present and correct */
537         if (*q >= 6 && (memcpy(u.c, q + 1, sizeof(u)), u.l == VEND_EB) &&
538             q[6] == RFC1533_VENDOR_MAJOR) {
539                 q = gettag(RFC1533_VENDOR_ADDPARM);
540                 i = PARAMSIZE - 1 - i;          /*  +1 for SPACE */
541                 if (i > *q)                     /* enough space? */
542                         i = *q;
543                 q++;
544                 if (i > 0)
545                         p[-1] = ' ';            /* NUL -> space */
546                 while (i-- > 0)
547                         *p++ = *q++;
548                 *p++ = '\0';                    /* position past NUL */
549 #ifdef BROKEN_ADDPARAM_HANDLING
550                 /* This code is disabled, since it makes absolutely no sense with the
551                  * new menu code (via external programs) to unconditionally add the
552                  * parameters specified in the menu entry.  The user might have changed
553                  * the parameters manually.  Parameters MUST be passed through the
554                  * official RFC1533_VENDOR_ADDPARM tag, otherwise BOTH the changed
555                  * parameters and the unchanged parameters are added to the cmdline.
556                  * Finally there is no guarantee that the menu code preserves the menu
557                  * tags, as this is quite tricky and they generally contain nothing of
558                  * interest to a started kernel.  In fact I seriously think that the
559                  * whole idea of a RFC1533_VENDOR_SELECTION tag is wrong - KE.  */
560                 if (*(q = gettag(RFC1533_VENDOR_SELECTION)) == 1
561                   && *(q = gettag(q[1])) > 0) {
562                         unsigned char   *r = skip6colons(q);
563                         /* If we have an argument and enough space, copy it */
564                         if ((i = *q - (r - q) + 1) > 0
565                           && i < PARAMSIZE - 2 - strlen(params)) {
566                         /* +2 for SPACE and final NUL */
567                                 p[-1] = ' ';
568                                 while (i-- > 0) {
569                                         /* escapes: ~b -> \\, ~c -> : */
570                                         if (i > 0 && r[0] == '~' && r[1] == 'b')
571                                                 *p++ = '\\', r += 2, --i;
572                                         else if (i > 0 && r[0] == '~' && r[1] == 'c')
573                                                 *p++ = ':', r += 2, --i;
574                                         else
575                                                 *p++ = *r++;
576                                 }
577                                 *p++ = '\0';
578                         }
579                 }
580 #endif /* BROKEN_ADDPARAM_HANDLING */
581         }
582         /* Move parameters to end of parameter area,
583            tail first to avoid overwriting */
584         q = params + PARAMSIZE;
585         /* At least 1 byte is copied, the NUL */
586         do {
587                 *--q = *--p;
588         } while (p != params);
589         ip = q;
590         op = params;
591 #ifdef  DEBUG
592         printf("Parameters: %s\n", p);
593 #endif
594         /* mem= param affects top_of_initrd */
595         process_params();
596         if (seg[S_RAMDISK] != 0) {
597                 unsigned long           max;
598
599                 get_memsizes();
600                 max = (setup->su_version >= 0x203) ? setup->ramdisk_max : 0x37FFFFFF;
601                 /* compute top of initrd only if user has not overridden it */
602                 if (top_of_initrd == 0) {
603                         struct e820entry        *e;
604                         /* look for highest E820_RAM that is under ramdisk_max
605                            strictly speaking we should also check that
606                            we have room for the ramdisk in the memory segment */
607                         for (i = 0; i < meminfo.map_count; i++) {
608                                 e = &meminfo.map[i];
609                                 if (e->type == E820_RAM
610                                         && e->addr < max
611                                         && (e->addr + e->size) > top_of_initrd)
612                                         top_of_initrd = e->addr + e->size;
613                         }
614                         /*2004/05/08: memdisk needs 64k between initrd and the computed top */
615                         top_of_initrd -= 0x10000;
616                 }
617                 if (top_of_initrd > max)
618                         top_of_initrd = max;
619                 /* Round down to next lower 4k boundary */
620                 top_of_initrd &= ~0xFFF;
621                 printf("Top of ramdisk is %#X\n", top_of_initrd);
622                 if (rdmode == RD_TOP || rdmode == RD_HEXADDR) {
623                         long                    *dp, *sp;
624
625                        /*2004/05/08: now we have a true size rd, hence
626                                need to align tail pointer to 4k boundary up */
627                         sp = (long *)((p = (unsigned char *)seg[S_RAMDISK]->p_paddr) +
628                                 (i = ((seg[S_RAMDISK]->p_filesz + 0xfff) & ~0xfff)));
629                         /*
630                          * If user specified address, align dest tail pointer to 4k boundary below
631                          */
632                         if (rdmode == RD_HEXADDR)
633                                 dp = (long *)((rdaddr & ~0xfff) + i);
634                         else
635                                 dp = (long *)top_of_initrd;
636                         /* Copy to destination by longwords, tail first;
637                                 seg[] might get overwritten, save rd size first */
638                         i = seg[S_RAMDISK]->p_filesz;
639                         while (sp > (long *)p)
640                                 *--dp = *--sp;
641                         printf("Ramdisk at %#X, size %#X\n",
642                                 (setup->su_ramdisk_start = (unsigned long)dp),
643                                 (setup->su_ramdisk_size = i));
644                 } else {        /* leave ramdisk as loaded, just report */
645                         printf("Ramdisk at %#X, size %#X\n",
646                                 (setup->su_ramdisk_start = (unsigned long)seg[S_RAMDISK]->p_paddr),
647                                 (setup->su_ramdisk_size = seg[S_RAMDISK]->p_filesz));
648                 }
649         }
650 #ifdef  DEBUG
651         printf("Ready\n");
652 #endif
653 #if DEBUG > 3
654         /* Delay so we can read display */
655         for (i = 0; i < 0x7ffffff; i++)
656                 ;
657 #endif
658         xstartlinux((unsigned long)setup);
659         return (0);
660 }
661 #endif  /* FIRST32LINUX */
662
663 #ifdef  FIRST32DOS
664 extern void printf(const char *, ...);
665 extern void xstart(unsigned long, union infoblock *, struct bootp_t *);
666 extern void exit(int);
667
668 struct bootp_t  bpcopy;
669
670 void putchar(int c)
671 {
672         if (c == '\n')
673                 putchar('\r');
674         console_putc(c);
675 }
676
677 static inline void quit(void)
678 {
679         printf("Bad argument\n");
680         exit(0);
681 }
682
683 static void parse_elf_boot_notes(
684         void *notes, union infoblock **rheader, struct bootp_t **rbootp)
685 {
686         unsigned char *note, *end;
687         Elf_Bhdr *bhdr;
688         Elf_Nhdr *hdr;
689
690         bhdr = notes;
691         if (bhdr->b_signature != ELF_BHDR_MAGIC) {
692                 return;
693         }
694
695         note = ((char *)bhdr) + sizeof(*bhdr);
696         end  = ((char *)bhdr) + bhdr->b_size;
697         while (note < end) {
698                 unsigned char *n_name, *n_desc, *next;
699                 hdr = (Elf_Nhdr *)note;
700                 n_name = note + sizeof(*hdr);
701                 n_desc = n_name + ((hdr->n_namesz + 3) & ~3);
702                 next = n_desc + ((hdr->n_descsz + 3) & ~3);
703                 if (next > end) 
704                         break;
705 #if 0
706                 printf("n_type: %x n_name(%d): n_desc(%d): \n", 
707                         hdr->n_type, hdr->n_namesz, hdr->n_descsz);
708 #endif
709
710                 if ((hdr->n_namesz == 10) &&
711                         (memcmp(n_name, "Etherboot", 10) == 0)) {
712                         switch(hdr->n_type) {
713                         case EB_BOOTP_DATA:
714                                 *rbootp = *((void **)n_desc);
715                                 break;
716                         case EB_HEADER:
717                                 *rheader = *((void **)n_desc);
718                                 break;
719                         default:
720                                 break;
721                         }
722                 }
723                 note = next;
724         }
725 }
726
727 int first(struct ebinfo *eb, union infoblock *header, struct bootp_t *bootp)
728 {
729 #if DEBUG > 1
730         printf("&eb = %#X\n", &eb);
731 #endif
732         printf(MKNBI_VERSION "/" __FILE__ " (ELF)" " (GPL)\n");
733 #if DEBUG > 1
734         printf("eb = %#X, header = %#X, bootp = %#X\n", eb, header, bootp);
735 #endif
736         /* Sanity checks */
737         parse_elf_boot_notes(eb, &header, &bootp);
738         if (header->img.magic != ELF_MAGIC || bootp->bp_op != BOOTP_REPLY)
739                 quit();
740         memcpy(&bpcopy, bootp, sizeof(bpcopy));
741         xstart(RELOC - 0x1000, header, &bpcopy);
742         return (0);
743 }
744 #endif  /* FIRST32DOS */