1 /* ----------------------------------------------------------------------- *
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]
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.
13 * ----------------------------------------------------------------------- */
23 #include "../version.h"
25 const char memdisk_version[] = "MEMDISK " VERSION_STR " " DATE;
26 const char copyright[] =
27 "Copyright " FIRSTYEAR "-" YEAR_STR " H. Peter Anvin et al";
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[];
42 struct memdisk_header {
50 /* The Disk Parameter Table may be required */
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 */
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 */
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 */
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 */
75 uint8_t rate; /* Data transfer rate */
76 uint8_t cmos; /* CMOS type */
79 uint32_t old_fd_dpt; /* Extension: pointer to old INT 1Eh */
83 /* EDD disk parameter table */
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));
108 uint16_t cmdline_off, cmdline_seg;
114 uint8_t bootloaderid;
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 */
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
147 struct edd_dpt edd_dpt;
148 struct edd4_cd_pkt cd_pkt; /* Only really in a memdisk_iso_* hook */
149 } __attribute__((packed));
151 /* An EDD disk packet */
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));
162 * Routine to seek for a command-line item and return a pointer
163 * to the data portion, if present
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)
171 static const char *getcmditem(const char *what)
174 const char *wp = what;
177 for (p = shdr->cmdline; *p; p++) {
179 case 0: /* Ground state */
187 case 1: /* Matching */
202 case 2: /* Mismatch, skip rest of option */
204 match = 0; /* Next option */
209 /* Check for matching string at end of line */
210 if (match == 1 && *wp == '\0')
217 * Check to see if this is a gzip image
219 #define UNZIP_ALIGN 512
221 extern void _end; /* Symbol signalling end of data */
223 void unzip_if_needed(uint32_t * where_p, uint32_t * size_p)
225 uint32_t where = *where_p;
226 uint32_t size = *size_p;
228 uint32_t startrange, endrange;
229 uint32_t gzdatasize, gzwhere;
230 uint32_t orig_crc, offset;
234 /* Is it a gzip image? */
235 if (check_zip((void *)where, size, &zbytes, &gzdatasize,
236 &orig_crc, &offset) == 0) {
238 if (offset + zbytes > size) {
240 * Assertion failure; check_zip is supposed to guarantee this
243 die("internal error: check_zip returned nonsense\n");
247 * Find a good place to put it: search memory ranges in descending
248 * order until we find one that is legal and fits
251 for (i = nranges - 1; i >= 0; i--) {
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.
258 if (ranges[i].type != 1)
262 if (ranges[i].start >= 0xFFFFFFFF)
265 startrange = (uint32_t) ranges[i].start;
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);
272 /* Make sure we don't overwrite ourselves */
273 if (startrange < (uint32_t) & _end)
274 startrange = (uint32_t) & _end;
276 /* Allow for alignment */
278 (ranges[i].start + (UNZIP_ALIGN - 1)) & ~(UNZIP_ALIGN - 1);
280 /* In case we just killed the whole range... */
281 if (startrange >= endrange)
285 * Must be large enough... don't rely on gzwhere for this
288 if (endrange - startrange < gzdatasize)
292 * This is where the gz image would be put if we put it in this
295 gzwhere = (endrange - gzdatasize) & ~(UNZIP_ALIGN - 1);
297 /* Cast to uint64_t just in case we're flush with the top byte */
298 if ((uint64_t) where + size >= gzwhere && where < endrange) {
300 * Need to move source data to avoid compressed/uncompressed
305 if (gzwhere - startrange < size)
306 continue; /* Can't fit both old and new */
308 newwhere = (gzwhere - size) & ~(UNZIP_ALIGN - 1);
309 printf("Moving compressed data from 0x%08x to 0x%08x\n",
312 memmove((void *)newwhere, (void *)where, size);
322 die("Not enough memory to decompress image (need 0x%08x bytes)\n",
325 printf("gzip image: decompressed addr 0x%08x, len 0x%08x: ",
328 *size_p = gzdatasize;
329 *where_p = (uint32_t) unzip((void *)(where + offset), zbytes,
330 gzdatasize, orig_crc, (void *)target);
335 * Figure out the "geometry" of the disk in question
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 */
347 /* Format of a DOS partition table entry */
350 uint8_t start_h, start_s, start_c;
352 uint8_t end_h, end_s, end_c;
355 } __attribute__ ((packed));
357 /* Format of a FAT filesystem superblock */
364 char bs_filsystype[8];
365 } __attribute__ ((packed));
367 uint8_t bs_jmpboot[3];
369 uint16_t bpb_bytspersec;
370 uint8_t bpb_secperclus;
371 uint16_t bpb_rsvdseccnt;
373 uint16_t bpb_rootentcnt;
374 uint16_t bpb_totsec16;
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;
383 struct fat_extra extra;
386 uint32_t bpb_fatsz32;
387 uint16_t bpb_extflags;
389 uint32_t bpb_rootclus;
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));
397 } __attribute__ ((packed));
399 /* Format of a DOSEMU header */
400 struct dosemu_header {
401 uint8_t magic[7]; /* DOSEMU\0 */
407 } __attribute__ ((packed));
409 #define FOUR(a,b,c,d) (((a) << 24)|((b) << 16)|((c) << 8)|(d))
411 static const struct geometry *get_disk_image_geometry(uint32_t where,
414 static struct geometry hd_geometry;
415 struct dosemu_header dosemu;
416 unsigned int sectors, xsectors, v;
421 printf("command line: %s\n", shdr->cmdline);
423 hd_geometry.sector_size = 512; /* Assume floppy/HDD at first */
426 if (CMD_HASDATA(p = getcmditem("offset")) && (v = atou(p)))
429 sectors = xsectors = (size - offset) >> 9;
431 hd_geometry.hsrc = "guess";
432 hd_geometry.ssrc = "guess";
433 hd_geometry.sectors = sectors;
434 hd_geometry.offset = offset;
436 if ((p = getcmditem("iso")) != CMD_NOTFOUND) {
438 eltorito_dump(where);
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
458 hd_geometry.driveno = 0x00;
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;
469 /* 2048-byte sectors, so adjust the size and count */
470 hd_geometry.sector_size = 2048;
471 sectors = (size - hd_geometry.offset) >> 11;
473 case 1: /* 1.2 MB floppy */
475 hd_geometry.type = 2;
478 case 2: /* 1.44 MB floppy */
480 hd_geometry.type = 4;
483 case 3: /* 2.88 MB floppy */
485 hd_geometry.type = 6;
489 hd_geometry.driveno = 0x80;
490 hd_geometry.type = 0;
491 sectors = (size - hd_geometry.offset) >> 9;
494 /* For HDD emulation, we figure out the geometry later. Otherwise: */
496 hd_geometry.hsrc = hd_geometry.ssrc = "El Torito";
498 hd_geometry.sectors = sectors;
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;
513 hd_geometry.hsrc = hd_geometry.ssrc = "DOSEMU";
516 if (CMD_HASDATA(p = getcmditem("c")) && (v = atou(p)))
518 if (CMD_HASDATA(p = getcmditem("h")) && (v = atou(p))) {
520 hd_geometry.hsrc = "cmd";
522 if (CMD_HASDATA(p = getcmditem("s")) && (v = atou(p))) {
524 hd_geometry.ssrc = "cmd";
527 if (!hd_geometry.h || !hd_geometry.s) {
528 int h, s, max_h, max_s;
530 max_h = hd_geometry.h;
531 max_s = hd_geometry.s;
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);
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) {
547 fs->bpb_fatsz16 ? &fs->x.fat16.extra : &fs->x.fat32.extra;
549 (extra->bs_bootsig == 0x29 && extra->bs_filsystype[0] == 'F'
550 && extra->bs_filsystype[1] == 'A'
551 && extra->bs_filsystype[2] == 'T'))
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";
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)) {
566 unsigned int xsectors = sectors;
568 hd_geometry.driveno = 0; /* Assume floppy */
571 /* Assume it's a floppy drive, guess a geometry */
572 unsigned int type, track;
575 if (xsectors < 320 * 2) {
579 } else if (xsectors < 640 * 2) {
583 } else if (xsectors < 1200 * 2) {
587 } else if (xsectors < 1440 * 2) {
591 } else if (xsectors < 2880 * 2) {
602 s = xsectors / track;
603 if (s < 63 && (xsectors % track) == 0) {
613 hd_geometry.hsrc = hd_geometry.ssrc = "fd";
615 /* No valid floppy geometry, fake it by simulating broken
616 sectors at the end of the image... */
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));
625 /* Assume hard disk */
626 if (!hd_geometry.driveno)
627 hd_geometry.driveno = 0x80;
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;
640 s = (ptab[i].end_s & 0x3f);
641 h = ptab[i].end_h + 1;
645 hd_geometry.hsrc = "MBR";
649 hd_geometry.ssrc = "MBR";
658 max_h = xsectors > 2097152 ? 255 : 64;
660 max_s = xsectors > 2097152 ? 63 : 32;
662 hd_geometry.h = max_h;
663 hd_geometry.s = max_s;
667 hd_geometry.c = xsectors / (hd_geometry.h * hd_geometry.s);
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;
675 if (hd_geometry.driveno & 0x80) {
676 hd_geometry.type = 0; /* Type = hard disk */
678 if (hd_geometry.type == 0)
679 hd_geometry.type = 0x10; /* ATAPI floppy, e.g. LS-120 */
682 if ((size - hd_geometry.offset) & 0x1ff) {
683 puts("MEMDISK: Image has fractional end sector\n");
685 if (sectors % (hd_geometry.h * hd_geometry.s)) {
686 puts("MEMDISK: Image seems to have fractional end cylinder\n");
688 if ((hd_geometry.c * hd_geometry.h * hd_geometry.s) > sectors) {
689 puts("MEMDISK: Image appears to be truncated\n");
696 * Find a $PnP installation check structure; return (ES << 16) + DI value
698 static uint32_t pnp_install_check(void)
701 unsigned char *p, csum;
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;
711 for (i = len; i; i--)
716 return (0xf000 << 16) + (uint16_t) (unsigned long)seg;
724 * Relocate the real-mode code to a new segment
729 } __attribute__ ((packed));
731 static void set_seg_base(uint32_t gdt_base, int seg, uint32_t v)
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;
738 static void relocate_rm_code(uint32_t newbase)
741 uint32_t oldbase = rm_args.rm_base;
742 uint32_t delta = newbase - oldbase;
745 memmove((void *)newbase, (void *)oldbase, rm_args.rm_size);
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;
755 gdt_base = rm_args.rm_gdt;
757 *(uint32_t *) (gdt_base + 2) = gdt_base; /* GDT self-pointer */
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);
763 asm volatile ("lgdtl %0"::"m" (*(char *)gdt_base));
765 *(uint32_t *) rm_args.rm_pmjmp += delta;
766 *(uint16_t *) rm_args.rm_rmjmp += delta >> 4;
768 rm_args.rm_handle_interrupt += delta;
773 static uint8_t checksum_buf(const void *buf, int count)
775 const uint8_t *p = buf;
784 #define STACK_NEEDED 512 /* Number of bytes of stack */
786 struct real_mode_args rm_args;
789 * Actual setup routine
790 * Returns the drive number (which is then passed in %dl to the
793 void setup(const struct real_mode_args *rm_args_ptr)
795 unsigned int bin_size;
797 struct memdisk_header *hptr;
798 struct patch_area *pptr;
800 uint32_t driverptr, driveraddr;
803 const struct geometry *geometry;
804 const struct edd4_bvd *bvd;
805 const struct edd4_bootcat *boot_cat = 0;
806 int total_size, cmdlinelen;
808 uint32_t ramdisk_image, ramdisk_size;
809 uint32_t boot_base, rm_base;
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 */
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 */
822 /* Show signs of life */
823 printf("%s %s\n", memdisk_version, copyright);
825 if (!shdr->ramdisk_image || !shdr->ramdisk_size)
826 die("MEMDISK: No ramdisk image specified!\n");
828 ramdisk_image = shdr->ramdisk_image;
829 ramdisk_size = shdr->ramdisk_size;
831 e820map_init(); /* Initialize memory data structure */
832 get_mem(); /* Query BIOS for memory map */
833 parse_mem(); /* Parse memory map */
835 printf("Ramdisk at 0x%08x, length 0x%08x\n", ramdisk_image, ramdisk_size);
837 unzip_if_needed(&ramdisk_image, &ramdisk_size);
839 geometry = get_disk_image_geometry(ramdisk_image, ramdisk_size);
841 if (getcmditem("edd") != CMD_NOTFOUND ||
842 getcmditem("ebios") != CMD_NOTFOUND)
844 else if (getcmditem("noedd") != CMD_NOTFOUND ||
845 getcmditem("noebios") != CMD_NOTFOUND ||
846 getcmditem("cbios") != CMD_NOTFOUND)
849 do_edd = (geometry->driveno & 0x80) ? 1 : 0;
851 if (getcmditem("iso") != CMD_NOTFOUND) {
853 do_edd = 1; /* Mandatory */
856 /* Choose the appropriate installable memdisk hook */
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;
862 bin_size = (int)&_binary_memdisk_iso_512_bin_size;
863 memdisk_hook = (char *)&_binary_memdisk_iso_512_bin_start;
867 bin_size = (int)&_binary_memdisk_edd_512_bin_size;
868 memdisk_hook = (char *)&_binary_memdisk_edd_512_bin_start;
870 bin_size = (int)&_binary_memdisk_chs_512_bin_size;
871 memdisk_hook = (char *)&_binary_memdisk_chs_512_bin_start;
875 /* Reserve the ramdisk memory */
876 insertrange(ramdisk_image, ramdisk_size, 2);
877 parse_mem(); /* Recompute variables */
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);
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)
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;
899 pptr->bootloaderid = shdr->type_of_loader;
901 pptr->configflags = CONFIG_SAFEINT; /* Default */
902 /* Set config flags */
903 if (getcmditem("ro") != CMD_NOTFOUND) {
904 pptr->configflags |= CONFIG_READONLY;
906 if (getcmditem("raw") != CMD_NOTFOUND) {
907 pptr->configflags &= ~CONFIG_MODEMASK;
908 pptr->configflags |= CONFIG_RAW;
910 if (getcmditem("bigraw") != CMD_NOTFOUND) {
911 pptr->configflags &= ~CONFIG_MODEMASK;
912 pptr->configflags |= CONFIG_BIGRAW | CONFIG_RAW;
914 if (getcmditem("int") != CMD_NOTFOUND) {
915 pptr->configflags &= ~CONFIG_MODEMASK;
916 /* pptr->configflags |= 0; */
918 if (getcmditem("safeint") != CMD_NOTFOUND) {
919 pptr->configflags &= ~CONFIG_MODEMASK;
920 pptr->configflags |= CONFIG_SAFEINT;
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");
934 switch (pptr->configflags & CONFIG_MODEMASK) {
936 puts("standard INT 15h");
939 puts("safe INT 15h");
944 case CONFIG_RAW | CONFIG_BIGRAW:
945 puts("big real mode raw");
948 printf("unknown %#x", pptr->configflags & CONFIG_MODEMASK);
951 puts(" access to high memory\n");
953 /* Set up a drive parameter table */
954 if (geometry->driveno & 0x80) {
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;
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;
976 pptr->dpt.fd.old_fd_dpt = rdz_32(BIOS_INT1E);
979 /* Set up an EDD drive parameter table */
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
992 if (geometry->sector_size != 2048)
993 pptr->edd_dpt.flags |= 0x0002; /* Geometry valid */
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;
1001 pptr->edd_dpt.devpath[0] = pptr->diskbuf;
1002 pptr->edd_dpt.chksum = -checksum_buf(&pptr->edd_dpt.dpikey, 73 - 30);
1006 bvd = (struct edd4_bvd *)(ramdisk_image + 17 * 2048);
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);
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);
1032 if (total_size > dos_mem)
1033 die("MEMDISK: Insufficient low memory\n");
1035 driveraddr = stddosmem - total_size;
1036 driveraddr &= ~0x3FF;
1038 printf("Old dos memory at 0x%05x (map says 0x%05x), loading at 0x%05x\n",
1039 stddosmem, dos_mem, driveraddr);
1041 /* Reserve this range of memory */
1042 wrz_16(BIOS_BASEMEM, driveraddr >> 10);
1043 insertrange(driveraddr, dos_mem - driveraddr, 2);
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;
1053 pptr->memint1588 = low_mem >> 10;
1056 printf("1588: 0x%04x 15E801: 0x%04x 0x%04x\n",
1057 pptr->memint1588, pptr->mem1mb, pptr->mem16mb);
1059 driverseg = driveraddr >> 4;
1060 driverptr = driverseg << 16;
1062 /* Anything beyond the end is for the stack */
1063 pptr->mystack = (uint16_t) (stddosmem - driveraddr);
1065 pptr->oldint13 = rdz_32(BIOS_INT13);
1066 pptr->oldint15 = rdz_32(BIOS_INT15);
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;
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");
1081 pptr->oldint13 = driverptr + hptr->iret_offs;
1084 /* Query drive parameters of this type */
1085 memset(®s, 0, sizeof regs);
1087 regs.eax.b[1] = 0x08;
1088 regs.edx.b[0] = geometry->driveno & 0x80;
1089 intcall(0x13, ®s, ®s);
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");
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]);
1104 /* Compare what INT 13h returned with the appropriate equipment byte */
1105 if (geometry->driveno & 0x80) {
1106 bios_drives = rdz_8(BIOS_HD_COUNT);
1108 uint8_t equip = rdz_8(BIOS_EQUIP);
1111 bios_drives = (equip >> 6) + 1;
1116 if (pptr->drivecnt > bios_drives) {
1117 printf("BIOS equipment byte says count = %d, go with that\n",
1119 pptr->drivecnt = bios_drives;
1123 /* Add ourselves to the drive count */
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;
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);
1137 /* Pointer to the command line */
1138 pptr->cmdline_off = bin_size + (nranges + 1) * sizeof(ranges[0]);
1139 pptr->cmdline_seg = driverseg;
1141 /* Copy driver followed by E820 table followed by command line */
1143 unsigned char *dpp = (unsigned char *)(driverseg << 4);
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;
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);
1156 /* Update various BIOS magic data areas (gotta love this shit) */
1158 if (geometry->driveno & 0x80) {
1159 /* Update BIOS hard disk count */
1160 uint8_t nhd = pptr->drivecnt;
1165 if (!do_eltorito) wrz_8(BIOS_HD_COUNT, nhd);
1167 /* Update BIOS floppy disk count */
1168 uint8_t equip = rdz_8(BIOS_EQUIP);
1169 uint8_t nflop = pptr->drivecnt;
1171 if (nflop > 4) /* Limit of equipment byte */
1176 equip |= ((nflop - 1) << 6) | 0x01;
1178 wrz_8(BIOS_EQUIP, equip);
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);
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));
1192 wrz_32(BIOS_INT13, driverptr + hptr->int13_offs);
1193 wrz_32(BIOS_INT15, driverptr + hptr->int15_offs);
1195 wrz_32(BIOS_INT1E, driverptr + pptr->dpt_ptr);
1197 printf("new: int13 = %08x int15 = %08x int1e = %08x\n",
1198 rdz_32(BIOS_INT13), rdz_32(BIOS_INT15), rdz_32(BIOS_INT1E));
1200 /* Figure out entry point */
1203 shdr->sssp = 0x7c00;
1204 shdr->csip = 0x7c00;
1206 boot_base = boot_seg << 4;
1207 shdr->sssp = boot_seg << 16;
1208 shdr->csip = boot_seg << 16;
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");
1216 relocate_rm_code(rm_base);
1218 /* Reboot into the new "disk" */
1219 puts("Loading boot sector... ");
1222 /* 4 times as many 512-byte sectors in a 2048-byte sector */
1223 boot_lba = pptr->cd_pkt.start * 4;
1225 memcpy((void *)boot_base, (char *)pptr->diskbuf + boot_lba * 512, boot_len);
1227 if (getcmditem("pause") != CMD_NOTFOUND) {
1228 puts("press any key to boot... ");
1230 intcall(0x16, ®s, NULL);
1233 puts("booting...\n");
1235 /* On return the assembly code will jump to the boot vector */
1236 shdr->esdi = pnp_install_check();
1237 shdr->edx = geometry->driveno;