[memdisk] Add El Torito emulation for .ISO images
[profile/ivi/syslinux.git] / memdisk / setup.c
1 /* ----------------------------------------------------------------------- *
2  *
3  *   Copyright 2001-2009 H. Peter Anvin - All Rights Reserved
4  *   Copyright 2009 Intel Corporation; author: H. Peter Anvin
5  *   Portions copyright 2009 Shao Miller [El Torito code]
6  *
7  *   This program is free software; you can redistribute it and/or modify
8  *   it under the terms of the GNU General Public License as published by
9  *   the Free Software Foundation, Inc., 53 Temple Place Ste 330,
10  *   Boston MA 02111-1307, USA; either version 2 of the License, or
11  *   (at your option) any later version; incorporated herein by reference.
12  *
13  * ----------------------------------------------------------------------- */
14
15 #include <stdint.h>
16 #include "bda.h"
17 #include "dskprobe.h"
18 #include "e820.h"
19 #include "eltorito.h"
20 #include "conio.h"
21 #include "version.h"
22 #include "memdisk.h"
23 #include "../version.h"
24
25 const char memdisk_version[] = "MEMDISK " VERSION_STR " " DATE;
26 const char copyright[] =
27     "Copyright " FIRSTYEAR "-" YEAR_STR " H. Peter Anvin et al";
28
29 extern const char _binary_memdisk_chs_512_bin_start[];
30 extern const char _binary_memdisk_chs_512_bin_end[];
31 extern const char _binary_memdisk_chs_512_bin_size[];
32 extern const char _binary_memdisk_edd_512_bin_start[];
33 extern const char _binary_memdisk_edd_512_bin_end[];
34 extern const char _binary_memdisk_edd_512_bin_size[];
35 extern const char _binary_memdisk_iso_512_bin_start[];
36 extern const char _binary_memdisk_iso_512_bin_end[];
37 extern const char _binary_memdisk_iso_512_bin_size[];
38 extern const char _binary_memdisk_iso_2048_bin_start[];
39 extern const char _binary_memdisk_iso_2048_bin_end[];
40 extern const char _binary_memdisk_iso_2048_bin_size[];
41
42 struct memdisk_header {
43     uint16_t int13_offs;
44     uint16_t int15_offs;
45     uint16_t patch_offs;
46     uint16_t total_size;
47     uint16_t iret_offs;
48 };
49
50 /* The Disk Parameter Table may be required */
51 typedef union {
52     struct hd_dpt {
53         uint16_t max_cyl;       /* Max cylinder */
54         uint8_t max_head;       /* Max head */
55         uint8_t junk1[5];       /* Obsolete junk, leave at zero */
56         uint8_t ctrl;           /* Control byte */
57         uint8_t junk2[7];       /* More obsolete junk */
58     } hd;
59     struct fd_dpt {
60         uint8_t specify1;       /* "First specify byte" */
61         uint8_t specify2;       /* "Second specify byte" */
62         uint8_t delay;          /* Delay until motor turn off */
63         uint8_t sectors;        /* Sectors/track */
64
65         uint8_t bps;            /* Bytes/sector (02h = 512) */
66         uint8_t isgap;          /* Length of intersector gap */
67         uint8_t dlen;           /* Data length (0FFh) */
68         uint8_t fgap;           /* Formatting gap */
69
70         uint8_t ffill;          /* Format fill byte */
71         uint8_t settle;         /* Head settle time (ms) */
72         uint8_t mstart;         /* Motor start time */
73         uint8_t maxtrack;       /* Maximum track number */
74
75         uint8_t rate;           /* Data transfer rate */
76         uint8_t cmos;           /* CMOS type */
77         uint8_t pad[2];
78
79         uint32_t old_fd_dpt;    /* Extension: pointer to old INT 1Eh */
80     } fd;
81 } dpt_t;
82
83 /* EDD disk parameter table */
84 struct edd_dpt {
85     uint16_t len;               /* Length of table */
86     uint16_t flags;             /* Information flags */
87     uint32_t c;                 /* Physical cylinders (count!) */
88     uint32_t h;                 /* Physical heads (count!) */
89     uint32_t s;                 /* Physical sectors/track (count!) */
90     uint64_t sectors;           /* Total sectors */
91     uint16_t bytespersec;       /* Bytes/sector */
92     uint16_t dpte_off, dpte_seg;        /* DPTE pointer */
93     uint16_t dpikey;            /* Device Path Info magic */
94     uint8_t  dpilen;            /* Device Path Info length */
95     uint8_t  res1;              /* Reserved */
96     uint16_t res2;              /* Reserved */
97     uint8_t  bustype[4];        /* Host bus type */
98     uint8_t  inttype[8];        /* Interface type */
99     uint64_t intpath;           /* Interface path */
100     uint64_t devpath[2];        /* Device path (double QuadWord!) */
101     uint8_t  res3;              /* Reserved */
102     uint8_t  chksum;            /* DPI checksum */
103 } __attribute__((packed));
104
105 struct patch_area {
106     uint32_t diskbuf;
107     uint32_t disksize;
108     uint16_t cmdline_off, cmdline_seg;
109
110     uint32_t oldint13;
111     uint32_t oldint15;
112
113     uint16_t olddosmem;
114     uint8_t bootloaderid;
115     uint8_t _pad1;
116
117     uint16_t dpt_ptr;
118     /* End of the official MemDisk_Info */
119     uint8_t driveshiftlimit;    /* Do not shift drives above this region */
120     uint8_t _pad2;              /* Pad to DWORD */
121     uint16_t _pad3;             /* Pad to QWORD */
122
123     uint16_t memint1588;
124
125     uint16_t cylinders;
126     uint16_t heads;
127     uint32_t sectors;
128
129     uint32_t mem1mb;
130     uint32_t mem16mb;
131
132     uint8_t driveno;
133     uint8_t drivetype;
134     uint8_t drivecnt;
135     uint8_t configflags;
136
137 #define CONFIG_READONLY 0x01
138 #define CONFIG_RAW      0x02
139 #define CONFIG_SAFEINT  0x04
140 #define CONFIG_BIGRAW   0x08    /* MUST be 8! */
141 #define CONFIG_MODEMASK 0x0e
142
143     uint16_t mystack;
144     uint16_t statusptr;
145
146     dpt_t dpt;
147     struct edd_dpt edd_dpt;
148     struct edd4_cd_pkt cd_pkt; /* Only really in a memdisk_iso_* hook */
149 } __attribute__((packed));
150
151 /* An EDD disk packet */
152 struct edd_dsk_pkt {
153     uint8_t size;               /* Packet size        */
154     uint8_t res1;               /* Reserved           */
155     uint16_t count;             /* Count to transfer  */
156     uint32_t buf;               /* Buffer pointer     */
157     uint64_t start;             /* LBA to start from  */
158     uint64_t buf64;             /* 64-bit buf pointer */
159 } __attribute__ ((packed));
160
161 /*
162  * Routine to seek for a command-line item and return a pointer
163  * to the data portion, if present
164  */
165
166 /* Magic return values */
167 #define CMD_NOTFOUND   ((char *)-1)     /* Not found */
168 #define CMD_BOOL       ((char *)-2)     /* Found boolean option */
169 #define CMD_HASDATA(X) ((int)(X) >= 0)
170
171 static const char *getcmditem(const char *what)
172 {
173     const char *p;
174     const char *wp = what;
175     int match = 0;
176
177     for (p = shdr->cmdline; *p; p++) {
178         switch (match) {
179         case 0:         /* Ground state */
180             if (*p == ' ')
181                 break;
182
183             wp = what;
184             match = 1;
185             /* Fall through */
186
187         case 1:         /* Matching */
188             if (*wp == '\0') {
189                 if (*p == '=')
190                     return p + 1;
191                 else if (*p == ' ')
192                     return CMD_BOOL;
193                 else {
194                     match = 2;
195                     break;
196                 }
197             }
198             if (*p != *wp++)
199                 match = 2;
200             break;
201
202         case 2:         /* Mismatch, skip rest of option */
203             if (*p == ' ')
204                 match = 0;      /* Next option */
205             break;
206         }
207     }
208
209     /* Check for matching string at end of line */
210     if (match == 1 && *wp == '\0')
211         return CMD_BOOL;
212
213     return CMD_NOTFOUND;
214 }
215
216 /*
217  * Check to see if this is a gzip image
218  */
219 #define UNZIP_ALIGN 512
220
221 extern void _end;               /* Symbol signalling end of data */
222
223 void unzip_if_needed(uint32_t * where_p, uint32_t * size_p)
224 {
225     uint32_t where = *where_p;
226     uint32_t size = *size_p;
227     uint32_t zbytes;
228     uint32_t startrange, endrange;
229     uint32_t gzdatasize, gzwhere;
230     uint32_t orig_crc, offset;
231     uint32_t target = 0;
232     int i, okmem;
233
234     /* Is it a gzip image? */
235     if (check_zip((void *)where, size, &zbytes, &gzdatasize,
236                   &orig_crc, &offset) == 0) {
237
238         if (offset + zbytes > size) {
239             /*
240              * Assertion failure; check_zip is supposed to guarantee this
241              * never happens.
242              */
243             die("internal error: check_zip returned nonsense\n");
244         }
245
246         /*
247          * Find a good place to put it: search memory ranges in descending
248          * order until we find one that is legal and fits
249          */
250         okmem = 0;
251         for (i = nranges - 1; i >= 0; i--) {
252             /*
253              * We can't use > 4G memory (32 bits only.)  Truncate to 2^32-1
254              * so we don't have to deal with funny wraparound issues.
255              */
256
257             /* Must be memory */
258             if (ranges[i].type != 1)
259                 continue;
260
261             /* Range start */
262             if (ranges[i].start >= 0xFFFFFFFF)
263                 continue;
264
265             startrange = (uint32_t) ranges[i].start;
266
267             /* Range end (0 for end means 2^64) */
268             endrange = ((ranges[i + 1].start >= 0xFFFFFFFF ||
269                          ranges[i + 1].start == 0)
270                         ? 0xFFFFFFFF : (uint32_t) ranges[i + 1].start);
271
272             /* Make sure we don't overwrite ourselves */
273             if (startrange < (uint32_t) & _end)
274                 startrange = (uint32_t) & _end;
275
276             /* Allow for alignment */
277             startrange =
278                 (ranges[i].start + (UNZIP_ALIGN - 1)) & ~(UNZIP_ALIGN - 1);
279
280             /* In case we just killed the whole range... */
281             if (startrange >= endrange)
282                 continue;
283
284             /*
285              * Must be large enough... don't rely on gzwhere for this
286              * (wraparound)
287              */
288             if (endrange - startrange < gzdatasize)
289                 continue;
290
291             /*
292              * This is where the gz image would be put if we put it in this
293              * range...
294              */
295             gzwhere = (endrange - gzdatasize) & ~(UNZIP_ALIGN - 1);
296
297             /* Cast to uint64_t just in case we're flush with the top byte */
298             if ((uint64_t) where + size >= gzwhere && where < endrange) {
299                 /*
300                  * Need to move source data to avoid compressed/uncompressed
301                  * overlap
302                  */
303                 uint32_t newwhere;
304
305                 if (gzwhere - startrange < size)
306                     continue;   /* Can't fit both old and new */
307
308                 newwhere = (gzwhere - size) & ~(UNZIP_ALIGN - 1);
309                 printf("Moving compressed data from 0x%08x to 0x%08x\n",
310                        where, newwhere);
311
312                 memmove((void *)newwhere, (void *)where, size);
313                 where = newwhere;
314             }
315
316             target = gzwhere;
317             okmem = 1;
318             break;
319         }
320
321         if (!okmem)
322             die("Not enough memory to decompress image (need 0x%08x bytes)\n",
323                 gzdatasize);
324
325         printf("gzip image: decompressed addr 0x%08x, len 0x%08x: ",
326                target, gzdatasize);
327
328         *size_p = gzdatasize;
329         *where_p = (uint32_t) unzip((void *)(where + offset), zbytes,
330                                     gzdatasize, orig_crc, (void *)target);
331     }
332 }
333
334 /*
335  * Figure out the "geometry" of the disk in question
336  */
337 struct geometry {
338     uint32_t sectors;           /* Sector count */
339     uint32_t c, h, s;           /* C/H/S geometry */
340     uint32_t offset;            /* Byte offset for disk */
341     uint8_t type;               /* Type byte for INT 13h AH=08h */
342     uint8_t driveno;            /* Drive no */
343     uint16_t sector_size;       /* Sector size in bytes (512 vs. 2048) */
344     const char *hsrc, *ssrc;    /* Origins of H and S geometries */
345 };
346
347 /* Format of a DOS partition table entry */
348 struct ptab_entry {
349     uint8_t active;
350     uint8_t start_h, start_s, start_c;
351     uint8_t type;
352     uint8_t end_h, end_s, end_c;
353     uint32_t start;
354     uint32_t size;
355 } __attribute__ ((packed));
356
357 /* Format of a FAT filesystem superblock */
358 struct fat_extra {
359     uint8_t bs_drvnum;
360     uint8_t bs_resv1;
361     uint8_t bs_bootsig;
362     uint32_t bs_volid;
363     char bs_vollab[11];
364     char bs_filsystype[8];
365 } __attribute__ ((packed));
366 struct fat_super {
367     uint8_t bs_jmpboot[3];
368     char bs_oemname[8];
369     uint16_t bpb_bytspersec;
370     uint8_t bpb_secperclus;
371     uint16_t bpb_rsvdseccnt;
372     uint8_t bpb_numfats;
373     uint16_t bpb_rootentcnt;
374     uint16_t bpb_totsec16;
375     uint8_t bpb_media;
376     uint16_t bpb_fatsz16;
377     uint16_t bpb_secpertrk;
378     uint16_t bpb_numheads;
379     uint32_t bpb_hiddsec;
380     uint32_t bpb_totsec32;
381     union {
382         struct {
383             struct fat_extra extra;
384         } fat16;
385         struct {
386             uint32_t bpb_fatsz32;
387             uint16_t bpb_extflags;
388             uint16_t bpb_fsver;
389             uint32_t bpb_rootclus;
390             uint16_t bpb_fsinfo;
391             uint16_t bpb_bkbootsec;
392             char bpb_reserved[12];
393             /* Clever, eh?  Same fields, different offset... */
394             struct fat_extra extra;
395         } fat32 __attribute__ ((packed));
396     } x;
397 } __attribute__ ((packed));
398
399 /* Format of a DOSEMU header */
400 struct dosemu_header {
401     uint8_t magic[7];           /* DOSEMU\0 */
402     uint32_t h;
403     uint32_t s;
404     uint32_t c;
405     uint32_t offset;
406     uint8_t pad[105];
407 } __attribute__ ((packed));
408
409 #define FOUR(a,b,c,d) (((a) << 24)|((b) << 16)|((c) << 8)|(d))
410
411 static const struct geometry *get_disk_image_geometry(uint32_t where,
412                                                       uint32_t size)
413 {
414     static struct geometry hd_geometry;
415     struct dosemu_header dosemu;
416     unsigned int sectors, xsectors, v;
417     unsigned int offset;
418     int i;
419     const char *p;
420
421     printf("command line: %s\n", shdr->cmdline);
422
423     hd_geometry.sector_size = 512;      /* Assume floppy/HDD at first */
424
425     offset = 0;
426     if (CMD_HASDATA(p = getcmditem("offset")) && (v = atou(p)))
427         offset = v;
428
429     sectors = xsectors = (size - offset) >> 9;
430
431     hd_geometry.hsrc = "guess";
432     hd_geometry.ssrc = "guess";
433     hd_geometry.sectors = sectors;
434     hd_geometry.offset = offset;
435
436     if ((p = getcmditem("iso")) != CMD_NOTFOUND) {
437 #ifdef DBG_ELTORITO
438         eltorito_dump(where);
439 #endif
440         struct edd4_bvd *bvd = (struct edd4_bvd *)(where + 17 * 2048);
441         /* Tiny sanity check */
442         if ((bvd->boot_rec_ind != 0) || (bvd->ver != 1))
443             printf("El Torito BVD sanity check failed.\n");
444         struct edd4_bootcat *boot_cat =
445             (struct edd4_bootcat *)(where + bvd->boot_cat * 2048);
446         /* Another tiny sanity check */
447         if ((boot_cat->validation_entry.platform_id != 0) ||
448             (boot_cat->validation_entry.key55 != 0x55) ||
449             (boot_cat->validation_entry.keyAA != 0xAA))
450             printf("El Torito boot catalog sanity check failed.\n");
451         /* If we have an emulation mode, set the offset to the image */
452         if (boot_cat->initial_entry.media_type)
453             hd_geometry.offset += boot_cat->initial_entry.load_block * 2048;
454         if (boot_cat->initial_entry.media_type < 4) {
455             /* We're a floppy emulation mode or our params will be
456              * overwritten by the no emulation mode case
457              */
458             hd_geometry.driveno = 0x00;
459             hd_geometry.c = 80;
460             hd_geometry.h = 2;
461         }
462         switch (boot_cat->initial_entry.media_type) {
463         case 0:         /* No emulation   */
464             hd_geometry.driveno = 0xE0;
465             hd_geometry.type = 10;      /* ATAPI removable media device */
466             hd_geometry.c = 65535;
467             hd_geometry.h = 255;
468             hd_geometry.s = 15;
469             /* 2048-byte sectors, so adjust the size and count */
470             hd_geometry.sector_size = 2048;
471             sectors = (size - hd_geometry.offset) >> 11;
472             break;
473         case 1:         /* 1.2 MB floppy  */
474             hd_geometry.s = 15;
475             hd_geometry.type = 2;
476             sectors = 2400;
477             break;
478         case 2:         /* 1.44 MB floppy */
479             hd_geometry.s = 18;
480             hd_geometry.type = 4;
481             sectors = 2880;
482             break;
483         case 3:         /* 2.88 MB floppy */
484             hd_geometry.s = 36;
485             hd_geometry.type = 6;
486             sectors = 5760;
487             break;
488         case 4:
489             hd_geometry.driveno = 0x80;
490             hd_geometry.type = 0;
491             sectors = (size - hd_geometry.offset) >> 9;
492             break;
493         }
494         /* For HDD emulation, we figure out the geometry later. Otherwise: */
495         if (hd_geometry.s) {
496             hd_geometry.hsrc = hd_geometry.ssrc = "El Torito";
497         }
498         hd_geometry.sectors = sectors;
499     }
500
501     /* Do we have a DOSEMU header? */
502     memcpy(&dosemu, (char *)where + hd_geometry.offset, sizeof dosemu);
503     if (!memcmp("DOSEMU", dosemu.magic, 7)) {
504         /* Always a hard disk unless overruled by command-line options */
505         hd_geometry.driveno = 0x80;
506         hd_geometry.type = 0;
507         hd_geometry.c = dosemu.c;
508         hd_geometry.h = dosemu.h;
509         hd_geometry.s = dosemu.s;
510         hd_geometry.offset += dosemu.offset;
511         sectors = (size - hd_geometry.offset) >> 9;
512
513         hd_geometry.hsrc = hd_geometry.ssrc = "DOSEMU";
514     }
515
516     if (CMD_HASDATA(p = getcmditem("c")) && (v = atou(p)))
517         hd_geometry.c = v;
518     if (CMD_HASDATA(p = getcmditem("h")) && (v = atou(p))) {
519         hd_geometry.h = v;
520         hd_geometry.hsrc = "cmd";
521     }
522     if (CMD_HASDATA(p = getcmditem("s")) && (v = atou(p))) {
523         hd_geometry.s = v;
524         hd_geometry.ssrc = "cmd";
525     }
526
527     if (!hd_geometry.h || !hd_geometry.s) {
528         int h, s, max_h, max_s;
529
530         max_h = hd_geometry.h;
531         max_s = hd_geometry.s;
532
533         if (!(max_h | max_s)) {
534             /* Look for a FAT superblock and if we find something that looks
535                enough like one, use geometry from that.  This takes care of
536                megafloppy images and unpartitioned hard disks. */
537             const struct fat_extra *extra = NULL;
538             const struct fat_super *fs = (const struct fat_super *)
539                 ((char *)where + hd_geometry.offset);
540
541             if ((fs->bpb_media == 0xf0 || fs->bpb_media >= 0xf8) &&
542                 (fs->bs_jmpboot[0] == 0xe9 || fs->bs_jmpboot[0] == 0xeb) &&
543                 fs->bpb_bytspersec == 512 &&
544                 fs->bpb_numheads >= 1 && fs->bpb_numheads <= 256 &&
545                 fs->bpb_secpertrk >= 1 && fs->bpb_secpertrk <= 63) {
546                 extra =
547                     fs->bpb_fatsz16 ? &fs->x.fat16.extra : &fs->x.fat32.extra;
548                 if (!
549                     (extra->bs_bootsig == 0x29 && extra->bs_filsystype[0] == 'F'
550                      && extra->bs_filsystype[1] == 'A'
551                      && extra->bs_filsystype[2] == 'T'))
552                     extra = NULL;
553             }
554             if (extra) {
555                 hd_geometry.driveno = extra->bs_drvnum & 0x80;
556                 max_h = fs->bpb_numheads;
557                 max_s = fs->bpb_secpertrk;
558                 hd_geometry.hsrc = hd_geometry.ssrc = "FAT";
559             }
560         }
561
562         if (!(max_h | max_s)) {
563             /* No FAT filesystem found to steal geometry from... */
564             if ((sectors < 4096 * 2) && (hd_geometry.sector_size == 512)) {
565                 int ok = 0;
566                 unsigned int xsectors = sectors;
567
568                 hd_geometry.driveno = 0;        /* Assume floppy */
569
570                 while (!ok) {
571                     /* Assume it's a floppy drive, guess a geometry */
572                     unsigned int type, track;
573                     int c, h, s;
574
575                     if (xsectors < 320 * 2) {
576                         c = 40;
577                         h = 1;
578                         type = 1;
579                     } else if (xsectors < 640 * 2) {
580                         c = 40;
581                         h = 2;
582                         type = 1;
583                     } else if (xsectors < 1200 * 2) {
584                         c = 80;
585                         h = 2;
586                         type = 3;
587                     } else if (xsectors < 1440 * 2) {
588                         c = 80;
589                         h = 2;
590                         type = 2;
591                     } else if (xsectors < 2880 * 2) {
592                         c = 80;
593                         h = 2;
594                         type = 4;
595                     } else {
596                         c = 80;
597                         h = 2;
598                         type = 6;
599                     }
600                     track = c * h;
601                     while (c < 256) {
602                         s = xsectors / track;
603                         if (s < 63 && (xsectors % track) == 0) {
604                             ok = 1;
605                             break;
606                         }
607                         c++;
608                         track += h;
609                     }
610                     if (ok) {
611                         max_h = h;
612                         max_s = s;
613                         hd_geometry.hsrc = hd_geometry.ssrc = "fd";
614                     } else {
615                         /* No valid floppy geometry, fake it by simulating broken
616                            sectors at the end of the image... */
617                         xsectors++;
618                     }
619                 }
620             } else {
621                 /* Assume it is a hard disk image and scan for a partition table */
622                 const struct ptab_entry *ptab = (const struct ptab_entry *)
623                     ((char *)where + hd_geometry.offset + (512 - 2 - 4 * 16));
624
625                 /* Assume hard disk */
626                 if (!hd_geometry.driveno)
627                     hd_geometry.driveno = 0x80;
628
629                 if (*(uint16_t *) ((char *)where + 512 - 2) == 0xaa55) {
630                     for (i = 0; i < 4; i++) {
631                         if (ptab[i].type && !(ptab[i].active & 0x7f)) {
632                             s = (ptab[i].start_s & 0x3f);
633                             h = ptab[i].start_h + 1;
634
635                             if (max_h < h)
636                                 max_h = h;
637                             if (max_s < s)
638                                 max_s = s;
639
640                             s = (ptab[i].end_s & 0x3f);
641                             h = ptab[i].end_h + 1;
642
643                             if (max_h < h) {
644                                 max_h = h;
645                                 hd_geometry.hsrc = "MBR";
646                             }
647                             if (max_s < s) {
648                                 max_s = s;
649                                 hd_geometry.ssrc = "MBR";
650                             }
651                         }
652                     }
653                 }
654             }
655         }
656
657         if (!max_h)
658             max_h = xsectors > 2097152 ? 255 : 64;
659         if (!max_s)
660             max_s = xsectors > 2097152 ? 63 : 32;
661
662         hd_geometry.h = max_h;
663         hd_geometry.s = max_s;
664     }
665
666     if (!hd_geometry.c)
667         hd_geometry.c = xsectors / (hd_geometry.h * hd_geometry.s);
668
669     if ((p = getcmditem("floppy")) != CMD_NOTFOUND) {
670         hd_geometry.driveno = CMD_HASDATA(p) ? atou(p) & 0x7f : 0;
671     } else if ((p = getcmditem("harddisk")) != CMD_NOTFOUND) {
672         hd_geometry.driveno = CMD_HASDATA(p) ? atou(p) | 0x80 : 0x80;
673     }
674
675     if (hd_geometry.driveno & 0x80) {
676         hd_geometry.type = 0;   /* Type = hard disk */
677     } else {
678         if (hd_geometry.type == 0)
679             hd_geometry.type = 0x10;    /* ATAPI floppy, e.g. LS-120 */
680     }
681
682     if ((size - hd_geometry.offset) & 0x1ff) {
683         puts("MEMDISK: Image has fractional end sector\n");
684     }
685     if (sectors % (hd_geometry.h * hd_geometry.s)) {
686         puts("MEMDISK: Image seems to have fractional end cylinder\n");
687     }
688     if ((hd_geometry.c * hd_geometry.h * hd_geometry.s) > sectors) {
689         puts("MEMDISK: Image appears to be truncated\n");
690     }
691
692     return &hd_geometry;
693 }
694
695 /*
696  * Find a $PnP installation check structure; return (ES << 16) + DI value
697  */
698 static uint32_t pnp_install_check(void)
699 {
700     uint32_t *seg;
701     unsigned char *p, csum;
702     int i, len;
703
704     for (seg = (uint32_t *) 0xf0000; seg < (uint32_t *) 0x100000; seg += 4) {
705         if (*seg == ('$' + ('P' << 8) + ('n' << 16) + ('P' << 24))) {
706             p = (unsigned char *)seg;
707             len = p[5];
708             if (len < 0x21)
709                 continue;
710             csum = 0;
711             for (i = len; i; i--)
712                 csum += *p++;
713             if (csum != 0)
714                 continue;
715
716             return (0xf000 << 16) + (uint16_t) (unsigned long)seg;
717         }
718     }
719
720     return 0;
721 }
722
723 /*
724  * Relocate the real-mode code to a new segment
725  */
726 struct gdt_ptr {
727     uint16_t limit;
728     uint32_t base;
729 } __attribute__ ((packed));
730
731 static void set_seg_base(uint32_t gdt_base, int seg, uint32_t v)
732 {
733     *(uint16_t *) (gdt_base + seg + 2) = v;
734     *(uint8_t *) (gdt_base + seg + 4) = v >> 16;
735     *(uint8_t *) (gdt_base + seg + 7) = v >> 24;
736 }
737
738 static void relocate_rm_code(uint32_t newbase)
739 {
740     uint32_t gdt_base;
741     uint32_t oldbase = rm_args.rm_base;
742     uint32_t delta = newbase - oldbase;
743
744     cli();
745     memmove((void *)newbase, (void *)oldbase, rm_args.rm_size);
746
747     rm_args.rm_return += delta;
748     rm_args.rm_intcall += delta;
749     rm_args.rm_bounce += delta;
750     rm_args.rm_base += delta;
751     rm_args.rm_gdt += delta;
752     rm_args.rm_pmjmp += delta;
753     rm_args.rm_rmjmp += delta;
754
755     gdt_base = rm_args.rm_gdt;
756
757     *(uint32_t *) (gdt_base + 2) = gdt_base;    /* GDT self-pointer */
758
759     /* Segments 0x10 and 0x18 are real-mode-based */
760     set_seg_base(gdt_base, 0x10, rm_args.rm_base);
761     set_seg_base(gdt_base, 0x18, rm_args.rm_base);
762
763     asm volatile ("lgdtl %0"::"m" (*(char *)gdt_base));
764
765     *(uint32_t *) rm_args.rm_pmjmp += delta;
766     *(uint16_t *) rm_args.rm_rmjmp += delta >> 4;
767
768     rm_args.rm_handle_interrupt += delta;
769
770     sti();
771 }
772
773 static uint8_t checksum_buf(const void *buf, int count)
774 {
775     const uint8_t *p = buf;
776     uint8_t c;
777
778     while (count--)
779         c += *p++;
780
781     return c;
782 }
783
784 #define STACK_NEEDED    512     /* Number of bytes of stack */
785
786 struct real_mode_args rm_args;
787
788 /*
789  * Actual setup routine
790  * Returns the drive number (which is then passed in %dl to the
791  * called routine.)
792  */
793 void setup(const struct real_mode_args *rm_args_ptr)
794 {
795     unsigned int bin_size;
796     char *memdisk_hook;
797     struct memdisk_header *hptr;
798     struct patch_area *pptr;
799     uint16_t driverseg;
800     uint32_t driverptr, driveraddr;
801     uint16_t dosmem_k;
802     uint32_t stddosmem;
803     const struct geometry *geometry;
804     const struct edd4_bvd *bvd;
805     const struct edd4_bootcat *boot_cat = 0;
806     int total_size, cmdlinelen;
807     com32sys_t regs;
808     uint32_t ramdisk_image, ramdisk_size;
809     uint32_t boot_base, rm_base;
810     int bios_drives;
811     int do_edd = 1;             /* 0 = no, 1 = yes, default is yes */
812     int do_eltorito = 0;        /* default is no */
813     int no_bpt;                 /* No valid BPT presented */
814     uint32_t boot_seg = 0;      /* Meaning 0000:7C00 */
815     uint32_t boot_len = 512;    /* One sector */
816     uint32_t boot_lba = 0;      /* LBA of bootstrap code */
817
818     /* We need to copy the rm_args into their proper place */
819     memcpy(&rm_args, rm_args_ptr, sizeof rm_args);
820     sti();                      /* ... then interrupts are safe */
821
822     /* Show signs of life */
823     printf("%s  %s\n", memdisk_version, copyright);
824
825     if (!shdr->ramdisk_image || !shdr->ramdisk_size)
826         die("MEMDISK: No ramdisk image specified!\n");
827
828     ramdisk_image = shdr->ramdisk_image;
829     ramdisk_size = shdr->ramdisk_size;
830
831     e820map_init();             /* Initialize memory data structure */
832     get_mem();                  /* Query BIOS for memory map */
833     parse_mem();                /* Parse memory map */
834
835     printf("Ramdisk at 0x%08x, length 0x%08x\n", ramdisk_image, ramdisk_size);
836
837     unzip_if_needed(&ramdisk_image, &ramdisk_size);
838
839     geometry = get_disk_image_geometry(ramdisk_image, ramdisk_size);
840
841     if (getcmditem("edd") != CMD_NOTFOUND ||
842         getcmditem("ebios") != CMD_NOTFOUND)
843         do_edd = 1;
844     else if (getcmditem("noedd") != CMD_NOTFOUND ||
845              getcmditem("noebios") != CMD_NOTFOUND ||
846              getcmditem("cbios") != CMD_NOTFOUND)
847         do_edd = 0;
848     else
849         do_edd = (geometry->driveno & 0x80) ? 1 : 0;
850
851     if (getcmditem("iso") != CMD_NOTFOUND) {
852         do_eltorito = 1;
853         do_edd = 1;             /* Mandatory */
854     }
855
856     /* Choose the appropriate installable memdisk hook */
857     if (do_eltorito) {
858         if (geometry->sector_size == 2048) {
859             bin_size = (int)&_binary_memdisk_iso_2048_bin_size;
860             memdisk_hook = (char *)&_binary_memdisk_iso_2048_bin_start;
861         } else {
862             bin_size = (int)&_binary_memdisk_iso_512_bin_size;
863             memdisk_hook = (char *)&_binary_memdisk_iso_512_bin_start;
864         }
865     } else {
866         if (do_edd) {
867             bin_size = (int)&_binary_memdisk_edd_512_bin_size;
868             memdisk_hook = (char *)&_binary_memdisk_edd_512_bin_start;
869         } else {
870             bin_size = (int)&_binary_memdisk_chs_512_bin_size;
871             memdisk_hook = (char *)&_binary_memdisk_chs_512_bin_start;
872         }
873     }
874
875     /* Reserve the ramdisk memory */
876     insertrange(ramdisk_image, ramdisk_size, 2);
877     parse_mem();                /* Recompute variables */
878
879     /* Figure out where it needs to go */
880     hptr = (struct memdisk_header *)memdisk_hook;
881     pptr = (struct patch_area *)(memdisk_hook + hptr->patch_offs);
882
883     dosmem_k = rdz_16(BIOS_BASEMEM);
884     pptr->olddosmem = dosmem_k;
885     stddosmem = dosmem_k << 10;
886     /* If INT 15 E820 and INT 12 disagree, go with the most conservative */
887     if (stddosmem > dos_mem)
888         stddosmem = dos_mem;
889
890     pptr->driveno = geometry->driveno;
891     pptr->drivetype = geometry->type;
892     pptr->cylinders = geometry->c;      /* Possible precision loss */
893     pptr->heads = geometry->h;
894     pptr->sectors = geometry->s;
895     pptr->disksize = geometry->sectors;
896     pptr->diskbuf = ramdisk_image + geometry->offset;
897     pptr->statusptr = (geometry->driveno & 0x80) ? 0x474 : 0x441;
898
899     pptr->bootloaderid = shdr->type_of_loader;
900
901     pptr->configflags = CONFIG_SAFEINT; /* Default */
902     /* Set config flags */
903     if (getcmditem("ro") != CMD_NOTFOUND) {
904         pptr->configflags |= CONFIG_READONLY;
905     }
906     if (getcmditem("raw") != CMD_NOTFOUND) {
907         pptr->configflags &= ~CONFIG_MODEMASK;
908         pptr->configflags |= CONFIG_RAW;
909     }
910     if (getcmditem("bigraw") != CMD_NOTFOUND) {
911         pptr->configflags &= ~CONFIG_MODEMASK;
912         pptr->configflags |= CONFIG_BIGRAW | CONFIG_RAW;
913     }
914     if (getcmditem("int") != CMD_NOTFOUND) {
915         pptr->configflags &= ~CONFIG_MODEMASK;
916         /* pptr->configflags |= 0; */
917     }
918     if (getcmditem("safeint") != CMD_NOTFOUND) {
919         pptr->configflags &= ~CONFIG_MODEMASK;
920         pptr->configflags |= CONFIG_SAFEINT;
921     }
922
923     printf("Disk is %s%d, %u%s K, C/H/S = %u/%u/%u (%s/%s), EDD %s, %s\n",
924            (geometry->driveno & 0x80) ? "hd" : "fd",
925            geometry->driveno & 0x7f,
926            geometry->sectors >> 1,
927            (geometry->sectors & 1) ? ".5" : "",
928            geometry->c, geometry->h, geometry->s,
929            geometry->hsrc, geometry->ssrc,
930            do_edd ? "on" : "off",
931            pptr->configflags & CONFIG_READONLY ? "ro" : "rw");
932
933     puts("Using ");
934     switch (pptr->configflags & CONFIG_MODEMASK) {
935     case 0:
936         puts("standard INT 15h");
937         break;
938     case CONFIG_SAFEINT:
939         puts("safe INT 15h");
940         break;
941     case CONFIG_RAW:
942         puts("raw");
943         break;
944     case CONFIG_RAW | CONFIG_BIGRAW:
945         puts("big real mode raw");
946         break;
947     default:
948         printf("unknown %#x", pptr->configflags & CONFIG_MODEMASK);
949         break;
950     }
951     puts(" access to high memory\n");
952
953     /* Set up a drive parameter table */
954     if (geometry->driveno & 0x80) {
955         /* Hard disk */
956         pptr->dpt.hd.max_cyl = geometry->c - 1;
957         pptr->dpt.hd.max_head = geometry->h - 1;
958         pptr->dpt.hd.ctrl = (geometry->h > 8) ? 0x08 : 0;
959     } else {
960         /* Floppy - most of these fields are bogus and mimic
961            a 1.44 MB floppy drive */
962         pptr->dpt.fd.specify1 = 0xdf;
963         pptr->dpt.fd.specify2 = 0x02;
964         pptr->dpt.fd.delay = 0x25;
965         pptr->dpt.fd.sectors = geometry->s;
966         pptr->dpt.fd.bps = 0x02;
967         pptr->dpt.fd.isgap = 0x12;
968         pptr->dpt.fd.dlen = 0xff;
969         pptr->dpt.fd.fgap = 0x6c;
970         pptr->dpt.fd.ffill = 0xf6;
971         pptr->dpt.fd.settle = 0x0f;
972         pptr->dpt.fd.mstart = 0x05;
973         pptr->dpt.fd.maxtrack = geometry->c - 1;
974         pptr->dpt.fd.cmos = geometry->type > 5 ? 5 : geometry->type;
975
976         pptr->dpt.fd.old_fd_dpt = rdz_32(BIOS_INT1E);
977     }
978
979     /* Set up an EDD drive parameter table */
980     if (do_edd) {
981         pptr->edd_dpt.sectors = geometry->sectors;
982         /* The EDD spec has this as <= 15482880  sectors (1024x240x63);
983            this seems to make very little sense.  Try for something saner. */
984         if (geometry->c <= 1024 && geometry->h <= 255 && geometry->s <= 63) {
985             pptr->edd_dpt.c = geometry->c;
986             pptr->edd_dpt.h = geometry->h;
987             pptr->edd_dpt.s = geometry->s;
988             /* EDD-4 states that invalid geometry should be returned
989              * for INT 0x13, AH=0x48 "EDD Get Disk Parameters" call on an
990              * El Torito ODD.  Check for 2048-byte sector size
991              */
992             if (geometry->sector_size != 2048)
993                 pptr->edd_dpt.flags |= 0x0002;  /* Geometry valid */
994         }
995         if (!(geometry->driveno & 0x80)) {
996             /* Floppy drive.  Mark it as a removable device with
997                media change notification; media is present. */
998             pptr->edd_dpt.flags |= 0x0014;
999         }
1000
1001         pptr->edd_dpt.devpath[0] = pptr->diskbuf;
1002         pptr->edd_dpt.chksum = -checksum_buf(&pptr->edd_dpt.dpikey, 73 - 30);
1003     }
1004
1005     if (do_eltorito) {
1006         bvd = (struct edd4_bvd *)(ramdisk_image + 17 * 2048);
1007         boot_cat =
1008             (struct edd4_bootcat *)(ramdisk_image + bvd->boot_cat * 2048);
1009         pptr->cd_pkt.type = boot_cat->initial_entry.media_type; /* Cheat */
1010         pptr->cd_pkt.driveno = geometry->driveno;
1011         pptr->cd_pkt.start = boot_cat->initial_entry.load_block;
1012         pptr->cd_pkt.load_seg = boot_cat->initial_entry.load_seg;
1013         pptr->cd_pkt.sect_count = boot_cat->initial_entry.sect_count;
1014         boot_len = pptr->cd_pkt.sect_count * 2048;
1015         pptr->cd_pkt.geom1 = (uint8_t)(pptr->cylinders) & 0xFF;
1016         pptr->cd_pkt.geom2 = (uint8_t)(pptr->sectors) | (uint8_t)((pptr->cylinders >> 2) & 0xC0);
1017         pptr->cd_pkt.geom3 = (uint8_t)(pptr->heads);
1018     }
1019
1020     /* The size is given by hptr->total_size plus the size of the E820
1021        map -- 12 bytes per range; we may need as many as 2 additional
1022        ranges (each insertrange() can worst-case turn 1 area into 3)
1023        plus the terminating range, over what nranges currently show. */
1024     cmdlinelen = strlen(shdr->cmdline) + 1;
1025     total_size = hptr->total_size;      /* Actual memdisk code */
1026     total_size += (nranges + 3) * sizeof(ranges[0]);    /* E820 memory ranges */
1027     total_size += cmdlinelen;   /* Command line */
1028     total_size += STACK_NEEDED; /* Stack */
1029     printf("Total size needed = %u bytes, allocating %uK\n",
1030            total_size, (total_size + 0x3ff) >> 10);
1031
1032     if (total_size > dos_mem)
1033         die("MEMDISK: Insufficient low memory\n");
1034
1035     driveraddr = stddosmem - total_size;
1036     driveraddr &= ~0x3FF;
1037
1038     printf("Old dos memory at 0x%05x (map says 0x%05x), loading at 0x%05x\n",
1039            stddosmem, dos_mem, driveraddr);
1040
1041     /* Reserve this range of memory */
1042     wrz_16(BIOS_BASEMEM, driveraddr >> 10);
1043     insertrange(driveraddr, dos_mem - driveraddr, 2);
1044     parse_mem();
1045
1046     pptr->mem1mb = low_mem >> 10;
1047     pptr->mem16mb = high_mem >> 16;
1048     if (low_mem == (15 << 20)) {
1049         /* lowmem maxed out */
1050         uint32_t int1588mem = (high_mem >> 10) + (low_mem >> 10);
1051         pptr->memint1588 = (int1588mem > 0xffff) ? 0xffff : int1588mem;
1052     } else {
1053         pptr->memint1588 = low_mem >> 10;
1054     }
1055
1056     printf("1588: 0x%04x  15E801: 0x%04x 0x%04x\n",
1057            pptr->memint1588, pptr->mem1mb, pptr->mem16mb);
1058
1059     driverseg = driveraddr >> 4;
1060     driverptr = driverseg << 16;
1061
1062     /* Anything beyond the end is for the stack */
1063     pptr->mystack = (uint16_t) (stddosmem - driveraddr);
1064
1065     pptr->oldint13 = rdz_32(BIOS_INT13);
1066     pptr->oldint15 = rdz_32(BIOS_INT15);
1067
1068     /* Adjust the E820 table: if there are null ranges (type 0)
1069        at the end, change them to type end of list (-1).
1070        This is necessary for the driver to be able to report end
1071        of list correctly. */
1072     while (nranges && ranges[nranges - 1].type == 0) {
1073         ranges[--nranges].type = -1;
1074     }
1075
1076     if (getcmditem("nopass") != CMD_NOTFOUND) {
1077         /* nopass specified - we're the only drive by definition */
1078         printf("nopass specified - we're the only drive\n");
1079         bios_drives = 0;
1080         pptr->drivecnt = 0;
1081         pptr->oldint13 = driverptr + hptr->iret_offs;
1082         no_bpt = 1;
1083     } else {
1084         /* Query drive parameters of this type */
1085         memset(&regs, 0, sizeof regs);
1086         regs.es = 0;
1087         regs.eax.b[1] = 0x08;
1088         regs.edx.b[0] = geometry->driveno & 0x80;
1089         intcall(0x13, &regs, &regs);
1090
1091         /* Note: per suggestion from the Interrupt List, consider
1092            INT 13 08 to have failed if the sector count in CL is zero. */
1093         if ((regs.eflags.l & 1) || !(regs.ecx.b[0] & 0x3f)) {
1094             printf("INT 13 08: Failure, assuming this is the only drive\n");
1095             pptr->drivecnt = 0;
1096             no_bpt = 1;
1097         } else {
1098             printf("INT 13 08: Success, count = %u, BPT = %04x:%04x\n",
1099                    regs.edx.b[0], regs.es, regs.edi.w[0]);
1100             pptr->drivecnt = regs.edx.b[0];
1101             no_bpt = !(regs.es | regs.edi.w[0]);
1102         }
1103
1104         /* Compare what INT 13h returned with the appropriate equipment byte */
1105         if (geometry->driveno & 0x80) {
1106             bios_drives = rdz_8(BIOS_HD_COUNT);
1107         } else {
1108             uint8_t equip = rdz_8(BIOS_EQUIP);
1109
1110             if (equip & 1)
1111                 bios_drives = (equip >> 6) + 1;
1112             else
1113                 bios_drives = 0;
1114         }
1115
1116         if (pptr->drivecnt > bios_drives) {
1117             printf("BIOS equipment byte says count = %d, go with that\n",
1118                    bios_drives);
1119             pptr->drivecnt = bios_drives;
1120         }
1121     }
1122
1123     /* Add ourselves to the drive count */
1124     pptr->drivecnt++;
1125
1126     /* Discontiguous drive space.  There is no really good solution for this. */
1127     if (pptr->drivecnt <= (geometry->driveno & 0x7f))
1128         pptr->drivecnt = (geometry->driveno & 0x7f) + 1;
1129
1130     /* Probe for contiguous range of BIOS drives starting with driveno */
1131     pptr->driveshiftlimit = probe_drive_range(geometry->driveno) + 1;
1132     if ((pptr->driveshiftlimit & 0x80) != (geometry->driveno & 0x80))
1133         printf("We lost the last drive in our class of drives.\n");
1134     printf("Drive probing gives drive shift limit: 0x%02x\n",
1135         pptr->driveshiftlimit);
1136
1137     /* Pointer to the command line */
1138     pptr->cmdline_off = bin_size + (nranges + 1) * sizeof(ranges[0]);
1139     pptr->cmdline_seg = driverseg;
1140
1141     /* Copy driver followed by E820 table followed by command line */
1142     {
1143         unsigned char *dpp = (unsigned char *)(driverseg << 4);
1144
1145         /* Adjust these pointers to point to the installed image */
1146         /* Careful about the order here... the image isn't copied yet! */
1147         pptr = (struct patch_area *)(dpp + hptr->patch_offs);
1148         hptr = (struct memdisk_header *)dpp;
1149
1150         /* Actually copy to low memory */
1151         dpp = mempcpy(dpp, memdisk_hook, bin_size);
1152         dpp = mempcpy(dpp, ranges, (nranges + 1) * sizeof(ranges[0]));
1153         dpp = mempcpy(dpp, shdr->cmdline, cmdlinelen + 1);
1154     }
1155
1156     /* Update various BIOS magic data areas (gotta love this shit) */
1157
1158     if (geometry->driveno & 0x80) {
1159         /* Update BIOS hard disk count */
1160         uint8_t nhd = pptr->drivecnt;
1161
1162         if (nhd > 128)
1163             nhd = 128;
1164
1165         if (!do_eltorito) wrz_8(BIOS_HD_COUNT, nhd);
1166     } else {
1167         /* Update BIOS floppy disk count */
1168         uint8_t equip = rdz_8(BIOS_EQUIP);
1169         uint8_t nflop = pptr->drivecnt;
1170
1171         if (nflop > 4)          /* Limit of equipment byte */
1172             nflop = 4;
1173
1174         equip &= 0x3E;
1175         if (nflop)
1176             equip |= ((nflop - 1) << 6) | 0x01;
1177
1178         wrz_8(BIOS_EQUIP, equip);
1179
1180         /* Install DPT pointer if this was the only floppy */
1181         if (getcmditem("dpt") != CMD_NOTFOUND ||
1182             ((nflop == 1 || no_bpt) && getcmditem("nodpt") == CMD_NOTFOUND)) {
1183             /* Do install a replacement DPT into INT 1Eh */
1184             pptr->dpt_ptr = hptr->patch_offs + offsetof(struct patch_area, dpt);
1185         }
1186     }
1187
1188     /* Install the interrupt handlers */
1189     printf("old: int13 = %08x  int15 = %08x  int1e = %08x\n",
1190            rdz_32(BIOS_INT13), rdz_32(BIOS_INT15), rdz_32(BIOS_INT1E));
1191
1192     wrz_32(BIOS_INT13, driverptr + hptr->int13_offs);
1193     wrz_32(BIOS_INT15, driverptr + hptr->int15_offs);
1194     if (pptr->dpt_ptr)
1195         wrz_32(BIOS_INT1E, driverptr + pptr->dpt_ptr);
1196
1197     printf("new: int13 = %08x  int15 = %08x  int1e = %08x\n",
1198            rdz_32(BIOS_INT13), rdz_32(BIOS_INT15), rdz_32(BIOS_INT1E));
1199
1200     /* Figure out entry point */
1201     if (!boot_seg) {
1202         boot_base = 0x7c00;
1203         shdr->sssp = 0x7c00;
1204         shdr->csip = 0x7c00;
1205     } else {
1206         boot_base = boot_seg << 4;
1207         shdr->sssp = boot_seg << 16;
1208         shdr->csip = boot_seg << 16;
1209     }
1210
1211     /* Relocate the real-mode code to below the stub */
1212     rm_base = (driveraddr - rm_args.rm_size) & ~15;
1213     if (rm_base < boot_base + boot_len)
1214         die("MEMDISK: bootstrap too large to load\n");
1215
1216     relocate_rm_code(rm_base);
1217
1218     /* Reboot into the new "disk" */
1219     puts("Loading boot sector... ");
1220
1221     if (do_eltorito) {
1222         /* 4 times as many 512-byte sectors in a 2048-byte sector */
1223         boot_lba = pptr->cd_pkt.start * 4;
1224     }
1225     memcpy((void *)boot_base, (char *)pptr->diskbuf + boot_lba * 512, boot_len);
1226
1227     if (getcmditem("pause") != CMD_NOTFOUND) {
1228         puts("press any key to boot... ");
1229         regs.eax.w[0] = 0;
1230         intcall(0x16, &regs, NULL);
1231     }
1232
1233     puts("booting...\n");
1234
1235     /* On return the assembly code will jump to the boot vector */
1236     shdr->esdi = pnp_install_check();
1237     shdr->edx = geometry->driveno;
1238 }